37

I have some simple models, Profile, Certifier and Designer, the two latter inheriting from Profile (multi table inheritance). In Designer there’s a foreign key to Certifier.

class Profile(models.Model):
    TYPES = (
        ('admin', _('Administrator')),
        ('certifier', _('Certifier')),
        ('designer', _('Designer'))
    )
    
    user = models.OneToOneField(User)
    type = models.CharField(max_length=9, choices=TYPES)
    
    def __str__(self):
        return self.user.username + ' (' + self.type + ')'

class Admin(Profile):
    pass
class Certifier(Profile):
    pass
class Designer(Profile):
    certifier = models.ForeignKey(Certifier)

In Django 1.8 this works perfectly, but in 1.9 I get;

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:

check.Designer.certifier: (models.E006) The field 'certifier' clashes with the field 'certifier' from model 'check.profile'.

(Profile.type is irrelevant in this case, I just need it to distinguish logged in user profile types).

check.profile obviously doesn’t have a field 'certifier'. Is this a bug or do I miss something? The same thing happens in another project.

Community
  • 1
  • 1
Jens-Erik Weber
  • 478
  • 1
  • 4
  • 11
  • Do you have conflicting migration files (006 perhaps)?, are you sharing a database? you mention that it happens in another project – Sayse Dec 04 '15 at 12:01
  • 1
    @Sayse E006 is the [error code](https://docs.djangoproject.com/en/1.9/ref/checks/#core-system-checks) from the system checks framework, not a migration number. – Alasdair Dec 04 '15 at 12:09
  • 1
    @Alasdair - Ah of course it is, Still think the problem is (was) possibly a conflicting migration – Sayse Dec 04 '15 at 12:10
  • 2
    There were no migration problems in 1.8 , and I don’t share the database with other programs. After renaming the field, the migrations caused by the 1.9 upgrade in admin and auth also worked fine. The other occurrence of this issue is in another project, but also with a case of multi table inheritance with a foreign key: parent model Component, both Window and Spacer inherit from Component, and there’s a foreign key pointing from Window to a Spacer, and the field name is spacer. – Jens-Erik Weber Dec 04 '15 at 12:18
  • This seems to be poor design in 1.9, or simply a bug. I now have a perfectly functional database created under 1.8 that errors on makemigrations in 1.9. Plus, related_name seems the obvious solution to resolve the issue but it does not. – tufelkinder Dec 14 '15 at 08:18

2 Answers2

31

I think that you shouldn't use name certifier for that foreign key relation because class Profile actually has certifier, admin and designer fields(although by descriptor) according to docs and in that case names actually would clash.

from django.contrib.auth.models import User

c = Certifier.objects.create(
    type='admin',
    user=User.objects.latest('date_joined'),
)

p = c.profile_ptr
print(p.certifier) #username (admin)

Change to something like certifier_field = models.ForeignKey(Certifier)

As it was pointed out in comments, you could rename the models to CertifierProfile, AdminProfile etc to avoid the clash.

Or you could also silence the check by adding SILENCED_SYSTEM_CHECKS = ['models.E006'] to your settings, but this is not a good approach.

Vineeth Sai
  • 3,389
  • 7
  • 23
  • 34
Alex Polekha
  • 1,590
  • 15
  • 13
  • I also wasn't glad to adjust my projects. I just tryed to explain reasons for django developers to impose this new requirement. – Alex Polekha Dec 04 '15 at 12:04
  • 2
    It solves the problem in 1.9, but nevertheless, it’s not nice to have such field names, especially because everything worked until 1.8 with the field name certifier. – Jens-Erik Weber Dec 04 '15 at 12:05
  • 4
    The [Django docs](https://docs.djangoproject.com/en/1.9/topics/db/models/#multi-table-inheritance) say that you can go from the parent model `Profile` to its child `Certifier` with `profile.certifier`. Defining another `certifier` field is ambiguous, so a check for this has been added to 1.9. If you really wanted to, you could [silence the check](https://docs.djangoproject.com/en/1.9/ref/settings/#silenced-system-checks) by adding `SILENCED_SYSTEM_CHECKS = ['models.E006']` to your settings, but I wouldn't recommend this. – Alasdair Dec 04 '15 at 12:18
  • 3
    If you don't like `certifier_field`, you could rename the models to `CertifierProfile`, `AdminProfile` etc to avoid the clash. Or, you could try setting the [parent field](https://docs.djangoproject.com/en/1.8/topics/db/models/#specifying-the-parent-link-field) with a `related_name`. – Alasdair Dec 04 '15 at 12:22
  • 1
    Okay, thanks for the solution, explanation and comments! – Jens-Erik Weber Dec 04 '15 at 12:25
  • 2
    In my case (using django_model_utils InheritanceManager), silencing the check seems to be the best solution. Applying irrational names to the fields as a work around was not appealing. Everything seems to work fine, including the attribute name on the superclass and the subclass (not that I needed the former). – Paul Whipp Jun 06 '16 at 23:35
30

You can specify Profile is an abstract class. This will stop the check from being confused with your parent fields.

class Meta:
    abstract = True
mrcai
  • 301
  • 3
  • 2
  • I think it's probably a good rule of thumb to "never have a field name match the model name", however doing this can help avoid a major rewrite if you have a ton of logic tied to the field name (ie the field exists on API endpoints and is relied on by consuming apps) – alukach Nov 10 '16 at 18:07
  • Thanks, this works and I don't have to rename anything. – R891 Nov 18 '20 at 10:10