django Choice list (dynamic choices)

Viewed 1116

i have a choices list :

CATEGORY_CHOICES = (
("T-shirts", "T-shirts"),
("Hoodies", "Hoodies"),
("Shorts", "Shorts"),

)

but i want to make this list dynamic so i can add and delete choices ,i created a new model Category what i want to do is something like this :

CATEGORY_CHOICES = (
for choice in Category.object.all():
    (choice.category, "choice.category"),
 )

but it doesn't seems to work

1 Answers

In that case, you should not make use of a CharField or some other field with choices, but use a ForeignKey [Django-doc].

For example:

class Category(models.Model):
    category = models.CharField(max_length=128, unique=True)

    def __str__(self):
        return self.category

class MyModel(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

If you construct a ModelForm, it will use by default a ModelChoiceField [Django-doc], and the default widget is a dropdown with the Category options.

If you want to select multiple Categorys, you should use a ManyToManyField [Django-doc]:

class Category(models.Model):
    category = models.CharField(max_length=128, unique=True)

    def __str__(self):
        return self.category

class MyModel(models.Model):
    categories = models.ManyToManyField(Category)

In a filter, you can then use a ModelMultipleChoiceFilter [readthedocs]:

class MyModelFilter(django_filters.FilterSet):
    categories = django_filters.ModelMultipleChoiceFilter(
        queryset=Category.objects.all()
    )
    class Meta:
        model = MyModel
        fields = ['categories']

But normally, without specifying anything that is the default field it will use.

You can alter the widget to a CheckboxSelectMultiple [Django-doc] to work with a sequence of checkboxes:

class MyModelFilter(django_filters.FilterSet):
    categories = django_filters.ModelMultipleChoiceFilter(
        queryset=Category.objects.all(),
        widget=forms.CheckboxSelectMultiple()
    )
    class Meta:
        model = MyModel
        fields = ['categories']
Related