【问题标题】:Show soft warning from clean method of Django Formset for Model Form显示来自模型表单的 Django Formset 的 clean 方法的软警告
【发布时间】:2020-12-02 08:13:13
【问题描述】:

我有一个模型表单和一个表单集,我正在成功使用,没有问题。

在我的表单集的clean 方法中,我执行了一些逻辑 - 但以前导致ValidationError 的要求之一现在正在更改,应该只是在模板中对用户的一个简单警告。

我的模型表单和表单集如下所示:

class AlignmentForm(forms.ModelForm):
    def __init__(self, *args, employee, **kwargs):
        self.person = person
        super().__init__(*args, **kwargs)

    class Meta:
        model = Alignment
        fields = [
            "alignment",
            "start_date",
            "end_date",
        ]


class AlignmentFormSet(forms.BaseModelFormSet):

    def clean(self):
        if any(self.errors):
            return

        # I've trimmed out additional logic and checks
        # This is the area of concern

        alignment_error = {}
        for i, form in enumerate(self.forms):
            if not end_date:
                if alignment == "Wrong":
                    alignment_error = {
                        "alignment": alignment,
                        "added_message": "Corrected",
                    }

        if alignment_error:
            raise forms.ValidationError(
                f"""
                The alignment is
                 ({alignment_error['alignment']}) and must
                 be ({alignment_error['added_message']}).
            """
            )

        return form

当前的ValidationError 需要成为仅在模板中呈现给用户的一条消息 - 但不会阻止表单验证和保存。

我尝试过这样做:

    if alignment_error:
        messages.warning(
            request,
            f"""
            The alignment is
             ({alignment_error['alignment']}) and must
             be ({alignment_error['added_message']}).
        """,
        )

但这不起作用,因为我无权访问请求。我可以访问它吗?

实现这一目标的最佳方法是什么?我仍然想显示该消息,但只是不希望它阻止表单保存。

编辑添加:

views 函数如下所示:(基本部分)

def person(request, person_no):
    person = get_user_model().objects.get(person_no=person_no)
    formset = get_alignment_formset(person, request.POST)
    if request.method == "POST":
        # If add alignment is in form the util method will handle adding
        # the extra form if add alignment not in post data actually validate
        # and process the form
        if "add_alignment" not in request.POST:
            if formset.is_valid():
                # If form is valid we want to get the person being updated
                # current alignment
                alignment_before = Alignment.get_active_primary(person)

                for formset_form in formset:
                    if formset_form.has_changed():
                        alignment = formset_form.save(commit=False)
                        alignment.user = person
                        if not alignment.pk:
                            alignment.created_by = request.user
                        alignment.modified_by = request.user
                        alignment.save()
                    else:
                        alignment = formset_form.save(commit=False)

                # do some logic with position control here
                warnings, errors = update_foil_alignment_app(
                    request.user, person, alignment_before, alignment
                )
                if errors or warnings:
                    for error in errors:
                        messages.error(request, error)
                    for warning in warnings:
                        messages.warning(request, warning)
                    kwargs = {"person_no": person.person_no}
                    return redirect("app_name:person", **kwargs)

                messages.success(
                    request,
                    f"""
                    You have successfully updated alignments for
                     {alignment.user.last_name}, {alignment.user.first_name}.
                """,
                )
                kwargs = {"person_no": person.person_no}
                return redirect("app_name:person", **kwargs)

utils 函数如下所示:

def get_alignment_formset(person, post_data=None):
    extra = 0
    # If add alignment in post_data we add the extra form and clear out
    # post data, we don't actually want to post only data
    if post_data:
        if "add_alignment" in post_data:
            post_data = None
            extra = 1
    formset = modelformset_factory(
        Alignment,
        fields=("alignment", "start_date", "end_date"),
        extra=extra,
        form=AlignmentForm,
        formset=AlignmentFormSet,
    )
    formset = formset(
        post_data or None,
        form_kwargs={"person": person},
        queryset=Alignment.exclude_denied.filter(user=person).annotate(
            num_end_date=Count("end_date")
        ).order_by(
            "-end_date",
        ),
    )
    return formset

【问题讨论】:

  • 你能发表你正在使用的观点吗?
  • @SukhpreetSingh 我已经添加了视图和随之而来的 utils 调用

标签: python django forms django-forms modelform


【解决方案1】:

我相信此时我已经能够通过执行以下操作适当地传递请求:

Views.py:

def person(request, person_no):
    person = get_user_model().objects.get(person_no=person_no)
    formset = get_alignment_formset(person, request.POST, request)

Utils.py:

def get_alignment_formset(person, post_data=None, request=None):
    extra = 0
    # If add alignment in post_data we add the extra form and clear out
    # post data, we don't actually want to post only data
    if post_data:
        if "add_alignment" in post_data:
            post_data = None
            extra = 1
    formset = modelformset_factory(
        Alignment,
        fields=("alignment", "start_date", "end_date"),
        extra=extra,
        form=AlignmentForm,
        formset=AlignmentFormSet,
    )
    formset = formset(
        post_data or None,
        form_kwargs={"person": person, "request": request},
        queryset=Alignment.exclude_denied.filter(user=person).annotate(
            num_end_date=Count("end_date")
        ).order_by(
            "-end_date",
        ),
    )
    return formset

Forms.py:

class AlignmentForm(forms.ModelForm):
    def __init__(self, *args, employee, request, **kwargs):
        self.person = person
        self.request = request
        super().__init__(*args, **kwargs)

class AssignmentFormSet(forms.BaseModelFormSet):

    def clean(self):
        ...
        ...
        if alignment_error:
            warning = "There was an issue"
            messages.warning(form.request, warning)

它现在按预期显示为警告。

【讨论】:

    猜你喜欢
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 2020-06-26
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-14
    • 2011-05-05
    相关资源
    最近更新 更多