Opened 13 years ago
Last modified 5 years ago
#16732 assigned Bug
Unable to have abstract model with unique_together
Reported by: | Mitar | Owned by: | Can Sarıgöl |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | mmitar@…, Giacomo Graziosi, direx | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | yes | 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 (10)
comment:1 by , 13 years ago
comment:2 by , 13 years ago
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 by , 13 years ago
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 by , 11 years ago
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 by , 10 years ago
Cc: | added |
---|
comment:6 by , 10 years ago
Cc: | added |
---|
comment:7 by , 6 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
Status: | new → assigned |
Version: | 1.3 → master |
PR
When I read the document about meta-inheritance, I didn't see the topic that in abstract = False
case What happens to child meta? as far as I could see from code, ordering
and get_latest_by
always moving in child meta in every situation. Should we change the code like my PR + document about {{{ abstract = False }} and fix the blown up test?
comment:8 by , 5 years ago
Patch needs improvement: | set |
---|
Topic for abstract = False
is not a part of "Abstract base classes" documentation (see meta-and-multi-table-inheritance). Falling tests show that it is not a proper solution. ('suffix1', 'suffix2')
should be inherited from an abstract class BookXtra
. I'm afraid that proposed change is strongly backward incompatible.
comment:9 by , 5 years ago
Patch needs improvement: | unset |
---|
I got your backward-incompatible concern. I added a case for classes that have more than one inherited classes and abstract at least one. this can solve BookXtra test.
comment:10 by , 5 years ago
Needs tests: | set |
---|
But this does work:
And also creates tables as wanted.