[Django] #33714: Better admin support for ArrayFields where the base_field has choices

96 views
Skip to first unread message

Django

unread,
May 17, 2022, 10:17:26 AM5/17/22
to django-...@googlegroups.com
#33714: Better admin support for ArrayFields where the base_field has choices
-----------------------------------------+------------------------
Reporter: Jaap Roes | Owner: nobody
Type: New feature | Status: new
Component: contrib.admin | Version: dev
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-----------------------------------------+------------------------
Currently the admin doesn't really work well when registering a model that
has a ArrayField of which the base_field has choices e.g.:

{{{
class Post(model.Model):
category = ArrayField(
models.CharField(choices=[
('FASHION', 'Fashion'),
('STYLE', 'Style'),
('SPORTS', 'Sports'),
('FUN', 'Fun'),
], max_length=8),
size=2,
blank=True,
default=list
)
}}}

For example, the edit form uses a simple text input to edit the choices
instead of a `MultipleChoiceField`. Adding the field to `list_display`
will show the raw values, not the display names. Adding the field to
`list_filter` will only show filter options of combinations used in the
database (stringified arrays).

--
Ticket URL: <https://code.djangoproject.com/ticket/33714>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
May 17, 2022, 10:54:03 AM5/17/22
to django-...@googlegroups.com
#33714: Better admin support for ArrayFields where the base_field has choices
-------------------------------+--------------------------------------

Reporter: Jaap Roes | Owner: nobody
Type: New feature | Status: new
Component: contrib.admin | Version: dev
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

Comment (by Jaap Roes):

We have some workarounds in place to make it work in our projects.

Instead of `ArrayField` we use:

{{{
from django import forms
from django.contrib.postgres.fields import ArrayField


class ChoiceArrayField(ArrayField):
def formfield(self, **kwargs):
defaults = {
"form_class": forms.MultipleChoiceField,
"choices": self.base_field.choices,
**kwargs,
}

# Bypass the ArrayField's formfield, because we don't want it to
pass the unexpected
# base_field to our selected form_class.
return super(ArrayField, self).formfield(**defaults)
}}}

For list filters we use:

{{{
class ChoiceArrayFieldListFilter(admin.SimpleListFilter):
field_name = NotImplemented # Set by subclasses
(ChoiceArrayFieldListFilter.for_field)

def __init__(self, request, params, model, model_admin):
field = model._meta.get_field(self.field_name)
self.parameter_name = field.name
self.title = field.verbose_name
self._choices = field.base_field.choices
super().__init__(request, params, model, model_admin)

def lookups(self, request, model_admin):
return self._choices

def queryset(self, request, queryset):
if value := self.value():
queryset = queryset.filter(**{
f'{self.field_name}__contains': [value]
})
return queryset

@classmethod
def for_field(cls, field_name):
return type(f'{field_name.title()}ListFilter',
(ChoiceArrayFieldListFilter,), {
'field_name': field_name
})
}}}

and for list display purposes we define methods on the admin class that
call this little helper function:

{{{
def _get_array_field_display(obj, field_name):
field = obj._meta.get_field(field_name)
choice_lookup = dict(field.base_field.flatchoices)
return "; ".join(str(choice_lookup.get(value)) for value in
getattr(obj, field_name))
}}}

It would be nice if we can get rid of these workarounds and have this
working in Django Admin without any extra code.

--
Ticket URL: <https://code.djangoproject.com/ticket/33714#comment:1>

Django

unread,
May 17, 2022, 11:47:37 AM5/17/22
to django-...@googlegroups.com
#33714: Better admin support for ArrayFields where the base_field has choices
-------------------------------+--------------------------------------
Reporter: Jaap Roes | Owner: nobody
Type: New feature | Status: closed
Component: contrib.admin | Version: dev
Severity: Normal | Resolution: duplicate

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => duplicate


Comment:

I think we can treat this as a duplicate of #32328.

--
Ticket URL: <https://code.djangoproject.com/ticket/33714#comment:2>

Django

unread,
Jun 2, 2022, 8:55:05 AM6/2/22
to django-...@googlegroups.com
#33714: Better admin support for ArrayFields where the base_field has choices
-------------------------------+--------------------------------------
Reporter: Jaap Roes | Owner: nobody
Type: New feature | Status: closed
Component: contrib.admin | Version: dev
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

Comment (by Jaap Roes):

I don't agree that this is a duplicate. This is about a much narrower case
where an ArrayField is used to wrap another field with choices. Basically
using the ArrayField as a M2M where the "other" side is a fixed set of
options, instead of a database table. The most similar ticket I can find
is #24858, which has been resolved but for a much more esoteric case
(imho) where the ArrayField itself has choices.

--
Ticket URL: <https://code.djangoproject.com/ticket/33714#comment:3>

Django

unread,
Jun 2, 2022, 11:04:59 AM6/2/22
to django-...@googlegroups.com
#33714: Better admin support for ArrayFields where the base_field has choices
-------------------------------+--------------------------------------
Reporter: Jaap Roes | Owner: nobody
Type: New feature | Status: closed
Component: contrib.admin | Version: dev
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

Comment (by Mariusz Felisiak):

Replying to [comment:3 Jaap Roes]:


> I don't agree that this is a duplicate. This is about a much narrower
case where an ArrayField is used to wrap another field with choices.
Basically using the ArrayField as a M2M where the "other" side is a fixed
set of options, instead of a database table. The most similar ticket I
can find is #24858, which has been resolved but for a much more esoteric
case (imho) where the ArrayField itself has choices.

My understanding is that we could have a better widget. I don't think it's
worth improving only this rather niche case.

--
Ticket URL: <https://code.djangoproject.com/ticket/33714#comment:4>

Reply all
Reply to author
Forward
0 new messages