Как использовать запрос в ModelForm в Django

Я хотел бы сделать запрос, где текущий пользователь используется как фильтр в ModelForm:

class BookSubmitForm(ModelForm):
    book = forms.ModelChoiceField(queryset=Book.objects.filter(owner=request.user),)
...

Проводит ли Django запрос в форму? Это хорошая практика? Как я могу использовать запрос? (конечно, запрос имени не определен)

Edit:

Я попробовал другое решение, которое должно вызвать форму в представлении, передав ей запрос:

form = BookSubmitForm(request)

а затем в форме я использую это:

class BookSubmitForm(ModelForm):
    def __init__(self, request, *args, **kwargs):
        super(BookSubmitForm, self).__init__(*args, **kwargs)
        self.fields["library"].queryset = Library.objects.filter(owner=request.user)

Он работает, и код находится в форме. Теперь я не уверен, что это лучшее решение, можно ли улучшить его?

Ответы

Ответ 1

Нет, запрос не передается в ModelForm. Вам нужно сделать что-то вроде этого на ваш взгляд:

form = BookSubmitForm()
form.fields['book'].queryset = Book.objects.filter(owner=request.user)
# pass form to template, etc

Как вы сказали, часто бывает проще инкапсулировать это в объекте Form, особенно если у вас есть несколько полей, которые потребуют отфильтрованных запросов. Чтобы сделать это, переопределите формы __init__() и пусть он принимает значение kwarg request:

class BookSubmitForm(ModelForm):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request")
        super(BookSubmitForm, self).__init__(*args, **kwargs)
        self.fields["book"].queryset = Book.objects.filter(owner=self.request.user)
        self.fields["whatever"].queryset = WhateverModel.objects.filter(user=self.request.user)

Затем просто передайте запрос всякий раз, когда вы создаете BookSubmitForm в своем представлении:

def book_submit(request):
    if request.method == "POST":
        form = BookSubmitForm(request.POST, request=request)
        # do whatever
    else:
        form = BookSubmitForm(request=request)
    # render form, etc

Ответ 2

Расширение ответа AdamKG на представления на основе классов - переопределите метод get_form_kwargs:

class PassRequestToFormViewMixin:
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs

from django.views.generic.edit import CreateView
class BookSubmitCreateView(PassRequestToFormViewMixin, CreateView):
    form_class = BookSubmitForm
# same for EditView

а затем в формах:

from django.forms import ModelForm
class BookSubmitForm(ModelForm):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request")
        super().__init__(*args, **kwargs)
        ...