Django 1.9: Field clashes with the field of non-existing field in parent model

Jens-Erik Weber picture Jens-Erik Weber · Dec 4, 2015 · Viewed 12.6k times · Source

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.

Answer

Alex Polekha picture Alex Polekha · Dec 4, 2015

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.