具有动态表单的 Django FormView

Django FormView with dynamic forms

我创建了下面的 FormView,它将根据用户所处流程的哪个步骤动态 return 表单 class。我在使用 get_form 时遇到了问题方法。它 return 是 get 请求中 class 的正确形式,但 post 请求无效。

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)

post 请求在 get_form 行的 django\views\generic\edit.py 处失败,我意识到这是因为我在我的 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]

我的表单 class 未在 get 请求中得到处理,计算结果为 None。我绞尽脑汁想知道为什么当我重写 get_form 方法时它有效,但我自己命名的方法却不起作用?有谁知道这个缺陷可能是什么?

Django 的 FormMixin [Django-doc] defines a get_form function [Django-doc]。因此,您在这里基本上是 class 子 FormView 和 "patched" get_form 方法。

你对 gen_form 的尝试不起作用,因为你只定义了 local 变量,因此无论如何都没有太大区别,只有 super(..) 调用会有一些副作用。其他命令将使 CPU 忙一段时间,但最后只会将引用分配给 Formform_class 变量的调用,但由于它是本地的,你会扔掉的。

也就是说,您的函数包含一些错误。例如 **kwargs 通常包含 至多 一个参数:form_class。所以 steps 不会做太多。您可以通过 self.argsself.kwargs 访问 URL 参数,通过 self.request.GET 访问查询字符串参数。此外,您可能想要修补 get_form_class function,因为您 return 是对 class 的引用,而不是,据我所知,是对初始化表单的引用。

通过字符串处理构造 URLs 可能也不是一个好主意,因为如果您(稍微)更改 URL 模式,那么您很可能会忘记替换 success_url,因此您将引用不再存在的路径。使用 reverse function 是一种更安全的方法,因为您传递了视图的名称和参数,然后此函数将 "calculate" 正确 URL。这基本上就是 Django 模板中 {% url ... %} 模板标签背后的机制。

更好的方法是:

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>