Opened 7 years ago
Last modified 3 years ago
#16732 new Bug
Unable to have abstract model with unique_together
Reported by: | Mitar | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.3 |
Severity: | Normal | Keywords: | |
Cc: | mmitar@…, segfault, direx | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I have such model definition:
class SlugVersion(models.Model): class Meta: abstract = True unique_together = (('slug', 'version'),) slug = models.CharField(db_index=True, max_length=10, editable=False) version = models.IntegerField(db_index=True, editable=False) class Base(SlugVersion): name = models.CharField(max_length=10) class Test(Base): test = models.IntegerField()
And I am getting:
Error: One or more models did not validate: test.test: "unique_together" refers to slug. This is not in the same model as the unique_together statement. test.test: "unique_together" refers to version. This is not in the same model as the unique_together statement.
I see this is as a bug. Why there could not be a table for class Base
with unique constraints on its slug
and version
fields, and then 1-1 relationship with additional table for model Test
with field test
.
Change History (6)
comment:1 Changed 7 years ago by
comment:2 Changed 7 years ago by
Using such metaclass for Base
class above solves the problem:
class ModelBaseFix(models.base.ModelBase): def __new__(cls, name, bases, attrs): # We simply remove all unique_together values which we find in a parent new_class = super(ModelBaseFix, cls).__new__(cls, name, bases, attrs) unique_together = list(new_class._meta.unique_together) for parent_class in new_class._meta.parents.keys(): for parent_unique_together in parent_class._meta.unique_together: try: unique_together.remove(parent_unique_together) except ValueError: pass new_class._meta.unique_together = tuple(unique_together) return new_class
comment:3 Changed 7 years ago by
Triage Stage: | Unreviewed → Accepted |
---|
If I add this code below the models definition in the original report:
print SlugVersion._meta.abstract, SlugVersion._meta.unique_together print Base._meta.abstract, Base._meta.unique_together print Test._meta.abstract, Test._meta.unique_together
I get:
% ./manage.py validate True (('slug', 'version'),) False (('slug', 'version'),) False (('slug', 'version'),) Error: One or more models did not validate: selftest.test: "unique_together" refers to slug. This is not in the same model as the unique_together statement. selftest.test: "unique_together" refers to version. This is not in the same model as the unique_together statement.
This shows that Test
inherits the Meta
of Base
, which is wrong, because Base
isn't abstract.
comment:4 Changed 4 years ago by
Would this ever be fixed?
I have been avoiding the use of abstract models because of this and it prevents the model declarations from being DRY...
comment:5 Changed 3 years ago by
Cc: | segfault added |
---|
comment:6 Changed 3 years ago by
Cc: | direx added |
---|
But this does work:
And also creates tables as wanted.