Skip to content

Instantly share code, notes, and snippets.

@danni
Created March 8, 2016 08:52
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save danni/f55c4ce19598b2b345ef to your computer and use it in GitHub Desktop.
Save danni/f55c4ce19598b2b345ef to your computer and use it in GitHub Desktop.
Multi Choice Django Array Field
from django import forms
from django.contrib.postgres.fields import ArrayField
class ChoiceArrayField(ArrayField):
"""
A field that allows us to store an array of choices.
Uses Django 1.9's postgres ArrayField
and a MultipleChoiceField for its formfield.
Usage:
choices = ChoiceArrayField(models.CharField(max_length=...,
choices=(...,)),
default=[...])
"""
def formfield(self, **kwargs):
defaults = {
'form_class': forms.MultipleChoiceField,
'choices': self.base_field.choices,
}
defaults.update(kwargs)
# Skip our parent's formfield implementation completely as we don't
# care for it.
# pylint:disable=bad-super-call
return super(ArrayField, self).formfield(**defaults)
@anyidea
Copy link

anyidea commented Aug 10, 2023

After combining all the previous answers, below works for me, Django 4.2, Python 3.11

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


class _TypedMultipleChoiceField(forms.TypedMultipleChoiceField):
    def __init__(self, *args, **kwargs):
        kwargs.pop("base_field", None)
        kwargs.pop("max_length", None)
        super().__init__(*args, **kwargs)


class ChoiceArrayField(ArrayField):
    """
    A field that allows us to store an array of choices.

    Uses Django 4.2's postgres ArrayField
    and a TypeMultipleChoiceField for its formfield.

    Usage:

        choices = ChoiceArrayField(
            models.CharField(max_length=..., choices=(...,)), blank=[...], default=[...]
        )
    """
    def formfield(self, **kwargs):
        defaults = {
            'form_class': _TypedMultipleChoiceField,
            'choices': self.base_field.choices,
            'coerce': self.base_field.to_python,
        }
        defaults.update(kwargs)
        # Skip our parent's formfield implementation completely as we don't care for it.
        # pylint:disable=bad-super-call
        return super().formfield(**defaults)

@andreasnuesslein
Copy link

Thanks everybody. using @anyidea 's solution. works nicely

@sam-ghosh
Copy link

Thanks this solution works very well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment