#34388: Added support for direct usage of Choices classes on model fields
-------------------------------------+-------------------------------------
Reporter: T. Franzel | Owner: nobody
Type: New feature | Status: closed
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage:
| Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by T. Franzel):
I agree with having a single usage-pattern API, but is this really a fair
argument here, since this is not upheld on various occasions (for good
reason)? Here are a couple of examples:
{{{ #!python
FileField(upload_to='uploads/%Y/%m/%d/')
FileField(upload_to=lambda x,y: 'uploads/%Y/%m/%d/')
CharField(default='foo')
CharField(default=lambda: 'foo')
models.CharField(choices=[('cd', 'CD')])
models.CharField(choices=[('Audio', ('cd', 'CD')])
models.CharField(choices=FooChoices.choices)
models.CharField(choices=FooChoices) # too confusing?
}}}
Saying the lists need to go away for us to have `choices=FooChoices` is
imho a silly argument. Why not force every usage of `default` to be a
`lambda` for consistency’s sake? Same line of thought. The API provides
access at different abstraction levels for good reason. The "new way"
should be the preferred way, while allowing more fine grained control, if
the user so desires.
(If we loosen here then typing for choices goes from list of pairs
to list of pair OR Choices subclass, which I can imagine folk complaining
about.)
I don't see how this statement can be accurate given that it is already
more than `list[tuples]`. Due to category mode, it can also be
`list[tuple[tuple]]`. I don't see how `Union[..., ChoicesMeta]` adds any
more complexity or even uncertainty.
Explicit is better than implicit.
...
There should be one-- and preferably only one --obvious way to do
it.
Sorry, poor choice of words from me. The users intent is very explicit:
"Here is a class of Choices, use it on this field." There is no implicit
magic going on from a users perspective. Occam's Razor applies too,
because the shorter version is just as meaningful, thus the rest is just
an unexpected typing chore. And let's not pretend that appending
`.choices` is more obvious. I have seen numerous people who stumble
repeatedly over this in practice. Everyone who used `Choices` classes
before has seen a `fields.E005` error at least once.
If we were to engage in a transition to deprecate passing an
iterable of two items, and solely accept Choices classes, that would be n
annoying breaking change for many projects, with no good reason/added
value 😕
As for the reasons. List were there first. Then categories. Then `Choices`
were introduced. This is not even about adding a feature. This is merely
about connecting the existing facilities with 4 lines of low-impact code.
If that line of reasoning would be applied consistently, Django would
never get another new feature or improvement. Who would break a decade old
working feature, that can easily work alongside a more elegant version, on
purpose without a technical reason? And then reject the minor non-breaking
improvement based on the strange premise that there can only be one way? ?
I'm at a loss for words on that.
Let me make one more point. What was the point of the `Choices` class that
was introduced into Django? It was added a few versions back, but it was
not integrated at all. Why go through the trouble at all? Currently, it
adds very little utility over the `Enum` class itself. Why build a 100
feet bridge and right before "marriage" stop construction and decide this
is "complete enough". Pedestrians will have to jump the 3 feet gap,
otherwise people on bicycles will use it too. Yes, it looks that
ridiculous to me.
Please correct me if I'm wrong, but this class was meant to be used on
ModelFields/Forms. Please explain to me why we introduce a single-purpose
class and then actively prevent people from using it, as is, for its
designated purpose?
----
Disregard the rest if above text did not move you at all. No point in
reading further. Regarding retaining the reference and your GH comment:
Is this ever read? 🤔 On the ticket you say you what to access it
in 3rd-Party packages, so should it not be a public documented attribute
in that case?
No it is not read, but since Django is a framework meant to be extensible,
there is an argument to be made for things that are not directly used by
Django, but might be of utility downstream. private/public is a rather
academic discussion here. We need to use so many Django/DRF private
internals that this straw would certainly not break the camels back.
Essentially you want the field to maintain a reference to the
Choices class, so you can inspect it later, but in this case I'd think a
decorator in drf-spectacular adding the necessary annotation would be much
more coherent, than having Django maintain the (from it's POV) otherwise
idle reference.
We already do maintain a setting `ENUM_NAME_OVERRIDES` with an extra list
of choice sets to fix this issue. My point is, the user already has a
perfectly good model. Because you deem that this information irrelevant to
Django, the user has to replicate another list of (name,choices). This is
error-prone and violates single source of truth for no good reason. Since
we do have a fix, this is not a hill I want to die on. Just a wasted
opportunity I will point users to when asked again about this.
However, I would kindly ask you to reconsider point 1. Happy to amend the
PR and throw out point 2, if that is more acceptable.
--
Ticket URL: <https://code.djangoproject.com/ticket/34388#comment:5>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070186cb1b4b64-5151bd8e-70d1-4dfd-b11e-8d1449acc48e-000000%40eu-central-1.amazonses.com.