I know there isn’t
MultipleChoiceField for a Model, you can only use it on Forms.
Today I face an issue when analyzing a new project related with Multiple Choices.
I would like to have a field like a
choices with the option of multiple choice.
I solved this issue other times by creating a
CharField and managed the multiple choices in the form with a
forms.MultipleChoiceField and store the choices separated by commas.
In this project, due to configuration, I cannot do it as I mention above, I need to do it in the Models, and I prefer NOT to edit the Django admin form neither use forms. I need a Model Field with multiple choices option
- Have someone solved anything like this via Models ?
Maybe overriding some of the models function or using a custom widget… I don’t know, I’m kinda lost here.
I’m aware off simple choices, I would like to have something like:
class MODEL(models.Model): MY_CHOICES = ( ('a', 'Hola'), ('b', 'Hello'), ('c', 'Bonjour'), ('d', 'Boas'), ) ... ... my_field = models.CharField(max_length=1, choices=MY_CHOICES) ...
but with the capability of saving multiple choices not only 1 choice.
You need to think about how you are going to store the data at a database level. This will dictate your solution.
Presumably, you want a single column in a table that is storing multiple values. This will also force you to think about how you will serialize – for example, you can’t simply do comma separated if you need to store strings that might contain commas.
However, you are probably best off using a solution like django-multiselectfield
In case You are using Postgres consider using ArrayField.
from django.db import models from django.contrib.postgres.fields import ArrayField class WhateverModel(models.Model): WHATEVER_CHOICE = u'1' SAMPLE_CHOICES = ( (WHATEVER_CHOICE, u'one'), ) choices = ArrayField( models.CharField(choices=SAMPLE_CHOICES, max_length=2, blank=True, default=WHATEVER_CHOICE), )
From the two, https://pypi.python.org/pypi/django-select-multiple-field/ looks more well rounded and complete. It even has a nice set of unittests.
The problem I found is that it throws a Django 1.10 deprecation warning in the class that implements the model field.
I fixed this and sent a PR. The latest code, until they merge my PR (if they ever decide to hehe) is in my fork of the repo, here: https://github.com/matiasherranz/django-select-multiple-field
In Your Case, I used ManyToManyField
It Will be something like that:
class MY_CHOICES(models.Model) choice = models.CharField(max_length=154, unique=True) class MODEL(models.Model): ... ... my_field = models.ManyToManyField(MY_CHOICES)
So, now you can select multiple choices
If you want the widget to look like a text input and still be able to allow selecting several options from suggestions, you might be looking for Select2. There is also django-select2 that integrates it with Django Forms and Admin.
You can use an
IntegerField for the model and powers of two for the choices (a bitmap field). I’m not sure why Django doesn’t have this already built-in.
class MyModel(models.Model): A = 1 B = 2 C = 4 MY_CHOICES = ((A, "foo"), (B, "bar"), (C, "baz")) my_field = models.IntegerField(default=0) from functools import reduce class MyForm(forms.ModelForm): class Meta: model = MyModel # it can be set to required=True if needed my_multi_field = forms.TypedMultipleChoiceField( coerce=int, choices=MyModel.MY_CHOICES, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['my_multi_field'].initial = [ c for c, _ in MyModel.MY_CHOICES if self.instance.my_field & c ] def save(self, *args, **kwargs): self.instance.my_field = reduce( lambda x, y: x | y, self.cleaned_data.get('my_multi_field', ), 0) return super().save(*args, **kwargs)
It can be queried like this:
MyModel.objects.filter(my_field=MyModel.A | MyModel.C) to get all records with A and C set.
The easiest way I found (just I use eval() to convert string gotten from input to tuple to read again for form instance or other place)
This trick works very well
#model.py class ClassName(models.Model): field_name = models.CharField(max_length=100) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.field_name: self.field_name= eval(self.field_name) #form.py CHOICES = [('pi', 'PI'), ('ci', 'CI')] class ClassNameForm(forms.ModelForm): field_name = forms.MultipleChoiceField(choices=CHOICES) class Meta: model = ClassName fields = ['field_name',] #view.py def viewfunction(request, pk): ins = ClassName.objects.get(pk=pk) form = ClassNameForm(instance=ins) if request.method == 'POST': form = form (request.POST, instance=ins) if form.is_valid(): form.save() ...
from django.db import models class KarModel(models.Model): choose_gender = ( (True, 'Male'), (False, 'Female'), ) fullname= models.CharField(max_length=200) gender = models.BooleanField(default=True, choices=choose_gender) def __str__(self): return self.fullname
the simple way