| 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) |
Marakai
commented
Nov 7, 2016
|
Bless you! after slamming my head against a wall for nearly an entire day, your snippet gave me a breakthrough! Now, if you could add an example of using it with a field widget you found useful, this here backend guy thrown into doing frontend code would be eternally grateful! |
aniruddha-adhikary
commented
Nov 9, 2016
|
Thanks a lot @danni! You're the hero. |
Proper-Job
commented
Feb 28, 2017
|
@danni That's kind of problematic with the base_field being anything but a CharField. Wouldn't it be better to use a TypedMultipleChoiceField thus? def formfield(self, **kwargs):
defaults = {
'form_class': forms.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(ArrayField, self).formfield(**defaults) |
Proper-Job
commented
Mar 30, 2017
|
Actually starting on Django > 1.10.2 the custom field also needs a custom widget like below. Otherwise an empty selection won't be written back to the model. from django import forms
from django.contrib.postgres.fields import ArrayField
from django.forms import SelectMultiple
class ArraySelectMultiple(SelectMultiple):
def value_omitted_from_data(self, data, files, name):
return False
class ChoiceArrayField(ArrayField):
def formfield(self, **kwargs):
defaults = {
'form_class': forms.TypedMultipleChoiceField,
'choices': self.base_field.choices,
'coerce': self.base_field.to_python,
'widget': ArraySelectMultiple
}
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)
|
kholidfu
commented
Apr 13, 2017
•
|
Hi @danni, @Proper-Job Using Django 1.11, this is what I have:
I've succeeded entering the data (checked via Any ideas? |
ropable commentedOct 3, 2016
Excellent snippet, thanks!