Considering the following models:
class ManySide(django.db.models.Model):
one_side = models.ForeignKey(
to=OneSide, on_delete=models.PROTECT, related_name="related_one_side"
)
class OneSide(django.db.models:model):
# not containing any field relevant here
def many_side_elements(self):
pass # ?
What should I include in method many_side_elements so that calling it from a OneSide Model instance would list a queryset of ManySide elements?
Official docs imply that given o is a OneSide isntance, o.many_side_set.all() should work but it returns an error in shell.
My current solution is the following:
from django.apps import apps
[...]
def many_side_elements(self):
ManySideModel = apps.get_model('<app_name_here>', 'ManySide')
val = ManySideModel.objects.filter(one_side=self)
But I'm concerned it's ineffective since it requires importing the other Model. Actually it caused a circular dependency error message in my project, hence the get_model usage.
Is there any better way? Or xy_set should work in the first place? Then what am I doing wrong?
If you create the model field with a related name, the related name overrides the _set queryset.
In your case
o.related_one_side.all() should work without the need for another def.
See: https://docs.djangoproject.com/en/4.0/topics/db/queries/#following-relationships-backward
You can override the FOO_set name by setting the related_name parameter in the ForeignKey definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries'), the above example code would look like this: b.entries.all()
Related
Is it possible without related name (related_name="+") to prefetch objects on the target instance? Sure I know it's not a problem with the related name, but I'm not really sure if it's possible without it.
Here is the example code:
from django.db import models
class Parent(models.Model):
name = models.CharField(max_length=50)
class Child(models.Model):
parent = models.ForeignKey(to=Parent, related_name="+", on_delete=models.CASCADE)
name = models.CharField(max_length=50)
Parent.objects.all().prefetch_related('child_set')
Maybe it's possible using the Prefetch(lookup, queryset=None, to_attr=None) object, because it takes the queryset in the argument list?
Looked through the code a bit and found this line:
rel_obj_descriptor = getattr(instance.__class__, through_attr, None)
Here instance is the model instance, and through_attr is the field name of related instance to be fetched. This line basically tries to get a related descriptor to perform the prefetch query. In your case rel_obj_descriptor would contain None.
To answer your question no it is not possible at least for a Foreign Key, there may be some hack for Many to Many relationships as Django appears to use some internal descriptors for them.
I would advice you to simply not set related_name="+" since you want to use the backwards relation here. You say "It's because of separation of concerns between multiple apps" but that does not make much sense. Don't we set a foreign key to the user model for various other models anyway and still use the related name? Does the point of separation of concerns arise there(the user model is in a separate app)?
try
parent = Parent.objects.get(id=pk)
parent.child_set.all()
I don't know if having related_name = '+' prevents this situation, but if you never define related_name, you can definitely use this method.
I can't figure out the difference between prefetch_related('arg_set') and prefetch_related('arg') .
Sometimes prefetch_related doesn't work when using argument 'arg'even 'arg_set' works.
I've searched through docs.djangoproject.com but, at least, I can't find related document on both pages below.
https://docs.djangoproject.com/en/2.1/ref/models/querysets/ https://docs.djangoproject.com/ja/2.1/ref/contrib/contenttypes/
Could some of you elaborate the difference and when _set is necessary?
And I want to read the official document related to this issue so showing me the reference link is appreciated.
Thank you in advance.
environment:
windows10, python 3.7.2, django 2.1.8, sqlite3, PyCham 2019.1 .
views.py
from django.shortcuts import render
from .models import Article
def index(request):
a = Article.objects.all().select_related('user').prefetch_related('comment_set').order_by('id') # [1]
a = Article.objects.all().select_related('user').prefetch_related('comment').order_by('id') # [2]
return render(request,
'sns/index.html',
{'articles': a})
models.py
from django.db import models
from article_comment_model.settings import AUTH_USER_MODEL
class Article(models.Model):
user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='article_user')
title = models.CharField(max_length=100)
text = models.TextField()
class Comment(models.Model):
user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='comment_user')
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.TextField()
I want to understand the variety of prefetch_related arguments well.
The argument for callig prefetch_related() would be the name of the relation. In your case this would be a reverse ForeignKey relationship. As you can see in the documentation the name of the reverse relationship will be FOO_set where FOO is the model's lowercase name.
Therefore in your example prefetch_related('comment_set') should be correct. If you would specify a related_name like
article = models.ForeignKey(Article, on_delete=models.CASCADE,
related_name='comments')
the related_name will get used instead of FOO_set, therefore prefetch_related('comments') should be valid in this case.
The name of the lookup to use in prefetch_related depends on the answer to a couple of questions:
Is the relation defined on the model you are querying or on the other side of the relationship?
If the relation is defined on the model you are querying (termed "forward relationship" by the Django docs), then the lookup is simply the field name. If the relation is defined at the other end of the relationship ("backward relationship"), then the lookup depends on a second question:
Have you defined a related_name in the other model where the relationship is defined?
If yes, the lookup is the related_name. If there is no related_name, Django uses a default name, which is modelname_set for x-to-many relationships and modelname for x-to-one relationships (both in lower case).
In practical terms, this means the following in your code:
x-to-many relationships:
# no related names defined, using default manager name
Article.objects.prefetch_related('comment_set')
# using related names
User.objects.prefetch_related('article_user', 'comment_user')
x-to-one relationships:
Article.objects.prefetch_related('user')
Comment.objects.prefetch_related('article', 'user')
Using prefetch_related for x-to-one relationships like in the last two examples above is rare. We mostly use select_related as the latter only creates a join in the original query instead of issuing a separate query. However, as you can read towards the end of its documentation, prefetch_related has a few potential advantages. It can:
fetch a filtered queryset
fetch incomplete models (via only and defer)
perform nested prefetching via the Prefetch object
I want to create an object that contains 2 links to Users. For example:
class GameClaim(models.Model):
target = models.ForeignKey(User)
claimer = models.ForeignKey(User)
isAccepted = models.BooleanField()
but I am getting the following errors when running the server:
Accessor for field 'target' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'target'.
Accessor for field 'claimer' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'claimer'.
Can you please explain why I am getting the errors and how to fix them?
You have two foreign keys to User. Django automatically creates a reverse relation from User back to GameClaim, which is usually gameclaim_set. However, because you have two FKs, you would have two gameclaim_set attributes, which is obviously impossible. So you need to tell Django what name to use for the reverse relation.
Use the related_name attribute in the FK definition. e.g.
class GameClaim(models.Model):
target = models.ForeignKey(User, related_name='gameclaim_targets')
claimer = models.ForeignKey(User, related_name='gameclaim_users')
isAccepted = models.BooleanField()
The User model is trying to create two fields with the same name, one for the GameClaims that have that User as the target, and another for the GameClaims that have that User as the claimer. Here's the docs on related_name, which is Django's way of letting you set the names of the attributes so the autogenerated ones don't conflict.
The OP isn't using a abstract base class... but if you are, you will find that hard coding the related_name in the FK (e.g. ..., related_name="myname") will result in a number of these conflict errors - one for each inherited class from the base class. The link provided below contains the workaround, which is simple, but definitely not obvious.
From the django docs...
If you are using the related_name
attribute on a ForeignKey or
ManyToManyField, you must always
specify a unique reverse name for the
field. This would normally cause a
problem in abstract base classes,
since the fields on this class are
included into each of the child
classes, with exactly the same values
for the attributes (including
related_name) each time.
More info here.
Sometimes you have to use extra formatting in related_name
- actually, any time when inheritance is used.
class Value(models.Model):
value = models.DecimalField(decimal_places=2, max_digits=5)
animal = models.ForeignKey(
Animal, related_name="%(app_label)s_%(class)s_related")
class Meta:
abstract = True
class Height(Value):
pass
class Weigth(Value):
pass
class Length(Value):
pass
No clash here, but related_name is defined once and Django will take care for creating unique relation names.
then in children of Value class, you'll have access to:
herdboard_height_related
herdboard_lenght_related
herdboard_weight_related
I seem to come across this occasionally when I add a submodule as an application to a django project, for example given the following structure:
myapp/
myapp/module/
myapp/module/models.py
If I add the following to INSTALLED_APPS:
'myapp',
'myapp.module',
Django seems to process the myapp.mymodule models.py file twice and throws the above error. This can be resolved by not including the main module in the INSTALLED_APPS list:
'myapp.module',
Including the myapp instead of myapp.module causes all the database tables to be created with incorrect names, so this seems to be the correct way to do it.
I came across this post while looking for a solution to this problem so figured I'd put this here :)
Just adding to Jordan's answer (thanks for the tip Jordan) it can also happen if you import the level above the apps and then import the apps e.g.
myproject/
apps/
foo_app/
bar_app/
So if you are importing apps, foo_app and bar_app then you could get this issue. I had apps, foo_app and bar_app all listed in settings.INSTALLED_APPS
And you want to avoid importing apps anyway, because then you have the same app installed in 2 different namespaces
apps.foo_app
and
foo_app
I'm django learner and i have problem with django relationship concept.
I have written two models that have relations with single source model (UserProfile).but one of them does not work properly.The Message class work fine with it's two fields (sender,receiver),but the other class(Class) lead to
programing error:relation "CEA_class" already exists
where CEA is my app name.I really prefer to have two different field for the class and don't join them as single field.What I'm suppose to do with it?
class Message ---->that work fine
class Message(models.Model):
sender = models.ForeignKey(UserProfile,blank=False,related_name="sender")
receiver = models.ForeignKey(UserProfile,blank=False,related_name="receiver")
content = models.CharField(max_length=200)
priority = models.BigIntegerField(choices=PRIORITY_LIST,default=1)
class Class ---->that lead to error
class Class(models.Model):
subject = models.CharField(max_length=20)
time = models.CharField(max_length=20)
day = models.CharField(max_length=20)
location = models.CharField(max_length=20)
students = models.ManyToManyField(UserProfile,blank=True,related_name="students")
master = models.ForeignKey(UserProfile,blank=True,related_name="master")
Here is my whole UserProfile class
class UserProfile(models.Model):
user=models.OneToOneField(User,
related_name='UserProfile',on_delete=models.CASCADE)
field=models.CharField(max_length=20,default="ce")
userPhoto=models.ImageField(upload_to='documents/',blank=True)
Type=models.BigIntegerField(choices=USER_TYPE,default=2)
gender=models.BigIntegerField(choices=GENDER_TYPE,default=1)
def __str__(self):
return self.user.username
#The decorator can also takes extra arguments which are passed onto the
signal
#receiver(post_save,sender=User)
def create_or_update_UserProfile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
instance.UserProfile.save()
I have an error in my admin page as below:
.
ProgrammingError at /admin/CEA/class/
column CEA_class.master_id does not exist LINE 1: ...time",
"CEA_class"."day", "CEA_class"."location", "CEA_class...
I solved this a while ago and found some references including in the Django doc, but I'm actually still not quite sure why this is needed as the underlying SQL structure doesn't (as far as I can tell in looking at my own database) show the variance in related_name - it appears to be an internal Django issue rather than an actual SQL issue. In any case, when you have more than one field related to the same other model within a table then all except one have to have something referencing the class in order to get Django to keep things straight. It is often cleanest to add class to ALL the related_names within a model that has the problem for consistency, though I have checked my own code and sometimes I do that, sometimes I don't:
students = models.ManyToManyField(UserProfile,blank=True,related_name="%(class)s_students")
master = models.ForeignKey(UserProfile,blank=True,related_name="%(class)s_master")
After all i came to this conclusion that the best way for deleting the Annoying irrelevant data that cause the problems is to temporary rename the model and migrate and then rename it to it's first name.By this way django itself take care of deleting relations and every data in database that causes your problem.
With all these interpretations,all of the suggested answers was helpful but i think the simple is better,why not. :))
I have a django 1.6 app with the following (trimmed for clarity)
classes defined. User is the standard django.contrib.auth User class.
class Event(models.Model):
user = models.ForeignKey(User, related_name='events')
name = models.CharField(max_length=64)
class Profile(models.Model):
user = models.ForeignKey(User, related_name='aprofile')
class MemberProfile(Profile):
pass
Here are my admin classes:
class ProfileAdmin(ModelAdmin):
model = Profile
fields = ('user', )
class MemberProfileAdmin(ModelAdmin):
model = MemberProfile
fields = ('user', )
readonly_fields = ('user', )
What I'd like to do is display a read-only list of all events for a given member, or at least profile. Of course joining across the User foreign key seems like the way to go, but I am drawing a blank as to how to accomplish this. Here's a summary of attempts so far.
Define an inline admin on the Event class directly referencing the user field, and add it to the ProfileAdmin:
class EventInlineAdmin(TabularInline):
model = Event
fk_name = 'user' # Fails - fk_name 'user' is not a ForeignKey to <class 'solo365.solo_profile.models.profile.Profile'>
...well, no, it sure isn't. But our User has an 'aprofile' field, so...
class EventInlineAdmin(TabularInline):
model = Event
fk_name = 'user__aprofile' # Fails - EventInlineAdmin.fk_name' refers to field 'user__aprofile' that is missing from model 'admin_fk_test.Event'.
Ok, those fields look like they should sync up, but perhaps we need to be a little more aggressive:
class EventInlineAdmin(TabularInline):
model = Event
fk_name = 'user__aprofile__pk' # Fails - 'EventInlineAdmin.fk_name' refers to field 'user__aprofile__pk' that is missing from model 'admin_fk_test.Event'.
I've also tried messing with formfield_for_foreignkey() and friends in both the inline and the regular model admins, but without that fk_name having a valid value, those methods never get called.
I then considered trying to access the events field directly from a Profile's user:
class ProfileAdmin(ModelAdmin):
model = Profile
fields = ('user', 'user__events') # Fails - Unknown field(s) (user__events) specified for Profile. Check fields/fieldsets/exclude attributes of class ProfileAdmin.
What about with a custom formfield_for_foreignkey() method? Sadly that never gets called for anything other than the 'user' field. I've also considered a custom get_formsets() method, but frankly I'm not sure how I could use that without a working EventInlineAdmin.
I could of course define a custom field that simply concatenates all of the events and returns that as a string, but ideally I would prefer something like a fully-featured inline (even read-only) than just a chunk o' text. IOW such a custom field would have a method that (ideally) would return an inline form without requiring any sort of custom template, setting of allow_tags, etc.
Am I doomed to have to create a completely custom Form for the Profile admin class? Or is there a simple way to accomplish what I'm trying to do, that I'm just missing?
Update:
Bonus points if a provided solution works for the MemberProfileAdmin class, not just the ProfileAdmin class.
The relation between User and Profile should be a 1:1 relation which would allow the referencing via user__aprofile. Otherwise, the reverse relation of a foreing key is a queryset because one foreign key can be assigned to multiple instances. This is might be the reason why your code failed.
Change it to:
class Profile(models.Model):
user = models.OneToOneKey(User, related_name='aprofile')
This is a bit like using ForeignKey(unique=True).
To know the attributes, it might help to call dir(model_instance) on the model instance in question, or try around in the Django shell (./manage.py shell).
Also, I've experienced that it might be more confusing to assign a custom related_name like in your case where you would expect one profile by looking at the related name but you would actually get back a queryset.
The generated name in that case would be profile_set, and you would have to call profile_set.all() or profile_set.values() to get some actual profiles.