djangoname-clashmulti-table-inheritancedjango-1.9

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


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.


Solution

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