【问题标题】:raise forms.ValidationError not working提高 forms.ValidationError 不起作用
【发布时间】:2012-06-07 16:42:32
【问题描述】:

我有以下型号:

class Project(models.Model):
    title = models.CharField(max_length="100")

    pub_date = models.DateField(auto_now_add=True, editable=False)

    budget = models.IntegerField()

class Milestone(models.Model):

    title = models.CharField(max_length="50")

    budget_percentage = models.IntegerField(max_length=2)

    project = models.ForeignKey(Project)

在项目的创建表单中,我包含了一个用于里程碑的内联表单集。

我想验证提交项目时,至少创建了 4 个里程碑,并且所有里程碑的 budget_percentage 总和为 100

这是我的表格:

class BaseMilestoneProjectFormSet(BaseFormSet):
    def clean(self):

        if any(self.errors):
            # Don't bother validating the forms unless each form is valid on its own
            return

        if len(self.forms) < REQUIRED_MILESTONES:
            raise forms.ValidationError("At least %s milestones need to be created" % REQUIRED_MILESTONES)

        # Set initial control variables
        # Total percentage of budget to control
        total_percentage = 0
        # Date to control that milestones are linear, i.e. that second milestone isn't delivered before first
        current_control_date = date.min

        for i, form in zip(range(len(self.forms)), self.forms):

            if i == 0 and form.budget_percentage > MAX_BUDGET_FIRST_MILESTONE:
                raise forms.ValidationError("First milestone budget must not exceed %s percentage" % MAX_BUDGET_FIRST_MILESTONE)
            elif form.budget_percentage > MAX_BUDGET_MILESTONE:
                raise forms.ValidationError("Milestone's budget must not exceed %s percentage" % MAX_BUDGET_MILESTONE)

            if form.estimated_delivery_date < current_control_date:
                raise forms.ValidationError("Milestones must be linear, check your delivery dates")

            # Set control variables for next iteration    
            current_control_date = form.estimated_delivery_date                
            total_percentage += form.budget_percentage

        if total_percentage != 100:
            raise forms.ValidationError("All milestones budget percentage should sum up to 100%")

当我提交带有 3 个空里程碑表单的表单时,它不会对第一个表单做任何事情 forms.ValidationError(...)

我已经用 raise Exception() 验证了它实际上进入了 if,但它继续执行,好像什么都没发生一样。

这是我的代码中的错误还是对 ValidationError 的误解?

任何帮助将不胜感激,在此先感谢。

编辑:

我正在添加缺少的视图代码

class DelayedModelFormMixin(ModelFormMixin):
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.prepare_object_for_save(self.object)
        self.object.save()
        if hasattr(self.object, "save_m2m"):
            self.object.save_m2m()
        return super(ModelFormMixin, self).form_valid(form)

    def prepare_object_for_save(self, obj):
        pass

class ProjectNew(CreateView, DelayedModelFormMixin):
    model = Project
    success_url = '/projects/project/%(slug)s'
    form_class = ProjectForm

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(ProjectNew, self).dispatch(request, *args, **kwargs)

    def prepare_object_for_save(self, obj):
        obj.owner = self.request.user
        # Code for stacked milestones and rewards
        context = self.get_context_data()
        milestone_form = context['milestone_formset']
        reward_form = context['reward_formset']
        if milestone_form.is_valid() and reward_form.is_valid():
            self.object = form.save()
            milestone_form.instance = self.object
            milestone_form.save()
            reward_form.instance = self.object
            reward_form.save()
            return HttpResponseRedirect(success_url)

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def get_context_data(self, **kwargs):
        context = super(ProjectNew, self).get_context_data(**kwargs)
        if self.request.POST:
            context['milestone_formset'] = MilestoneFormSet(self.request.POST)
            context['reward_formset'] = RewardFormSet(self.request.POST)
        else:
            context['milestone_formset'] = MilestoneFormSet()
            context['reward_formset'] = RewardFormSet()
        return context

【问题讨论】:

  • 当您检查表单集是否有效时会发生什么? formset.is_valid() 它应该返回 false。
  • 您实际上是如何使用表单的?
  • 给我们一些关于如何使用表单集的线索。如果可以,请添加您正在使用表单集的视图的代码。尝试将len(self.forms) 部分更改为self.total_form_count()This 可以帮到你
  • 当您说“当我提交没有 3 个空里程碑表单的表单时”,您的意思是“当我提交包含 3 个空里程碑表单的表单时”?是“有”还是“没有”?
  • @mtnpaul 我要试试这个

标签: django validation django-forms inline-formset


【解决方案1】:

如果我理解您的问题,问题是您正在计算表单集中有多少表单,但您想要/需要计算表单集中有多少 BOUND 表单。

所以,我认为你需要改变这一行:

if len(self.forms) < REQUIRED_MILESTONES:

对于这些行:

bounded_forms = filter(lambda form:form.isbound(), self.forms)
if len(bounded_forms) < REQUIRED_MILESTONES:

然后您可以在执行此操作时引发验证错误。

编辑:

也许您不了解表单集验证的工作原理。可能是this可以帮忙,特别是这句话:

formset clean 方法是在所有 Form.clean 方法被调用后调用的。将使用表单集上的 non_form_errors() 方法找到错误。

如果我明白你说的意思

当我提交带有 3 个空里程碑表单的表单时,它对第一个表单没有任何作用。ValidationError(...)

那么,您不会看到引发的错误。因此,寻找它们的地方是 formset "non_form_errors" 方法。在你的模板中加入这样的东西:

<span>{{milestone_formset.non_form_errors}}</span>

现在您应该看到您在里程碑式表单集清理方法中引发的错误。

希望对你有帮助!

【讨论】:

  • 我不认为这是问题所在,我已经测试了它是否使用 raise Execption(message) 进入 if 并且它正确地引发了异常。问题在于 forms.ValueError
  • 我在表单模板上使用了 non_form_errors。问题是 django 表现得好像没事一样,重定向到成功页面,而不是返回表单模板
猜你喜欢
  • 2020-02-11
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
相关资源
最近更新 更多