Поле ModelChoiceField
Поле ModelChoiceField предназначено для создания выпадающего списка, где каждый вариант представляет собой объект модели. Оно принимает аргумент queryset - набор объектов, из которых пользователь может выбрать один. Это поле автоматически валидирует переданные данные, проверяя наличие выбранного объекта в указанном наборе запросов. При отправке формы значение поля преобразуется в объект модели, а не в его первичный ключ.
Синтаксис
from django import forms
from .models import Category
class MyForm(forms.Form):
category = forms.ModelChoiceField(queryset=Category.objects.all())
Параметры
Основной параметр - queryset, задающий набор объектов для выбора. Дополнительные параметры включают empty_label для добавления пустого пункта, to_field_name для указания поля модели, используемого в качестве значения, и стандартные параметры полей форм (например, required, initial, label).
Пример . Использование в форме
Создадим форму для выбора категории статьи с помощью ModelChoiceField:
from django import forms
from .models import Category, Article
class ArticleForm(forms.Form):
title = forms.CharField(max_length=100)
content = forms.CharField(widget=forms.Textarea)
category = forms.ModelChoiceField(queryset=Category.objects.all())
При рендеринге форма создаст выпадающий список со всеми категориями из базы данных. После отправки формы значение поля category будет объектом модели Category, а не его ID.
Пример . Обработка данных
Рассмотрим обработку данных из формы с ModelChoiceField в представлении:
from django.shortcuts import render
from .forms import ArticleForm
def create_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
content = form.cleaned_data['content']
category = form.cleaned_data['category']
# category - объект Category
print(f"Title: {title}")
print(f"Category: {category.name}")
else:
form = ArticleForm()
return render(request, 'create_article.html', {'form': form})
Валидация поля выполняется автоматически: если выбранный объект не существует в queryset, будет вызвана ошибка валидации.
Фильтрация queryset
Используйте метод filter, чтобы динамически ограничивать набор доступных объектов:
from django import forms
from .models import Article, Category
class ArticleForm(forms.Form):
title = forms.CharField(max_length=100)
category = forms.ModelChoiceField(
queryset=Category.objects.filter(is_active=True)
)
В этом примере в выпадающем списке отобразятся только активные категории.
Пустой пункт в выпадающем списке
Используйте параметр empty_label для добавления пустого пункта:
from django import forms
from .models import Category
class CategoryForm(forms.Form):
category = forms.ModelChoiceField(
queryset=Category.objects.all(),
empty_label="Выберите категорию"
)
Если установить empty_label в None, пустой пункт не будет отображаться. При значении required=False выбор пустого пункта допустим, и поле вернет None.
Использование to_field_name
Параметр to_field_name позволяет указать поле модели, которое будет использоваться в качестве значения выпадающего списка:
from django import forms
from .models import Article
class ArticleForm(forms.Form):
article = forms.ModelChoiceField(
queryset=Article.objects.all(),
to_field_name="slug"
)
Теперь значениями в выпадающем списке будут не первичные ключи, а значения поля slug модели Article.
Динамическая настройка queryset
Для динамической фильтрации queryset в зависимости от пользователя или других условий переопределите метод __init__ формы:
from django import forms
from .models import Category
class ArticleForm(forms.Form):
title = forms.CharField(max_length=100)
category = forms.ModelChoiceField(queryset=Category.objects.all())
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].queryset = Category.objects.filter(
author=user
)
В этом случае доступные категории будут зависеть от переданного пользователя.
Результат валидации
Если пользователь выберет несуществующий объект, поле вызовет ошибку ValidationError. Форма будет содержать ошибку в поле category:
from django import forms
from .models import Category
form = CategoryForm({'category': 999}) # Несуществующий ID
if not form.is_valid():
print(form.errors['category'])
Результат выполнения кода:
"Select a valid choice. 999 is not one of the available choices."
Смотрите также
-
класс
Form,
основной класс для создания форм -
класс
ModelForm,
форма, связанная с моделью базы данных -
поле
ChoiceField,
выбор из фиксированного списка вариантов -
поле
ModelMultipleChoiceField,
выбор нескольких объектов модели