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

Django中如何阻止已有参与者的Prediction被设为取消状态

问题描述

需求:当用户尝试将已有参与者的Prediction对象状态修改为cancelled时,显示警告消息并跳转至仪表盘,阻止状态变更。
当前问题:实现的条件语句未生效,即使对象存在参与者,状态仍会被设置为取消。

相关代码

视图代码

class PredictionUpdate(ProductInline, UpdateView):

    def get_context_data(self, **kwargs):
        ctx = super(PredictionUpdate, self).get_context_data(**kwargs)
        ctx['named_formsets'] = self.get_named_formsets()
        return ctx
    
    def get_current_object(self, id):
        prediction = Predictions.objects.get(id=id)
        return {
            "prediction":prediction
        }

    def get_named_formsets(self):
        return {
            'variants': PredictionDataFormSet(self.request.POST or None, self.request.FILES or None, instance=self.object, prefix='variants'),
        }

    def dispatch(self, request ,*args, **kwargs):
        obj = self.get_object()
        if obj.user != self.request.user:
            messages.warning(self.request, "You are not allowed to edit this bet!")
            return redirect("core:dashboard")
        
        if obj.status == "finished":
            messages.warning(self.request, "You cannot edit this bet again, send an update request to continue.")
            return redirect("core:dashboard")
            # raise Http404("You are not allowed to edit this Post")
        return super(PredictionUpdate, self).dispatch(request, *args, **kwargs)
    
    def form_valid(self, form):
        instance = form.instance
        if instance.participants.exists() and instance.status == 'cancelled':
            messages.warning(self.request, "You cannot cancel a bet that already have participants")
            return redirect("core:dashboard")
        else:
            form.save()
            return HttpResponseRedirect(self.get_success_url())

模型代码

STATUS = (
    ("live", "Live"),
    ("in_review", "In review"),
    ("pending", "Pending"),
    ("cancelled", "Cancelled"),
    ("finished", "Finished"),
)

class Predictions(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    title = models.CharField(max_length=1000)
    participants = models.ManyToManyField(User, related_name="participants", blank=True)
    status = models.CharField(choices=STATUS, max_length=100, default="in_review")
问题原因

form_valid方法中的判断逻辑有误:instance.status == 'cancelled'检查的是数据库中保存的旧状态,而非用户提交的新状态。当用户尝试修改状态为cancelled时,此时instance还是从数据库取出的原对象,状态尚未被表单更新,因此该判断永远不会触发。

解决方案

需要获取用户提交的新状态来做判断,有两种可行方式:

方式一:直接从表单清洗后的数据中获取新状态

def form_valid(self, form):
    # 获取用户提交的新状态
    new_status = form.cleaned_data.get('status')
    instance = form.instance
    # 判断:存在参与者且新状态为cancelled
    if instance.participants.exists() and new_status == 'cancelled':
        messages.warning(self.request, "不能取消已有参与者的赌注")
        return redirect("core:dashboard")
    else:
        form.save()
        return HttpResponseRedirect(self.get_success_url())

方式二:生成未保存的修改后实例再判断

如果需要对修改后的实例做更多操作,可以先调用save(commit=False)获取未保存的实例,注意要手动保存多对多关联:

def form_valid(self, form):
    # 获取修改后的实例(未写入数据库)
    instance = form.save(commit=False)
    if instance.participants.exists() and instance.status == 'cancelled':
        messages.warning(self.request, "不能取消已有参与者的赌注")
        return redirect("core:dashboard")
    else:
        instance.save()
        # 手动保存多对多字段的关联数据
        form.save_m2m()
        return HttpResponseRedirect(self.get_success_url())

内容的提问来源于stack exchange,提问作者Destiny Franks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:46:11