【问题标题】:Django CreateView with get_success_url not working for this specific case带有 get_success_url 的 Django CreateView 不适用于这种特定情况
【发布时间】:2019-10-30 12:05:39
【问题描述】:

我使用的是 Django 2.1。 我在使用 CreateView 时遇到问题,因为我需要重定向到更新 url,但该 url 包含一个在验证表单有效后手动创建的参数。

这是查看代码:

class ProjectCreateInvestmentCampaignView(LoginRequiredMixin, SuccessMessageMixin, generic.CreateView):
    template_name = 'webplatform/project_edit_investment_campaign.html'
    model = InvestmentCampaign
    form_class = CreateInvestmentCampaignForm
    success_message = 'Investment campaign created!'

    def get_success_url(self):
        return reverse_lazy('project-update-investment-campaign',
                            args=(self.kwargs['pk'], self.object.campaign.pk, self.object.pk))

    def form_valid(self, form):
        project = Project.objects.get(pk=self.kwargs['pk'])
        form.instance.investment_type = "A"
        form.instance.contract_type = "CI"
        form.instance.history_change_reason = 'Investment campaign created'
        valid = super(ProjectCreateInvestmentCampaignView, self).form_valid(form)
        if valid:
            campaign = CampaignBase.objects.create(project=project, )
            form.instance.campaign = campaign
            form.instance.campaign.project = project
            form.instance.campaign.creation_date = timezone.now()
            form.save()
        return valid

如您所见,在form_valid 上,我首先验证表单,然后创建对象营销活动并分配所有相关数据。这工作正常。 当我更改get_success_url 以适应我的用例时,问题出现了,即重定向到更新视图。 我调试并看到在form_valid 上创建变量valid 时,它会检查成功的url,这会触发我以下错误:

Exception Type: AttributeError
Exception Value:    
'NoneType' object has no attribute 'pk'
Exception Location: /Volumes/Archivos/work/i4b/webplatform/views/investor_campaign_views.py in get_success_url, line 25

我认为错误是因为尚未创建活动,因此它试图从不存在的对象中获取 pk

问题是,如果表单未经过验证,我将无法创建广告系列,但我需要该广告系列才能使 URL 正常工作(该 URL 正在工作,就像我已经拥有的 UpdateView 一样)。

【问题讨论】:

    标签: python django url django-views


    【解决方案1】:

    它只会在form_valid 之后调用get_success_url。所以由form_valid 来创建和保存所需的对象。如果不创建它们是有效的,那么您需要一种不同的方法。也许初始化(比如说)self.campaign_pk = 0,如果可以用campaign对象的pk创建一个campaign,就更新它,然后让下一个视图整理一下pk==0时该怎么做。或者,

    ...
        args=(self.kwargs['pk'], 
              self.object.campaign.pk if self.object.campaign else 0, 
              self.object.pk))
    

    (我没有完全按照你的代码,所以我可能在这里吠错了树)

    您可能不想要 CreateView 而想要 FormView,它不会为您处理对象创建,因此您可能会发现如何处理无法完全兑现的有效表单有更大的灵活性时间。甚至,只是一个普通的基于函数的旧视图,您可以在其中处理两个或多个表单,并且即使在所有表单都经过技术验证之后,也更有能力决定构成无效的条件。

    这是我使用过的基于函数的视图结构,我有两个表单要处理,并且在两个表单都验证后要执行一组相当长但无聊的操作:

    def receive_view( request):
    
        # let's put form instantiation in one place not two, and reverse the usual test. This
        # makes for a much nicer layout with actions not sandwiched by "boilerplate" 
        # note any([ ]) forces invocation of both .is_valid() methods 
        # so errors in second form get shown even in presence of errors in first
    
        args = [request.POST, ] if request.method == "POST" else []
        batchform = CreateUncWaferBatchForm( *args, layout=CreateUncWaferBatchLayout )
        po_form =  CreateUncWaferPOForm(     *args, layout = CreateUncWaferPOLayout, prefix='po')
        if request.method != "POST" or any(  
            [ not batchform.is_valid(), not po_form.is_valid() ]):
    
            return render(request, 'wafers/receive_uncoated.html',   # can get this out of the way at the top
                {'batchform': batchform,  
                'po_form': po_form, 
            })
    
        #it's a POST, everything is valid, do the work
        ...
        return redirect('appname:viewname', ...)
    

    【讨论】:

    • 我正在使用一个带有额外字段的 ModelForm,然后我将其保存在另一个模型上。对于这种情况,该字段是end_date,我在知道表单有效后将其保存在我正在创建的对象上:CampaignBase。考虑到args 中的if,它将仅用于通过验证,但是视图本身将获得具有正确pk 的视图,对吗?如果您认为拥有模型或任何其他额外信息将有助于了解我要解释的内容,请告诉我,我会更新问题。
    【解决方案2】:

    对我来说,get_success_url 没有被调用,因为表单无效(是 invalid)而且我不知道。您可以覆盖form_invalid(self, form) 来控制行为。

    此外,请考虑使用此代码块来显示模板中的任何错误

    {% if form.errors %}
    <div class="alert alert-danger" role="alert">
        {% for field, errors in form.errors.items %}
        {% for error in errors %}
        <b>{{ field }}</b>: {{ error }}
        {% endfor %}
        {% endfor %}
    </div>
    {% endif %}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      • 2015-10-26
      • 2020-02-16
      • 2013-07-05
      相关资源
      最近更新 更多