Opened 4 years ago

Closed 4 years ago

#15953 closed New feature (wontfix)

Allow setting individual fields as 'unique' from the model Meta options

Reported by: julien Owned by: nobody
Component: Database layer (models, ORM) Version: 1.3
Severity: Normal Keywords:
Cc: jonas-django@… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by julien)

I'm dealing with this case:

class A(models.Model):
    blah = models.CharField(max_length=100)

    class Meta:
        abstract = True

class B(A):
    pass

... where A is in a separate app than B and is used in multiple different contexts. I need to have the blah field be unique for B, whereas it shouldn't necessarily be unique in every other context where it is used. The only way I've found so far is:

class B(A):
    pass

B._meta.get_field('blah')._unique = True # Ugliness alert!

Is it envisageable to allow setting the unique flag for individual fields from the Meta options, in the same way as with unique_together? Something like this for example:

class B(A):

    class Meta:
        unique = ('blah',)

Change History (10)

comment:1 Changed 4 years ago by julien

  • Description modified (diff)

(fixed description: B inherits from A)

comment:2 Changed 4 years ago by julien

  • Description modified (diff)

comment:3 follow-up: Changed 4 years ago by jezdez

Wouldn't overriding the blah field in class B solve the issue?

comment:4 in reply to: ↑ 3 Changed 4 years ago by julien

Replying to jezdez:

Wouldn't overriding the blah field in class B solve the issue?

Unfortunately not -- you get the following error:

django.core.exceptions.FieldError: Local field 'blah' in class 'B' clashes with field of similar name from base class 'A'

comment:5 Changed 4 years ago by jezdez

Uh, seems like a bug to me, but the ORM isn't my strong field.. waiting for someone capable to review it.

comment:6 Changed 4 years ago by jonash

  • Cc jonas-django@… added

comment:7 Changed 4 years ago by julien

Just a note. The new feature suggested here would be in the same spirit as ModelForm.Meta.widgets [1], which allows to override the widgets for given individual form fields instead of having to redefine the entire fields themselves. So, even if it were possible to override an entire Model field, I think it would still be nice to be able to override certain field properties, like unique for example.

I understand that we don't want to overload the Meta options, but hopefully it would make sense in this case. I don't know enough about the ORM to predict if there could be bad side effects so I'm leaving it up to the ORM experts to decide ;-)

[1] http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets

comment:8 Changed 4 years ago by Alex

  • Triage Stage changed from Unreviewed to Design decision needed

I'm -1 on this feature, it moves a field level option to the model level, which is wrong, also if the issue is inheritance solving just one special case is the complete wrong way to do this. Finally, a strong argument can be made that it's completely inappropriate to allow changing the field on subclasses (even in the abstract case, it obviously is in the MTI case). Marking as DDN for now, but I'm inclined to wontfix it.

comment:9 Changed 4 years ago by julien

That's fair enough. Thanks for your feedback. I'm not too precious about this and I won't mind if it gets wontfixed.

Just for the sake of argumentation, the case could also be made that the framework could allow the overriding of certain field properties at the Model level, in the same way as, like noted above, a form field's widget property can be overridden at the ModelForm level. Purely as a convenience.

Also, I often see many of the constraints linked to model inheritance, like to one pointed out by this ticket, quite unfortunate as they drastically limit the possibilities of making apps reusable. In my case, it's a shame that the abstract class A cannot be reused so easily in any context, where certain of its fields may or may not be unique. One approach would be to have the app ship some mixins A1 and A2, both defining a blah field but the former setting unique=False and the latter unique=True. But again, this would mean the app would have to anticipate every use case it might be used in, which again goes against the principles of reusability.

Anyway, for me this would be a nice-to-have feature rather than something essential. Maybe this is also highlighting some bigger issues with Django's handling of model inheritance and therefore should be part of a broader discussion.

comment:10 Changed 4 years ago by mtredinnick

  • Resolution set to wontfix
  • Status changed from new to closed
  • UI/UX unset

I'm with Alex for most of the same reasons. Retrofitting the database level behaviour of a parent class feels a bit fragile. Model inheritance differs from Python class inheritance in a few ways and overriding is one of them. A field validator is probably one solution here.

The reuse argument doesn't convince me a lot, either. If the field is genuinely intended to be reused as unique, it should be marked as such. It's not really subclassing when it's both unique and non-unique in different situations -- it's attempting to reuse something of the same name in different context, not using "is-a" relationships.

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