Django FormView с динамическими формами - PullRequest
1 голос
/ 02 мая 2019

Ниже я создал FormView, который будет динамически возвращать класс формы в зависимости от того, на каком этапе процесса находится пользователь. У меня возникли проблемы с методом get_form.Он возвращает правильный класс формы в запросе get, но почтовый запрос не работает.

tournament_form_dict = {
    '1':TournamentCreationForm,
    '2':TournamentDateForm,
    '3':TournamentTimeForm,
    '4':TournamentLocationForm,
    '5':TournamentRestrictionForm,
    '6':TournamentSectionForm,
    '7':TournamentSectionRestrictionForm,
    '8':TournamentSectionRoundForm,}

class CreateTournament(FormView):
    template_name = 'events/create_tournament_step.html'

    def __init__(self, *args, **kwargs):
        form_class = self.get_form()
        success_url = self.get_success_url()
        super(CreateTournament, self).__init__(*args, **kwargs)

    def get_form(self, **kwargs):
        if 'step' not in kwargs:
             step = '1'
        else:
             step = kwargs['step']
        return tournament_form_dict[step]

    def get_success_url(self, **kwargs):
        if 'step' not in kwargs:
            step = 1
        else:
            step = int(kwargs['step'])
        step += 1
        if 'record_id' not in kwargs:
            record_id = 0
        else:
            record_id = int(kwargs['record_id'])
        return 'events/tournaments/create/%d/%d/' % (record_id, step)

Сбой почтового запроса в django\views\generic\edit.py в строке get_form, что я понимаю, потому чтоЯ переписал его в своем FormView:

def post(self, request, *args, **kwargs):
    """
    Handle POST requests: instantiate a form instance with the passed
    POST variables and then check if it's valid.
    """
    form = self.get_form()
    if form.is_valid(): …
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

Однако, когда я изменяю имя моего пользовательского get_form метода на gen_form, примерно так:

def __init__(self, *args, **kwargs):
    form_class = self.gen_form()
    success_url = self.get_success_url()
    super(CreateTournament, self).__init__(*args, **kwargs)

def gen_form(self, **kwargs):
    if 'step' not in kwargs:
        step = '1'
    else:
        step = kwargs['step']
    return tournament_form_dict[step]

мой класс формы не обрабатывается в запросе get и оценивается как None.Я ломаю голову над тем, почему, когда я перезаписываю метод get_form, он работает, а мой собственный именованный метод - нет?Кто-нибудь знает, что это за недостаток?

1 Ответ

1 голос
/ 02 мая 2019

Джанго FormMixin [Джанго-док] определяет get_form функцию [Джанго-док] .Таким образом, здесь вы в основном подклассифицировали FormView и «исправили» метод get_form.

Ваша попытка с gen_form не работает, так как вы определили только локальные переменные, итаким образом, не имеет большого значения в любом случае, только вызов super(..) будет иметь некоторые побочные эффекты.Другие команды будут некоторое время держать процессор занятым, но в конце будут назначать ссылку только на вызовы Form на переменную form_class, но, поскольку она локальная, вы ее выбросите.

При этом ваша функция содержит некоторые ошибки.Например, **kwargs обычно будет содержать максимум один параметр: form_class.Так что step s не сделают много.Вы можете получить доступ к параметрам URL через self.args и self.kwargs, а параметры строки запроса через self.request.GET.Кроме того, вы, вероятно, все равно захотите пропатчить функцию get_form_class , поскольку вы возвращаете ссылку на класс, а не, насколько я понимаю, ссылку на инициализированную форму.

Построение URL с помощью обработки строк, вероятно, также не является хорошей идеей, поскольку, если вы (немного) измените шаблон URL, то, скорее всего, вы забудете заменить success_url, и, следовательно, вы будете ссылатьсяна путь, который больше не существует.Использование функции reverse является более безопасным способом, поскольку вы передаете имя представления и параметры, а затем эта функция «вычислит» правильный URL-адрес.По сути, это механизм, стоящий за тегом шаблона {% url ... %} в шаблонах Django.

Таким образом, лучший подход:

from django.urls import reverse

class CreateTournament(FormView):
    template_name = 'events/create_tournament_step.html'

    def <b>get_form_class</b>(self):
        return tournament_form_dict[<b>self.kwargs.get('step', '1')</b>]

    def get_success_url(self):
        new_step = int(self.kwargs.get('step', 1)) + 1
        # use a reverse
        return <b>reverse(</b>'name_of_view', kwargs={'step': new_step}<b>)</b>
...