首页 > 解决方案 > 未触发自定义表单集验证错误

问题描述

我创建了一个自定义验证错误,在抽象基于类的视图之前它工作得很好。出于某种原因,每当出现错误时,错误都是空白的,例如[{}]

验证错误逻辑:

class BaseFormSetValidation(BaseModelFormSet):

    def clean(self):
        super().clean()    
        days = ['day_1', 'day_2', 'day_3', 'day_4', 'day_5', 'day_6', 'day_7']
        for form in self.forms:
            for day in days:
                current_day = form.cleaned_data.get(day)
                if current_day is not None and current_day > 24:
                    raise ValidationError([{day: ["Submitted hours per day cannot exceed 24 hours"]}])


class DivErrorList(ErrorList):
        def __str__(self):
            return self.as_divs()
        def as_divs(self):
            if not self: return ''
            return '%s' % ''.join([e for e in self])

TimesheetModelFormSet = modelformset_factory(Timesheet, formset=BaseFormSetValidation, exclude=("year", "week", "project", "user"), extra=0)

TemplateView Class

class TimesheetEditorView(BaseTimesheet, TemplateView):
    form_class = TimesheetModelFormSet
    template_name = "timesheets/timesheet.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        timesheet = Timesheet.objects.filter(year=context["year"], week=context["week"], user=self.request.user).order_by("project_id") 

        timesheet_formset = self.form_class(queryset=timesheet, error_class=DivErrorList)
        create_timesheet_form = TimesheetModelForm(self.request.user)

        context.update(
            timesheet=timesheet,
            timesheet_formset=timesheet_formset,
            create_timesheet_form=create_timesheet_form
        )
        return context

    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        timesheet_formset = self.form_class(request.POST)
        if timesheet_formset.is_valid():
            messages.info(request, "Weekly timesheet updated", extra_tags='timesheet')
            timesheet_formset.save()
            success_url = reverse("timesheets:current-week", args=(context["year"], context["week"]))
            return HttpResponseRedirect(success_url)

        return render(request, "timesheets/timesheet.html", self.get_context_data(**kwargs))

继承自

class BaseTimesheet(object):

    ...

    def get_context_data(self, **kwargs):
        context = super(BaseTimesheet, self).get_context_data(**kwargs)
        year = kwargs.get("year") or datetime.datetime.now().year
        week = kwargs.get("week") or Week.thisweek().week
        user = self.request.user


        next_year, next_week = calc_next(year, week)
        previous_year, previous_week = calc_previous(year, week)
        calc_full_week = self.calc_full_week(year, week)

        context.update(
            week=week,
            year=year,
            next_week=next_week,
            previous_week=previous_week,
            next_year=next_year,
            previous_year=previous_year,
            current_week=calc_full_week
        )


        return context

以及带有错误处理的模板:

    {% for row in timesheet_formset %}
    {% if row.errors %}
    <div class="col-lg-10 offset-lg-1 text-center">
        <div class="alert alert-warning alert-dismissible fade show">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
            Error on project {{ row.instance.project }}
            {% endif %}


            {% for field in row %}
            {% if field.errors %}
            {% for error in field.errors %}
            <p>{{ field.label }} - {{ error }}</p>
            {% endfor %}
            {% endif %}
            {% endfor %}

            {% if row.errors %}
        </div>
    </div>
    {% endif %}

    {% endfor %}

    {% if timesheet_formset.non_form_errors %}
    <div class="col-lg-10 offset-lg-1 text-center">
        <div class="alert alert-warning alert-dismissible fade show">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
            {{ timesheet_formset.non_form_errors }}
        </div>
    </div>
    {% endif %}

我需要通过error_class=DivErrorList其他地方吗?现在,每当发生错误时,表格只是“重置”可以这么说

这是TimesheetEditorView我重构之前的样子,并且错误将在模板中正确输出。逻辑没有发生实际的“改变”——我所做的只是重构代码,这样我的观点就不会那么“厚”

@method_decorator(login_required, name='dispatch')
class TimesheetEditorView(View):
    form_class = TimesheetModelFormSet

    def get(self, request, *args, **kwargs):
        year = kwargs.get("year") or datetime.datetime.now().year
        week = kwargs.get("week") or Week.thisweek().week
        user = request.user
        if invalid_week(week, year):
            raise Http404("Invalid week / year")

        next_year, next_week = calc_next(year, week)
        previous_year, previous_week = calc_previous(year, week)
        calc_full_week = self.calc_full_week(year, week)

        timesheet = Timesheet.objects.filter(year=year, week=week, user=user).order_by("project_id")  # only show timesheet rows that belongs to logged in user

        timesheet_formset = self.form_class(queryset=timesheet)
        create_timesheet_form = TimesheetModelForm(user)
        context = {
            "create_timesheet_form": create_timesheet_form,
            "timesheet_formset": timesheet_formset,
            "week": week,
            "year": year,
            "next_week": next_week,
            "next_year": next_year,
            "previous_week": previous_week,
            "previous_year": previous_year,
            "current_week": calc_full_week,
        }

        return render(request, "timesheets/timesheet.html", context)

    def post(self, request, *args, **kwargs):
        year = kwargs.get("year") or datetime.datetime.now().year
        week = kwargs.get("week") or Week.thisweek().week

        if invalid_week(week, year):
            raise Http404("Invalid week / year")

        next_year, next_week = calc_next(year, week)
        previous_year, previous_week = calc_previous(year, week)

        timesheet_formset = self.form_class(request.POST, error_class=DivErrorList)
        if timesheet_formset.is_valid():
            messages.info(request, "Weekly timesheet updated", extra_tags='timesheet')
            timesheet_formset.save()
            success_url = reverse("timesheets:current-week", args=(year, week))
            return HttpResponseRedirect(success_url)

        create_timesheet_form = TimesheetModelForm(request.user)

        context = {
            "create_timesheet_form": create_timesheet_form,
            "timesheet_formset": timesheet_formset,
            "week": week,
            "year": year,
            "next_week": next_week,
            "next_year": next_year,
            "previous_week": previous_week,
            "previous_year": previous_year,

        }

        return render(request, "timesheets/timesheet.html", context)

标签: djangodjango-formsdjango-views

解决方案


问题是您没有交出表格:

def post(self, request, *args, **kwargs):
    context = self.get_context_data(**kwargs)
    timesheet_formset = self.form_class(request.POST)
    if timesheet_formset.is_valid():
        messages.info(request, "Weekly timesheet updated", extra_tags='timesheet')
        timesheet_formset.save()
        success_url = reverse("timesheets:current-week", args=(context["year"], context["week"]))
        return HttpResponseRedirect(success_url)

    return render(request, "timesheets/timesheet.html", self.get_context_data(**kwargs))

无需self.get_context_data(**kwargs)使用相同的 kwargs 调用它们,它们将是相同的。并且您必须像在“原始”视图中那样交出timesheet_formsetand 。create_timesheet_form

这将导致这样的事情:

def post(self, request, *args, **kwargs):
    context = self.get_context_data(**kwargs)
    timesheet_formset = self.form_class(request.POST)
    if timesheet_formset.is_valid():
        messages.info(request, "Weekly timesheet updated", extra_tags='timesheet')
        timesheet_formset.save()
        success_url = reverse("timesheets:current-week", args=(context["year"], context["week"]))
        return HttpResponseRedirect(success_url)

    context['timesheet_formset'] = timesheet_formset
    create_timesheet_form = TimesheetModelForm(request.user)
    context['create_timesheet_form '] = create_timesheet_form 

    return render(request, "timesheets/timesheet.html", )

您必须测试是否同时需要timesheet_formsetcreate_timesheet_form


推荐阅读