简体   繁体   English

Django CreateView with get_success_url 不适用于此特定情况

[英]Django CreateView with get_success_url not working for this specific case

I'm using Django 2.1.我正在使用 Django 2.1。 I'm having a problem with a CreateView because I need to redirect to the update url, but that url contains one argument that is created manually after verifying that the form is valid.我在使用 CreateView 时遇到问题,因为我需要重定向到更新 url,但是 url 包含一个在验证表单有效后手动创建的参数。

This is the view code:这是视图代码:

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

As you can see, on the form_valid I validate first the form, and then I create the object campaign and assign all the related data.如您所见,在form_valid上,我首先验证表单,然后创建 object 活动并分配所有相关数据。 This is working fine.这工作正常。 The problem came when I changed the get_success_url to fit my use case, that is redirecting to the update view.当我更改get_success_url以适合我的用例时出现问题,即重定向到更新视图。 I debugged and saw that at the moment I create the variable valid on the form_valid , it checks the success url, and that triggers me the following error:我调试并看到,当我在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

I asume that the error is because the campaign is not created yet so it's trying to get the pk from a non existing object.我认为错误是因为尚未创建活动,因此它试图从不存在的 object 获取pk

The thing is that I cannot create the campaign if the form is not validated, but I need the campaign to make the url working (that url is working as it is on the UpdateView that I already have).问题是,如果表单未经验证,我无法创建活动,但我需要活动来使 url 工作(url 正在工作,因为它在我已经拥有的UpdateView上工作)。

It will only invoke get_success_url after form_valid .它只会在get_success_url之后调用form_valid So it's up to form_valid to create and save the objects needed.因此,由form_valid创建和保存所需的对象。 If it's valid for them not to be created, you need a different approach.如果不创建它们是有效的,那么您需要一种不同的方法。 Maybe initialize (say) self.campaign_pk = 0 , update it if a campaign can be created with the pk of the campaign object, and let the next view sort out what to do when pk==0.也许初始化(比如说) self.campaign_pk = 0 ,如果可以使用活动 object 的 pk 创建活动,则更新它,然后让下一个视图理清 pk==0 时该怎么做。 Or,或者,

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

(I don't fully follow your code so I might be barking up the wrong tree here) (我没有完全遵循你的代码,所以我可能会在这里吠叫错误的树)

It may be that you don't want CreateView but FormView , which doesn't handle object creation for you, so you may find greater flexibility over how to process a valid form that nevertheless cannot be fully honoured all the time.可能您不想要CreateView而是FormView ,它不会为您处理 object 创建,因此您可能会发现如何处理无法始终完全兑现的有效表单具有更大的灵活性。 Or even, just a plain old function-based view, in which you can process two or more forms and be far more able to decide on conditions that constitute non-validity even after all the forms have technically validated.甚至,只是一个普通的基于函数的旧视图,您可以在其中处理两个或多个 forms,并且即使在所有 forms 都经过技术验证之后,也更有能力决定构成无效的条件。

This is a function-based view structure I have used where I have two forms to process, and a fairly long but boring set of operations to do after BOTH forms validate:这是我使用的基于函数的视图结构,其中我有两个 forms 需要处理,并且在两个 forms 验证之后要做一组相当长但无聊的操作:

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', ...)

For me, get_success_url was not invoked as the form was not valid (was invalid ) and I didn't know.对我来说, get_success_url没有被调用,因为表单无效( invalid )而且我不知道。 You can override form_invalid(self, form) to control the behavior.您可以覆盖form_invalid(self, form)来控制行为。

Also, consider this block of code to show any errors in your template此外,请考虑使用此代码块来显示模板中的任何错误

{% 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 %}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM