Reverse accessor clasher with Django [duplicate] - python

D:\zjm_code\basic_project>python manage.py syncdb
Error: One or more models did not validate:
topics.topic: Accessor for field 'content_type' clashes with related field 'Cont
entType.topic_set'. Add a related_name argument to the definition for 'content_t
ype'.
topics.topic: Accessor for field 'creator' clashes with related field 'User.crea
ted_topics'. Add a related_name argument to the definition for 'creator'.
topics.topic: Reverse query name for field 'creator' clashes with related field
'User.created_topics'. Add a related_name argument to the definition for 'creato
r'.
topicsMap.topic: Accessor for field 'content_type' clashes with related field 'C
ontentType.topic_set'. Add a related_name argument to the definition for 'conten
t_type'.
topicsMap.topic: Accessor for field 'creator' clashes with related field 'User.c
reated_topics'. Add a related_name argument to the definition for 'creator'.
topicsMap.topic: Reverse query name for field 'creator' clashes with related fie
ld 'User.created_topics'. Add a related_name argument to the definition for 'cre
ator'.

You have a number of foreign keys which django is unable to generate unique names for.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
Eg:
content_type = ForeignKey(Topic, related_name='topic_content_type')
See here for more.
http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name

Example:
class Article(models.Model):
author = models.ForeignKey('accounts.User')
editor = models.ForeignKey('accounts.User')
This will cause the error, because Django tries to automatically create a backwards relation for instances of accounts.User for each foreign key relation to user like user.article_set. This default method is ambiguous. Would user.article_set.all() refer to the user's articles related by the author field, or by the editor field?
Solution:
class Article(models.Model):
author = models.ForeignKey('accounts.User', related_name='author_article_set')
editor = models.ForeignKey('accounts.User', related_name='editor_article_set')
Now, for an instance of user user, there are two different manager methods:
user.author_article_set — user.author_article_set.all() will return a Queryset of all Article objects that have author == user
user.editor_article_set — user.editor_article_set.all() will return a Queryset of all Article objects that have editor == user
Note:
This is an old example — on_delete is now another required argument to models.ForeignKey. Details at What does on_delete do on Django models?

"If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased."
But if you have more than one foreign key in a model, django is unable to generate unique names for foreign-key manager.
You can help out by adding "related_name" arguments to the foreignkey field definitions in your models.
See here:
https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward

If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in th

If your models are inheriting from the same parent model, you should set a unique related_name in the parent's ForeignKey. For example:
author = models.ForeignKey('accounts.User', related_name='%(app_label)s_%(class)s_related')
It's better explained in the docs

I had a similar problem when I was trying to code a solution for a table that would pull names of football teams from the same table.
My table looked like this:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE)
making the below changes solved my issue:
hometeamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='home_team')
awayteamID = models.ForeignKey(Team, null=False, on_delete=models.CASCADE,related_name='away_team')

But in my case i am create a separate app for some functionality with same model name and field ( copy/paste ;) ) that's because of this type of error occurs i am just deleted the old model and code will work fine
May be help full for beginners like me :)

This isn't an ultimate answer for the question, however for someone it may solve the problem.
I got the same error in my project after checking out a really old commit (going to detached head state) and then getting the code base back up to date. Solution was to delete all *.pyc files in the project.

Do as the error message instructs you to:
Add a related_name argument to the
definition for 'creator'.

Related

How to make a username as a foreign key of another model in django

I am very new to Django. I want to link a model which has 2 field 'username' and 'password'. I want to make 'username' field as as Foreign in another model. But as per Django we can only pass the whole Model Object, who is referring to as it's foreign key.
am I wrong somewhere? please give me any solution regarding this basic problem.
No you can link to any unique field of a Django model. So if your models look like:
class Target(models.Model):
name = models.CharField(max_length=128, unique=True)
class SourceModel(models.Model):
target = models.ForeignKey(Target, to_field='name', on_delete=models.CASCADE)
You can assign the value of the target column to the target_id then. So for example:
Target.objects.create(name='target1')
SourceModel.objects.create(target_id='target1')
So you do not need to pass a Target object itself. You can use the …_id "twin" field to use the target column value. The database will normally enforce referential integrity, and thus will prevent passing a non-existing value to the foreign key column.

Cannot delete some instances of model because of FK

Python 3.6 and Django 1.11.7.
I've got two Models look like the following:
class User():
name = models.CharField()
...
class UserInfo():
user = models.OneToOneField(User, on_delete=models.PROTECT, primary_key=True, related_name='info')
I wanted to delete some user instance A, and I explicitly deleted user A's info. But when I tried to delete the user model user.delete(), I got the ProtecedError:
ProtectedError: ("Cannot delete some instances of model 'User' because they are referenced through a protected foreign key: 'UserInfo.user'", <QuerySet [<UserInfo: UserInfo object>]>)
Then I tried to put the delete inside a try/catch looks like follows:
try:
user.delete()
except ProtectedError:
UserInfo.objects.filter(user=user).delete()
user.delete()
But still got the same exception. What might went wrong in my operation?
You are using a protect clause on the related objects:
on_delete=models.PROTECT
You can check it in the documentation on:
https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ForeignKey.on_delete
You have it pointed here:
PROTECT[source]
Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.
Remove the on_delete=models.PROTECT on your user field. And run manage.py makemigrations
ForeignKey fields have a default value of CASCADE for the on_delete argument. This means that deleting the user object will cascade down and also delete the userinfo object linked to that user.
Looks like this is the behaviour you are looking for.
You can read more about this in the documentation documentation
Also note although on_delete has a default value fo CASCADE this argument will be required from Django 2.0.

Difference between 'related_name' and 'related_query_name' attributes in Django?

Can you explain the difference between related_name and related_query_name attributes for the Field object in Django ? When I use them, How to use them? Thanks!
related_name will be the attribute of the related object that allows you to go 'backwards' to the model with the foreign key on it. For example, if ModelA has a field like: model_b = ForeignKeyField(ModelB, related_name='model_as'), this would enable you to access the ModelA instances that are related to your ModelB instance by going model_b_instance.model_as.all(). Note that this is generally written with a plural for a Foreign Key, because a foreign key is a one to many relationship, and the many side of that equation is the model with the Foreign Key field declared on it.
The further explanation linked to in the docs is helpful. https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
related_query_name is for use in Django querysets. It allows you to filter on the reverse relationship of a foreign key related field. To continue our example - having a field on Model A like:
model_b = ForeignKeyField(ModelB, related_query_name='model_a') would enable you to use model_a as a lookup parameter in a queryset, like: ModelB.objects.filter(model_a=whatever). It is more common to use a singular form for the related_query_name. As the docs say, it isn't necessary to specify both (or either of) related_name and related_query_name. Django has sensible defaults.
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
Here foreign key forward relation is Album to musician and backward relation is musician to album. This means one album instance can have relation with only one musician instance(forward relation), and one musician instance can relate to multiple album instance(backward).
Forward query will be like this
Album_instance.artist
note here forward query done by Album_instance followed by artist(field name). and backward would be
Musician_instance.album_set.all()
here for backward query modelname_set is used .
now if you specifies the related_name like
artist = models.ForeignKey(Musician, on_delete=models.CASCADE, related_name='back')
then backward query syntax will be change modelname_set(artist.set) will be replace by back.
now backward query
Musician_instance.back.all()
If you’d prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'.
and related_query_name to use for the reverse filter name from the target model

Reverse accessor for X clashes with reverse accessor for Y [duplicate]

I'm trying to use the same foreign key for two fields in the same model and am getting an error.
Im trying to have a primary and secondary on call user, but am not sure how to format the relationship after receiving the errors below
class ManualRotas(models.Model):
rota_name = models.CharField(max_length=200,choices=settings.ONCALL_ROTAS)
primary_user = models.ForeignKey(User, unique=True, verbose_name="Primary OnCall Engineer")
p_start_time = models.DateTimeField(verbose_name="Start Time")
p_end_time = models.DateTimeField(verbose_name="End Time")
secondary_user = models.ForeignKey(User, verbose_name="Backup OnCall Engineer", unique=True,blank=True,null=True)
s_start_time = models.DateTimeField(blank=True,null=True, verbose_name="Start Time")
s_end_time = models.DateTimeField(blank=True,null=True,verbose_name="Start Time")
ERRORS:
oncall.ManualRotas.primary_user: (fields.E304) Reverse accessor for 'ManualRotas.primary_user' clashes with reverse accessor for 'ManualRotas.secondary_user'.
HINT: Add or change a related_name argument to the definition for 'ManualRotas.primary_user' or 'ManualRotas.secondary_user'.
oncall.ManualRotas.secondary_user: (fields.E304) Reverse accessor for 'ManualRotas.secondary_user' clashes with reverse accessor for 'ManualRotas.primary_user'.
HINT: Add or change a related_name argument to the definition for 'ManualRotas.secondary_user' or 'ManualRotas.primary_user'.
WARNINGS:
oncall.ManualRotas.primary_user: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.
oncall.ManualRotas.secondary_user: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.
System check identified 4 issues (0 silenced).
You have to define different related_name to both the ForeignKeys columns. For example:
class ManualRotas(models.Model):
primary_user = models.ForeignKey(User, related_name='related_primary_manual_roats', unique=True, verbose_name="Primary OnCall Engineer")
# related names ^ v
secondary_user = models.ForeignKey(User, related_name='related_secondary_manual_roats', verbose_name="Backup OnCall Engineer", unique=True,blank=True,null=True)
# .... Other columns
Please also refer ForeignKey.related_name document, which says:
The name to use for the relation from the related object back to this one. It’s also the default value for related_query_name (the name to use for the reverse filter name from the target model). See the related objects documentation for a full explanation and example. Note that you must set this value when defining relations on abstract models; and when you do so some special syntax is available.
Related posts:
Django: reverse accessors for foreign keys clashing
Django Reverse Accessor Clashes

What is choice_set in this Django app tutorial?

There is this line in the Django tutorial, Writing your first Django app, part 1:
p.choice_set.create(choice='Not much', votes=0)
How is choice_set called into existence and what is it?
I suppose the choice part is the lowercase version of the model Choice used in the tutorial, but what is choice_set? Can you elaborate?
UPDATE: Based on Ben's answer, I located this documentation: Following relationships "backward".
You created a foreign key on Choice which relates each one to a Question.
So, each Choice explicitly has a question field, which you declared in the model.
Django's ORM follows the relationship backwards from Question too, automatically generating a field on each instance called foo_set where Foo is the model with a ForeignKey field to that model.
choice_set is a RelatedManager which can create querysets of Choice objects which relate to the Question instance, e.g. q.choice_set.all()
If you don't like the foo_set naming which Django chooses automatically, or if you have more than one foreign key to the same model and need to distinguish them, you can choose your own overriding name using the related_name argument to ForeignKey.
Two crucial questions are asked here. First: How is choice_set called into existence. Second: What is it?
For all new developers like me, Let me describe how I made it easy for me. Let me answer the second question first. "What is it", through these 3 words? Model Instance, Objects-set related to that instance, Related_manager.
Models.py from Django tutorial:
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
Instance:
q = Question.objects.get(pk=3)
# Here q is an instance of model class 'Question'.
c = Choice.objects.get(pk=32)
# Here c is an instance of model class 'Choice'.
'Model Instance' is a single 'ROW' of an entire 'TABLE' of your database
Here, the Question Model is used as a foreign key to the Choice Model. Therefore, all the objects-set related to instance q can be filtered by using:
q.choice_set.all()
Therefore, choice_set here is, all the choices related to the question, that has pk=3.
Now, the answer to the first question needs the third word Related Manager. Django documentation here:-
If a model has a ForeignKey, instances of the foreign-key model will
have access to a Manager that returns all instances of the first
model. By default, this Manager is named FOO_set, where FOO is the
source model name, lowercased. This Manager returns QuerySets, which
can be filtered and manipulated as described in the “Retrieving
objects” section above.
This word (choice_set) can be changed using the 'related_name' parameter in the Foreign_key.
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices")
For backward relationtionship through foreign key:
q.choice_set.all()
# If using related_name, then it is same as
q.choices.all()
# All the choices related to the instance q.
For forward relationship:
choice_qs = Choice.objects.all()
choice_qs.filter(question=q)
# Same result as above. All the choices related to instance q.

Categories