#30920 closed New feature (wontfix)
Choice enumeration types should not enforce enum.unique().
Reported by: | Steve Jorgensen | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.0 |
Severity: | Normal | Keywords: | |
Cc: | Shai Berger, pope1ni | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The stated reason that Choice enumeration types enforce enum.unique()
is "to ensure that values cannot be defined multiple times" but that's a misunderstanding of how Enum
works with values and what enum.unique()
is for.
Enum
already enforces that no 2 instances may have the same value, but by default, it allows 2 or more attributes to refer to that same instance.
I believe that is desirable to allow situations like the following:
class Vehicle(models.TextChoices): CAR = 'C' TRUCK = 'T' JET_SKI = 'J' DEFAULT = 'C'
With enum.unique()
not enforced, this will create 3 entries (not 4) and make the single CAR
entry instance available through either Vehicle.CAR
or Vehicle.DEFAULT
. By enforcing enum.unique()
, we cause an exception to be raised at DEFAULT = 'C'
instead of making an alias to Vehicle.CAR
, and that appears to be purely a limitation and not a benefit.
Change History (3)
comment:1 by , 5 years ago
Cc: | added |
---|---|
Resolution: | → wontfix |
Status: | new → closed |
Summary: | Choice enumeration types should not enforce enum.unique(). It does not mean what it seems like it should mean. → Choice enumeration types should not enforce enum.unique(). |
Type: | Bug → New feature |
comment:2 by , 5 years ago
Makes sense. Thanks for explaining the decision in your response, @felixxm
comment:3 by , 5 years ago
Hi Steve,
As Felix says, we're using enums under the hood, but we've added some additional constraints on top.
These helper classes are intended to make working with field choices easier and more structured.
I see the following problems with allowing duplicate values:
- It is most likely not intended, e.g. a copy-paste error.
- Where we use display labels, it may be unclear that multiple entries refer to the same value.
- Following your example, when we load the value back from the database, is it "Default" or "Car"?
This is why we decided to enforce unique values. There is nothing to stop someone from doing things as they did before, i.e. not using Choices
.
For your example of a default case, I'd suggest that the blank value is the default, e.g. set __empty__ = _('(Default)')
.
That way you can change the default easily without needing to make a new migration.
Alternatively, if you need to enforce the value in the database, you can just set it in clean()
on your form or as the Field.default
.
I hope that helps.
Thanks for this report, however I don't think that it's the desired behavior. All properties (
.names
,.labels
,.choices
,.names
) will return only the first value without enforcing uniqueness, for example:What can be confusing. We made few design decisions to create the most usable and less error-prone classes for defining choices, IMO.
Choices
is not a strictenum
implementation.