代码之家  ›  专栏  ›  技术社区  ›  Hanny

显示来自模型表单Django Formset的clean方法的软警告

  •  0
  • Hanny  · 技术社区  · 4 年前

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

    在我的 clean formset的方法我执行一些逻辑,但其中一个需求之前导致了 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
    

    验证错误 需要成为模板中呈现给用户的消息,但不会阻止表单验证和保存。

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

    但这不起作用,因为我没有访问请求的权限。我可以使用它吗?

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

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

    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
    
    0 回复  |  直到 4 年前
        1
  •  0
  •   Hanny    4 年前

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

    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)
    

    它现在显示为一个预期的警告。