related_name changed after 1.6 - django

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

Related

Django CharField unique=True seems not working while unique=True is set

I'm using Django 3.0.2 and sqlite3 DB.
I set following simple models:
from django.db import models
class Description(models.Model):
IDENTIFIER_LENGTH = 30
identifier = models.CharField(max_length=IDENTIFIER_LENGTH, blank=False, unique=True, primary_key=True)
Strangely, the unique=True seems not working. Following code run in shell mode
from testunique.models import Description
object = Description('first-object')
object.save()
object.save()
doesn't raise any error. For the record, here is the SQL code of the migrations:
BEGIN;
--
-- Create model Description
--
CREATE TABLE "testunique_description" ("identifier" varchar(30) NOT NULL PRIMARY KEY);
COMMIT;
What is wrong here? Thanks for the answer.
Django considers records with a set primary key as records already in the database. Therefore it will not perform a INSERT … query, but an UPDATE …. It is sometimes used as a trick to set the primary key in Django to None to make a copy of a given record (since then Django will make another INSERT … query).
You can force insertion with:
Description.objects.create(name='first-object')
Description.objects.create(name='first-object') # raises an error
or you can work with force_insert=True:
Description(name='first-object').save(force_insert=True)
Description(name='first-object').save(force_insert=True) # raises an error

Django models and relationships . error [duplicate]

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

Foreign key in superclass results in a clash while make migrations

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.

Django syncdb conflicting related_name when using inheritance and ForeignKey

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...

Django error message "Add a related_name argument to the definition"

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'.