具有动态表单的Django FormView

时间:2019-05-02 17:12:05

标签: django python-3.x django-class-based-views

我在下面创建了FormView,它将根据用户所处过程的哪个步骤动态返回表单类。我在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) 方法上遇到了麻烦。它会在get请求中返回正确的表单类,但post请求无法正常工作。

django\views\generic\edit.py

发布请求在get_form行的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) 处失败,我意识到这是因为我已在FormView中将其覆盖:

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] 时,就像这样:

None

我的表单类未在get请求中得到处理,其结果为get_form。我想知道为什么当我覆盖{{1}}方法时它可以工作,但是我自己的命名方法不起作用吗?有人知道缺陷可能是什么吗?

1 个答案:

答案 0 :(得分:1)

Django的FormMixin [Django-doc]定义了get_form function [Django-doc]。因此,您在这里基本上将FormView的子类化,并“修补”了get_form方法。

您尝试使用gen_form无效,因为您仅定义了 local 变量,因此没有太大的区别,只有super(..)调用会有一些副作用。其他命令将使CPU繁忙一段时间,但是最后,将仅分配对对Form变量的form_class调用的引用,但是由于它是本地变量,因此将其丢弃

也就是说,您的函数包含一些错误。例如,**kwargs通常最多包含一个 个参数:form_class。因此,step不会做太多事情。您可以通过self.argsself.kwargs访问URL参数,并通过self.request.GET访问querystring参数。此外,您可能仍然想修补get_form_class function,因为您返回的是对类的引用,而据我所知,不是对初始化表格的引用。

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

因此,更好的方法是:

from django.urls import reverse

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

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

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