I'm upgrading from 1.6 to 1.9.
My project includes code derived from this sample AuditTrail: https://code.djangoproject.com/wiki/AuditTrail
Essentially, this AuditTrail allows to create an Audit model on-the-fly to record any changes to an audit table.
Part of the code needs to make sure to avoid clashes between related_name. This is done as follows, and works fine as of 1.6.
if isinstance(field, models.ForeignKey):
rel = copy.copy(field.rel)
rel.related_name = '_audit_' + field.related_query_name()
attrs[field.name].remote_field = rel
For some reason, after upgrading, django fails with SystemCheckError on all of these, with a traceback looking like:
SystemCheckError: System check identified some issues:
ERRORS:
email_reporting.ReportAudit.team: (fields.E304) Reverse accessor for 'ReportAudit.team' clashes with reverse accessor for 'Report.team'.
HINT: Add or change a related_name argument to the definition for 'ReportAudit.team' or 'Report.team'.
email_reporting.ReportAudit.team: (fields.E305) Reverse query name for 'ReportAudit.team' clashes with reverse query name for 'Report.team'.
HINT: Add or change a related_name argument to the definition for 'ReportAudit.team' or 'Report.team'.
Any ideas how to fix it? I can't find any changes to related_name that may be the culprit.
This only happens if I start django with ./manage.py shell_plus, but things seem to boot up properly if started with ./manage.py shell.
The solution was to directly modify rel instead of remote_field
if isinstance(field, models.ForeignKey):
rel = copy.copy(field.rel)
if rel.related_name:
rel.related_name = '_audit_' + rel.related_name
elif rel:
rel.related_name = '_audit_' + rel.get_accessor_name()
attrs[field.name].rel.related_name=rel.related_name
Django 1.10
I just wanted to unify a common field in a general model and then inherit from it. I don't know how else I could adhere to DRY principle. But I can't make migrations. Could you give me a piece of advice here?
class GeneralModel(models.Model):
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="created_by")
class Meta:
abstract = True
class Image(GeneralModel):
...
class Masterphoto(GeneralModel):
...
Traceback
python manage.py makemigrations
SystemCheckError: System check identified some issues:
ERRORS:
image.Image.created_by: (fields.E304) Reverse accessor for 'Image.created_by' clashes with reverse accessor for 'Masterphoto.created_by'.
HINT: Add or change a related_name argument to the definition for 'Image.created_by' or 'Masterphoto.created_by'.
image.Image.created_by: (fields.E305) Reverse query name for 'Image.created_by' clashes with reverse query name for 'Masterphoto.created_by'.
HINT: Add or change a related_name argument to the definition for 'Image.created_by' or 'Masterphoto.created_by'.
masterphoto.Masterphoto.created_by: (fields.E304) Reverse accessor for 'Masterphoto.created_by' clashes with reverse accessor for 'Image.created_by'.
HINT: Add or change a related_name argument to the definition for 'Masterphoto.created_by' or 'Image.created_by'.
masterphoto.Masterphoto.created_by: (fields.E305) Reverse query name for 'Masterphoto.created_by' clashes with reverse query name for 'Image.created_by'.
HINT: Add or change a related_name argument to the definition for 'Masterphoto.created_by' or 'Image.created_by'.
This isn't anything to do with migrations.
Related names must be unique. The model inheritance docs explain what to do in this case; you can use '%(app_label)s' and '%(class)s' to automatically insert the relevant names into the generated value.
In a Django multi-table inheritance scenario:
from django.db import models
class Place(models.Model):
pass
class Restaurant(Place):
pass
the subclass can be accessed through a superclass instance with the lower-case class name:
place = Place.objects.get(id=id)
restaurant = place.restaurant # auto-generated from `Restaurant`
How can the accessor name be customized, such that:
restaurant = place.custom_accessor_name
?
Given that the accessor is an implicitly-created OneToOneField, it is not clear where the related_name can be customized. It seems possible to add:
custom_accessor_name = models.OneToOneField(Restaurant)
but it is not clear if such a field is redundant or not.
If you want to define the one or one field manually, then use parent_link=True. Otherwise, an additional field will be created.
This time I think it's not me being stupid but an actual conflict. I have the below code (simplified):
from django.db import models
class Alpha(models.Model):
relation = models.ForeignKey('Delta', related_name = 'reverse_relation', blank = True, null = True)
class Meta:
abstract = True
class Beta(Alpha):
pass
class Gamma(Alpha):
pass
class Delta(models.Model):
pass
The problem is that Delta.reverse_relation could refer to an instance of Beta or an instance of Gamma. I would somehow have to provide multiple related_name values (or one that depends on the class name).I think the problem is clear but to be complete, the error (when running syncdb):
app.beta: Accessor for field 'relation' clashes with related field 'Delta.reverse_relation'. Add a related_name argument to the definition for 'relation'.
app.beta: Reverse query name for field 'relation' clashes with related field 'Delta.reverse_relation'. Add a related_name argument to the definition for 'relation'.
app.gamma: Accessor for field 'relation' clashes with related field 'Delta.reverse_relation'. Add a related_name argument to the definition for 'relation'.
app.gamma: Reverse query name for field 'relation' clashes with related field 'Delta.reverse_relation'. Add a related_name argument to the definition for 'relation'.
Is it possible at all to place the ForeignKey in the parent Alpha, or is the only way to cut-paste this code to Beta and Gamma? I prefer not to do that because it kind of defeats the point of inheritance if I can't define in the parent half the fields that all children share.
Any help is much apprectiated!
(If anyone can comment with why the error messages aren't in a code box I'll fix that.)
I think that you will find the following advice in the Django documentation helpful and relevant:
https://docs.djangoproject.com/en/1.7/topics/db/models/#be-careful-with-related-name
Essentially change the declaration of the relation field to:
relation = models.ForeignKey('Delta', related_name="%(app_label)s_%(class)s")
Best of luck...
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'.