'Django-admin: show multi select field for JSONField

I have a model with a field channel (JSONField). I'm strong an array of string in db with channel. By default, a JSONField is shown as a textarea in django-admin. My goal is to somehow make channel a multi-select field that later converts to like this ["APP", "WEB"].

models.py

@dataclass
class ChannelTypes:
    WEB: str = 'WEB'
    APP: str = 'APP'

class DiscountRule(models.Model):
    ...
    channel = models.JSONField(null=False, blank=False, default=list(astuple(ChannelTypes())))

My Approach: In forms.py, add custom fields (boolean) that only show up in admin form and are not stored in db. Something like this:

class RuleAdminForm(forms.ModelForm):
    WEB = forms.BooleanField(required=False)
    APP = forms.BooleanField(required=False)

Similarly, admin.py will populate the custom fields like this:

def get_form(self, request, obj=None, *args, **kwargs):
    form = super(BaseDiscountRuleAdmin, self).get_form(request, *args, **kwargs)
    for i in obj.channel:
        form.base_fields[i].initial = True
    return form

But this causes a problem that the custom field value persists after updating 1-2 times due to using base_fields[field_name].initial.

Ideas for goal: Multi select option 1



Solution 1:[1]

You can attach to admin class custom form

class DiscountRuleAdmin(admin.ModelAdmin):
    form = DiscountRuleForm

and forms.py

class DiscountRuleForm(forms.ModelForm):
    channel = forms.MultipleChoiceField(
        widget=FilteredSelectMultiple('channels', False),
        required=False,
    )

class Meta:
    model = DiscountRule
    fields = '__all__'

And play around it

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 bandirom