Django: related_name Reverse accessor - python

I have this model where InstitutePerson is a subclass of Person.
Person
InstitutePerson
Project
In Project:
participants_institite = models.ManyToManyField(InstitutePerson, blank = True, null = True)
participants_exterior = models.ManyToManyField(Person, blank = True, null = True)
I get an error:
Project.participants_institute: (fields.E304) Reverse accessor for 'Project.participants_institute' clashes with reverse accesor for 'Project.participants_exterior'.
I thought that related_name would solve the problem but after seeing some posts (related_name argument not working as expected in Django model?) I'm not sure how to proceed because of the inheritance among the classes.

Use related_name arg and define it manually
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
If you have two M2M field with same type Django can't generate properties on target modela automatically.
if you are not intereset in reversed direction, you can simply ise
models.ManyToManyField(..., related_name='+r1')
models.ManyToManyField(..., related_name='+r2')

Related

How can a model have multiple keys with the same type of models as values?

I'm making an application and I should make a Model which have 2 keys that saves models of the same type.
It's not easy to express in English so I will upload the image of the situation.
In Food Pair Model ( or we can call it table I think )
I want to refer Food Model But I wasn't able to use ForeignKey or ManyToManyField.
ERRORS:
food_test.FoodQuestion.left_food: (fields.E304) Reverse accessor for 'FoodQuestion.left_food' clashes with reverse accessor for 'FoodQuestion.right_food'.
HINT: Add or change a related_name argument to the definition for 'FoodQuestion.left_food' or 'FoodQuestion.right_food'.
food_test.FoodQuestion.right_food: (fields.E304) Reverse accessor for 'FoodQuestion.right_food' clashes with reverse accessor for 'FoodQuestion.left_food'.
HINT: Add or change a related_name argument to the definition for 'FoodQuestion.right_food' or 'FoodQuestion.left_food'.
I don't know what database relation to use in this case and how to make it.
What can I use for this case?
When you create a ForeignKey from one model to another Django will dynamically create a property on the model being referenced that will return a QuerySet with all objects that have the foreign key to that object
For example
class Foo(models.Model):
pass
class Bar(models.Model):
foo = models.ForeignKey(Foo, on_delete=models.CASCADE)
foo = Foo.objects.create()
bar = Bar.objects.create(foo=foo)
foo.bar_set.all() # This will return a queryset containing foo
By default this property will be <model_name_lowercase>_set. In your case because you have 2 foreign keys from one model to the same model Django is trying to create the same property on the Food model for each foreign key.
To get around this issue you can specify the name of this property using related_name, if you set this to '+' no reverse relation will be made at all or give them unique names
class FoodQuestion(models.Model):
left_food = models.ForeignKey(Food, on_delete=models.CASCADE, related_name='+')
left_food = models.ForeignKey(Food, on_delete=models.CASCADE, related_name='+')
You must define a unique related_name for each ForeignKey field in your FoodPair model.
class FoodPair(models.Model):
first_food = models.ForeignKey(Food, related_name="first_food")
second_food = models.ForeignKey(Food, related_name="second_food")
what_i_buy = models.ForeignKey(Food, related_name="what_i_buy")
If related_name is not defined Django automatically sets it and when there is multiple ForeignKey fields pointing to the same model the names clash.

Export User model into different app

I have a project with one app, where user, their posts and other models are located. Now I want to separate User model and put it into different app, called users.
How should I do this correctly? And how do I use this model in the old app?
User model of the first app looks like this:
class User(AbstractUser):
class Meta:
permissions = (
('can_do_this', 'Permission1'),
('can_do_that', 'Permission2'),
...,
)
User model of the second (users)app looks like this:
class ExternalUser(AbstractUser):
class Meta:
permissions = (
('can_do_this', 'Permission1'),
('can_do_that', 'Permission2'),
...,
)
I've done django-admin startapp users and copy-pasted user's model code into created app models.py.
Then I tried makemigrations and it failed, showing:
SystemCheckError: System check identified some issues:
ERRORS:
photogal.User.groups: (fields.E304) Reverse accessor for 'User.groups'
clashes with reverse accessor for 'ExternalUser.groups'.
HINT: Add or change a related_name argument to the definition for
'User.groups' or 'ExternalUser.groups'.
photogal.User.user_permissions: (fields.E304) Reverse accessor for
'User.user_permissions' clashes with reverse accessor for
'ExternalUser.user_permissions'.
HINT: Add or change a related_name argument to the definition for
'User.user_permissions' or 'ExternalUser.user_permissions'.
users.ExternalUser.groups: (fields.E304) Reverse accessor for
'ExternalUser.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for
'ExternalUser.groups' or 'User.groups'.
users.ExternalUser.user_permissions: (fields.E304) Reverse accessor for
'ExternalUser.user_permissions' clashes with reverse accessor for
'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for
'ExternalUser.user_permissions' or 'User.user_permissions'.
Adding related_name='+' to the old user model resulted in:
ERRORS:
<class 'django.contrib.auth.admin.UserAdmin'>: (admin.E020) The value of
'filter_horizontal[0]' must be a many-to-many field.
<class 'django.contrib.auth.admin.UserAdmin'>: (admin.E020) The value of
'filter_horizontal[1]' must be a many-to-many field.
Thanks!
Simply delete the old User model from the previous app, and put the new one in the new app, so that in the end you only have one User class that extends the AbstractUser class.
As for your second issue, try this.
I hope this helps.

Django: reverse accessors for foreign keys clashing

I have two Django models which inherit from a base class:
- Request
- Inquiry
- Analysis
Request has two foreign keys to the built-in User model.
create_user = models.ForeignKey(User, related_name='requests_created')
assign_user = models.ForeignKey(User, related_name='requests_assigned')
For some reason I'm getting the error
Reverse accessor for 'Analysis.assign_user' clashes with reverse accessor for 'Inquiry.assign_user'.
Everything I've read says that setting the related_name should prevent the clash, but I'm still getting the same error. Can anyone think of why this would be happening? Thanks!
The related_name would ensure that the fields were not conflicting with each other, but you have two models, each of which has both of those fields. You need to put the name of the concrete model in each one, which you can do with some special string substitution:
create_user = models.ForeignKey(User, related_name='%(class)s_requests_created')

Two ManyToMany fields without backwards relation

I'm trying to have a model with 2 ManyToMany fields without allowing a backwards relation.
So here is the model:
class Camp(models.Model):
#...
free_options = models.ManyToManyField('Option', related_name='+')
paid_options = models.ManyToManyField('Option', related_name='+')
After trying to do
python manage.py syncdb
I'm getting the following error:
Error: One or more models did not validate: camps.camp: Accessor for
m2m field 'free_options' clashes with related m2m field 'Option.+'.
Add a related_name argument to the definition for 'free_options'.
camps.camp: Reverse query name for m2m field 'free_options' clashes
with related m2m field 'Option.+'. Add a related_name argument to the
definition for 'free_o ptions'.
Is it not possible to have 2 fields without backwards relation on the same model? how can i fix this?
Thanks!
I would ask why you're bothered by having the backwards relation, just don't use it if you don't want it. But to answer the question, no there isn't a way to remove it entirely.
According to the Django documentation for the related_name argument of the ManyToManyField:
If you have more than one ManyToManyField pointing to the same model
and want to suppress the backwards relations, set each related_name to
a unique value ending with '+'
Emphasis mine.
So if you want to do that, you should be able to simply:
class Camp(models.Model):
#...
free_options = models.ManyToManyField('Option', related_name='free_options+')
paid_options = models.ManyToManyField('Option', related_name='paid_options+')
# ^^^^^^^^^^^^
to suppress the backwards relation on multiple ManyToManyField's in the same model.
Hope this helps!

related_name argument not working as expected in Django model?

I recently got a ForeignKey clash in my Django model. I have the need to have two foreign keys (owner, assigned_to) ultimately pointing to the same model (a user).
From what I understand I need a related_name argument to solve that problem. So I did that:
assigned_to = models.ForeignKey(TaskUser, blank=True, null=True, related_name='user_assignment')
and
owner = models.ForeignKey(TaskUser, related_name="user_ownership"
But I'm still getting an error:
tasks.task: Accessor for field 'owner' clashes with related field 'TaskUser.user
_ownership'. Add a related_name argument to the definition for 'owner'.
tasks.task: Reverse query name for field 'owner' clashes with related field 'TaskUser.user_ownership'. Add a related_name argument to the definition for 'owner'.
Why am I still getting this error?
There is one catch, owner is in a super class (BaseWidget) and assigned_to is in a sub class (Task). Are there issues with using related_name in an inheritance relationship? Do I need to just override the inheritance of owner and redefine related_name in the sub class instead? I'd appreciate any help!
If you have ForeignKey relationships in an abstract base class every class inheriting from it will have this relationship. As a result of this you must not 'hardcode' its related_name, because all sub classes will try to create the same accessor on the realted class (TaskUser in this case).
You should better do something like:
owner = models.ForeignKey(TaskUser, related_name="%(app_label)s_%(class)s_ownership")
See the django docs on this.
If you are using related_name in abstract base class you need to use a '%(app_label)s' and '%(class)s' in it.
Its mentioned in django doc
Be careful with related_name

Categories

Resources