Skip to content

Instantly share code, notes, and snippets.

@cwurld
Last active April 21, 2016 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwurld/f77e69598451404f30bacc46005a0a75 to your computer and use it in GitHub Desktop.
Save cwurld/f77e69598451404f30bacc46005a0a75 to your computer and use it in GitHub Desktop.
django and select2
'''
I have a model for customer intake. One of the fields is for tracking how the customer heard about us. I do
not want an endless proliferation of values, so I would like to use a multi-select. The problem is I also want the
user to add new choices as needed. It turns out this is possible with the Select2 widget:
https://select2.github.io/examples.html#tokenizer - check out this link to see how to setup your javascript.
It turns out this is a little tricky to implement. Below is a mixin you can use with a form to handle the field.
Also, if you are using bootstrap, you will want: https://fk.github.io/select2-bootstrap-css/
'''
class Intake(TimeStampedModel):
referral = models.CharField(max_length=1000, blank=True) # save as json encoded list
@classmethod
def get_referral_choices(cls):
"""
:return: a set of referal choices
"""
cut_off = datetime.datetime.now() - datetime.timedelta(200)
all_db_values = cls.objects.filter(created__gt=cut_off).values_list('referral', flat=True)
choice_set = {'Google', 'Bing'}
for v in all_db_values:
if v:
choices = json.loads(v)
choice_set.update(choices)
return choice_set
class ReferralFieldMixin(object):
def __init__(self, *args, **kwargs):
super(ReferralFieldMixin, self).__init__(*args, **kwargs)
self.fields['referral'].widget.attrs.update({'class': 'select2-tokenizer'})
self.fields['referral'].help_text = 'To create a new choice, type it followed by a space.'
referral_choices_set = set(models.Intake.get_referral_choices())
if self.initial and self.initial.get('referral'):
self.initial['referral'] = json.loads(self.initial['referral'])
referral_choices_set.update(self.initial['referral'])
if 'data' in kwargs and kwargs['data'].get('referral'):
# kwargs['data'] needs to be converted to a normal dict to get the referral field as a list
referral_choices_set.update(dict(kwargs['data'])['referral'])
referral_choices = sorted(list(referral_choices_set))
self.fields['referral'].choices = [[x, x] for x in referral_choices]
def clean_referral(self):
referral = map(methodcaller('capitalize'), self.cleaned_data['referral'])
return json.dumps(referral)
class IntakeForm(ReferralFieldMixin, forms.ModelForm):
referral = forms.MultipleChoiceField(required=False)
class Meta:
model = models.Intake
fields = ['referral']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment