Reputation: 739
I am working on a Django form that let's you order customs pizzas. When building the form to "Select Size" for instance, I want to pull from a database that has my menu item's available sizes in it, so that if the menu changes, the form will automatically know what sizes are available.
Right now I am having an issue with how the query set is returned as it shows up.
How should I alter the code such that
queryset=query_list.values_list('size').distinct()
shows up in the drop down as: Small, Medium
and not: (Small,), (Medium,)
Or is there maybe a way to pull directly from the SIZE_CHOICES tuple in the class?
Thank you!
Models.py:
class Pizza(MenuItem):
STYLE_CHOICES = (
('Regular', 'Regular'),
('Sicilian', 'Sicilian'),
)
SIZE_CHOICES = (
('Small', 'Small'),
('Large', 'Large'),
)
style = models.CharField(max_length=16, blank=False, choices=STYLE_CHOICES)
size = models.CharField(max_length=16, blank=False, choices=SIZE_CHOICES)
num_toppings = models.IntegerField()
toppings = models.ManyToManyField(Topping, blank=True)
is_special = models.BooleanField(default=False)
def toppings_list(self):
return "\n".join([p.name for p in self.toppings.all()])
def __str__(self):
return f"{self.style} {self.size}"
forms.py
class PizzaForm(forms.Form):
query_list = Pizza.objects.all()
style = forms.ModelChoiceField(
widget=forms.Select,
queryset=query_list,
empty_label="Select Size"
)
size_choices = forms.ModelChoiceField(
widget=forms.Select,
queryset=query_list.values_list('size').distinct(),
empty_label="Select Size"
)
topping_choices = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Topping.objects.all(),
required=False
)
Upvotes: 2
Views: 5121
Reputation: 32294
Anyone looking to create a choice field for a non-ModelForm where the choices come dynamically from a queryset but are not model instances, you can pass a callable to the choices
parameter on a ChoiceField
def _make_choices():
return [(c, c) for c in queryset.values_list('field', flat=True)]
choice_field = forms.ChoiceField(choices=_make_choices)
A Willem said, a ModelForm is the way to go for this problem.
Upvotes: 2
Reputation: 477607
This is not a ModelChoiceField
[Django-doc], since you do not select a model object, but a value. You thus can use a ChoiceField
[Django-doc], and import the choices from the model:
class PizzaForm(forms.Form):
style = forms.ChoiceField(
widget=forms.Select,
choices=Pizza.STYLE_CHOICES,
empty_label="Select Size"
)
size_choices = forms.ChoiceField(
widget=forms.Select,
choices=Pizza.SIZE_CHOICES,
empty_label="Select Size"
)
topping_choices = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Topping.objects.all(),
required=False
)
That being said, you might want to look into a ModelForm
[Django-doc]. This can automatically construct a form based on a model, and furthermore remove a lot of boilerplate code to save/update a Pizza
object in the database.
Upvotes: 2