Как реализовать несколько чекбоксов в форме Django?
Мне дали задание создать сайт рецептов. Пользователь может добавить рецепт. Он должен выбрать категорию (категории). Один рецепт может относиться как к одной категории, так и к нескольким. Я наследую свою форму от ModelForm. Вот код для нее:
class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ['title', 'description', 'ingredients', 'cooking_steps', 'time', 'calories', 'portions', 'image', 'categories']
widgets = {
'title' : TextInput(attrs={'class' : 'create_recipe_title', 'placeholder' : 'Enter a title...' }),
'description' : TextInput(attrs={'class' : 'create_recipe_description', 'placeholder' : 'Enter a short description...' }),
'ingredients' : Textarea(attrs={'class' : 'create_recipe_ingredients', 'placeholder' : 'Your ingredients...', 'disabled' : True }),
'time' : NumberInput(attrs={'class' : 'create_recipe_time', 'placeholder' : 'Cooking time...' }),
'calories' : NumberInput(attrs={'class' : 'create_recipe_calories', 'placeholder' : 'Calories...' }),
'portions' : NumberInput(attrs={'class' : 'create_recipe_portions', 'placeholder' : 'Portions...' }),
'image' : FileInput(attrs={'class' : 'create_recipe_image'}),
'cooking_steps' : Textarea(attrs={'class' : 'create_recipe_cooking_steps', 'placeholder' : 'Describe the cooking process...' }),
'categories' : SelectMultiple(choices=[(1, 'Food'), (2, 'Drinks'), (3, 'Hot'), (4, 'Cold'), (5, 'Breakfast'), (6, 'Lunch'), (7, 'Dinner'), (8, 'Выпечка и десерты'), (9, 'Soups'), (10, 'Salads'), (11, 'Pizza and pasta'), (12, 'Sauces'),(13, 'Portugal'), (14, 'Italy'), (15, 'France'), (16, 'Japan'), (17, 'Chine'), (18, 'Georgia'), (19, 'Armenia'), (20, 'Mexico'), (21, 'Africa'), (22, 'Dietary'), (23, 'Sugar free'), (24, 'Gluten and lactose free')])
}
Однако это работает не так. Он вообще не показывает никаких флажков. Я уверен, что все остальное я делаю правильно. Но в любом случае, код для моей модели:
class Recipe(Model):
title = CharField(max_length=20)
description = CharField(max_length=100)
ingredients = CharField(max_length=200)
cooking_steps = CharField(max_length=2000)
time = IntegerField()
calories = IntegerField()
portions = IntegerField()
image = ImageField(upload_to='static/recipes_photos')
author = ForeignKey(User, on_delete=CASCADE)
rating = IntegerField(default=0)
categories = ManyToManyField(Category, blank=False)
created = DateField(auto_now_add=True)
last_updated = DateField(auto_now_add=True)
saved_by = ManyToManyField(User, related_name='recipe_saved_by')
left_reaction = ManyToManyField(User, related_name='recipe_left_reaction')
recipes = RecipeManager()
objects = Manager()
и мое мнение:
class AddRecipe(View):
template_name = 'myapp/addrecipe.html'
def get(self, request):
context = {'add_recipe_form' : RecipeForm(),
'add_ingredient_form' : IngredientForm()}
return render(request, self.template_name, context=context)
def post(self, request):
form = ArticleForm(request.POST)
if form.is_valid():
recipe = form.save(commit=False)
recipe.author = request.user
recipe.save()
return redirect('recipe', recipe.pk)
context = {'add_article_form' : form}
return render(request, self.template_name , context=context)
Вот мой код шаблона:
<div class='right'>
{{ add_recipe_form.cooking_steps }}
{{ add_recipe_form.image }}
{{ add_recipe_form.categories }}
</div>
</form>
А что я вижу в сети:
Что я делаю не так?
Это потому, что вы используете ModelForm
, а это устанавливает поле категорий следующим образом:
categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all())
Таким образом, если у вас нет Category
записей, QuerySet пуст и варианты выбора тоже.
С другой стороны, ваша ошибка заключается в попытке переопределить значения на уровне виджета, в то время как поле остается нетронутым. Вы хотите переопределить само поле:
class RecipeForm(forms.ModelForm):
categories = forms.MultipleChoiceField(
choices=[
(1, "Food"),
(2, "Drinks"),
(3, "Hot"),
(4, "Cold"),
(5, "Breakfast"),
(6, "Lunch"),
(7, "Dinner"),
(8, "Выпечка и десерты"),
(9, "Soups"),
(10, "Salads"),
(11, "Pizza and pasta"),
(12, "Sauces"),
(13, "Portugal"),
(14, "Italy"),
(15, "France"),
(16, "Japan"),
(17, "Chine"),
(18, "Georgia"),
(19, "Armenia"),
(20, "Mexico"),
(21, "Africa"),
(22, "Dietary"),
(23, "Sugar free"),
(24, "Gluten and lactose free"),
]
)
class Meta:
model = Recipe
fields = [
...
]
widgets = {
...
}
Вам не нужно настраивать виджет categories
MultipleChoiceField, так как по умолчанию он имеет значение SelectMultiple
.
P.S.
Похоже, я пропустил часть вашего вопроса. Для преобразования в чекбоксы необходимо настроить виджеты:
class RecipeForm(forms.ModelForm):
categories = forms.MultipleChoiceField(
widget=forms.widgets.CheckboxSelectMultiple(),
choices=[...],
)
...