Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#24542 closed Bug (fixed)

Inheriting from multiple abstract model base classes with the same field leads to invalid SQL and db-level exception

Reported by: Ien Cheng Owned by: nobody
Component: Database layer (models, ORM) Version: 1.6
Severity: Normal Keywords: multiple model inheritance sql fielderror
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given the following model classes:

class Daddy(models.Model):

    class Meta:
        abstract = True

    foobar = models.CharField(default="", max_length=20)


class Mommy(models.Model):

    class Meta:
        abstract = True

    foobar = models.CharField(default="", max_length=20)


class Kid(Daddy, Mommy):
    pass

Django will validate this. However, the foobar field will show up twice in Kid._meta.local_fields, and if you try to save a Kid model instance, Django will generate SQL code that references foobar twice, leading to a hard-to-debug database level exception.

I suggest expected behavior to be either (1) throw a FieldError on validation (consistent with what Django does if a child model tries to "hide" a parent's field) or (2) ignore subsequent model fields from abstract model base classes (per MRO-order) with the same name as existing fields.

The real-world context that led to this bug discovery: in refactoring a large existing project, I subclassed models.Model and had all project models inherit from this subclass, which added a new field (let's call it foobar). Some models had multiple abstract base classes that subclassed from models.Model, in a typical mixin pattern. Django was validating and then creating foobar twice for such models, leading to the database error due to invalid SQL.

Change History (2)

comment:1 by Tim Graham, 10 years ago

Resolution: fixed
Status: newclosed

It's been fixed in Django 1.7 with the following validation error: polls.Kid.foobar: (models.E006) The field 'foobar' clashes with the field 'foobar' from model 'polls.kid'.

comment:2 by Ien Cheng, 10 years ago

Thanks Tim for the fast turnaround on this!

Note: See TracTickets for help on using tickets.
Back to Top