You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 2.1中CreateView的get_success_url因后续创建对象失效问题

解决Django CreateView中重定向URL依赖后续创建对象的问题

你的问题根源在于调用super().form_valid(form)的时机不对:这个方法会自动保存InvestmentCampaign实例到数据库,但此时你还没创建并关联CampaignBase对象,导致get_success_url尝试访问self.object.campaign.pk时,campaign属性还是None,触发AttributeError。

解决方案:调整逻辑顺序,先创建关联对象再保存表单

正确的流程应该是:先创建CampaignBase,把它关联到表单实例,再调用父类的form_valid完成保存,这样self.object在get_success_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):
        # 现在self.object.campaign已经存在,可以正常获取pk
        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'])
        
        # 1. 先创建CampaignBase对象,直接设置必要字段
        campaign = CampaignBase.objects.create(
            project=project,
            creation_date=timezone.now()
        )
        
        # 2. 给表单实例赋值所有必要字段,包括关联刚创建的campaign
        form.instance.investment_type = "A"
        form.instance.contract_type = "CI"
        form.instance.history_change_reason = 'Investment campaign created'
        form.instance.campaign = campaign  # 关键:提前关联campaign
        
        # 3. 最后调用父类方法,完成表单保存和后续重定向
        return super().form_valid(form)

为什么原来的代码会报错?

原来的代码执行顺序是:

  1. 调用super().form_valid(form):这一步会触发form.save(),把还没有campaign属性的InvestmentCampaign保存到数据库,同时self.object被设置为这个未完整的实例。
  2. 然后才创建CampaignBase并关联到form.instance,再调用form.save()更新数据库。

但get_success_url是在super().form_valid(form)的执行过程中被调用的,此时self.object还没有campaign属性,自然会出现'NoneType' object has no attribute 'pk'的错误。

额外优化点

  • 你原来代码中form.instance.campaign.project = project是多余的,因为创建CampaignBase时已经指定了project=project。
  • 如果Project对象可能不存在,建议用get_object_or_404(Project, pk=self.kwargs['pk'])替代get(),避免抛出DoesNotExist异常。

内容的提问来源于stack exchange,提问作者Pol Frances

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:26:03