Подтвердить что ты не робот

Как динамически установить набор запросов для моделей .ModelChoiceField для подкласса forms.Form

Конструктор для forms.ModelChoiceField требует набора запросов. Я не знаю набор запросов до тех пор, пока не произойдет запрос. Дистиллированная:

# models.py
class Bar(models.model):
    text = models.TextField()

class Foo(models.Model):
    name = models.CharField()
    bar = models.ForeignKey(Bar)

# forms.py
class FooForm(forms.Form):
    name = forms.CharField()
    text = forms.CharField(widget=forms.TextArea)

    bar = forms.ModelChoiceField(queryset='??????')

Что я сейчас делаю:

# forms.py

def get_foo_form_class(bars_queryset):
    class FooForm(forms.Form):
        name = forms.CharField()
        text = forms.CharField(widget=forms.TextArea)

        bar = forms.ModelChoiceField(queryset=bars_queryset)

    return FooForm

Затем я могу вызвать его в представлении, используя аргументы, обработанные из url с urlconf, чтобы построить запрос и получить класс. Это похоже на неправильный способ сделать это. Есть ли установленный способ сделать это в django?

4b9b3361

Ответ 1

Отмените метод формы __init__ и установите там запрос.

class FooForm(forms.Form):
    bar = forms.ModelChoiceField(queryset=Bar.objects.none())

    def __init__(self, *args, **kwargs):
        qs = kwargs.pop('bars')
        super(FooForm, self).__init__(*args, **kwargs)
        self.fields['bar'].queryset = qs

Ответ 2

Вы также можете сделать это в своем представлении перед тем, как представить форму в шаблоне. Я использую это и считаю его более гибким, если вы повторно используете форму в других представлениях и каждый раз меняете запрос:

from assets.models import Asset
location_id = '123456'
edit_form = AsssetSelectForm(request.POST or None, instance=selected_asset)
edit_form.fields["asset"].queryset = Asset.objects.filter(location_id=location_id)

Я также установил для запроса по умолчанию значение none в form.py:

class AsssetSelectForm(forms.Form):
    asset = forms.ModelChoiceField(queryset=Asset.objects.none())