goinnn/django-multiselectfield

Recommend ArrayField for PostgreSQL users

Closed this issue · 2 comments

In the interest of the community, I would propose to add a recommendation to the README for PostgreSQL users to use the native django.contrib.postgres.fields.ArrayField instead of this module.

In my opinion this is advantageous from several perspectives:

  • It removes the need for an additional dependency
  • It is well documented in the official Django documentation
  • It enables to use different data types as child field (e.g. CharField(), IntegerField(), etc.)
  • It provides handy contains queries (no need to use __regex)
  • Works with DRF out of the box (no need to excplicitly declare MultipleChoiceField on the serializer)

If there are resons not to agree with the above, I would propose to make it clear in the README what advantages this package brings over Django's native ArrayField.

One further note, to get the Django Admin to display a multi-select form field in the UI, a custom field can be used to extend the ArrayField:

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's Postgres ArrayField
    and a MultipleChoiceField for its formfield.
    """

    def formfield(self, **kwargs):
        defaults = {
            'form_class': forms.MultipleChoiceField,
            'choices': self.base_field.choices,
        }
        defaults.update(kwargs)
        # Skip the parent's formfield implementation completely as it does not matter.
        return super(ArrayField, self).formfield(**defaults)  # pylint:disable=bad-super-call

@LukasKlement This is a fantastic solution when using Postgres, thanks! I'd been trying to use an array field without an extra dependency all day and didn't realize it could be this simple - and this clean. (I'm not particularly experienced with Django.)

Note for anyone wanting to use a different widget than the default multi-select list that forms.MultipleChoiceField uses, you can specify a default widget, too, for instance a checkbox multiselect:

...

class ChoiceArrayField(ArrayField):
    ...

    def formfield(self, **kwargs):
        defaults = {
            'form_class': forms.MultipleChoiceField,
            'choices': self.base_field.choices,
            'widget': forms.CheckboxSelectMultiple,
        }
        ...
blag commented

Correct. This project is a bit of a workaround for non-PostgreSQL users, and ArrayFields would probably be a cleaner solution for PostgreSQL users.