Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better ArrayField admin widget?

Is there any way to make ArrayField's admin widget allow adding and deleting objects? It seems that by default, it is instead displayed just a text field, and uses comma separation for its values.

Besides being inconvenient, AFAICT in the case the base field of the array is a Char/TextField, this doesn't allow any way of including commas in any of the texts in the array.

like image 978
Danra Avatar asked Jul 15 '15 09:07

Danra


3 Answers

I take no credit for this (original source), but if you are using PostgreSQL as the database and are happy to use the Postgres-specific ArrayField implementation there is an even easier option: subclass ArrayField on the model and override the default admin widget. A basic implementation follows (tested in Django 1.9, 1.10, 1.11, 2.0, 2.1 & 2.2):

models.py

from django import forms
from django.db import models
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 our parent's formfield implementation completely as we don't
        # care for it.
        # pylint:disable=bad-super-call
        return super(ArrayField, self).formfield(**defaults)


FUNCTION_CHOICES = (
    ('0', 'Planning'),
    ('1', 'Operation'),
    ('2', 'Reporting'),
)


class FunctionModel(models.Model):
    name = models.CharField(max_length=128, unique=True)
    function = ChoiceArrayField(
        base_field=models.CharField(max_length=256, choices=FUNCTION_CHOICES),
        default=list)
like image 96
ropable Avatar answered Nov 08 '22 19:11

ropable


For OP, or anyone out there looking, between these helpful bits you should be good to go:

  • 1. Extending SelectMultiple or CheckboxSelectMultiple widget to parse arrayfield and
  • 2. Creating or extending admin form to display the arrayfield using the widget above
like image 14
Tariq W. Avatar answered Nov 08 '22 20:11

Tariq W.


This is a better version of an already accepted solution. Using "CheckboxSelectMultiple" makes it more usable in the admin page.

class ChoiceArrayField(ArrayField):

    def formfield(self, **kwargs):
        defaults = {
            'form_class': forms.TypedMultipleChoiceField,
            'choices': self.base_field.choices,
            'coerce': self.base_field.to_python,
            'widget': forms.CheckboxSelectMultiple,
        }
        defaults.update(kwargs)

        return super(ArrayField, self).formfield(**defaults)
like image 8
Halnode Technologies Avatar answered Nov 08 '22 19:11

Halnode Technologies