简体   繁体   English

Django inlineformset_factory 验证器不工作

[英]Django inlineformset_factory validators not working

Code Snippet代码片段

Django version: 3.1.7 Django 版本:3.1.7

models.py模型.py

# custom validator
is_numeric = RegexValidator(r"^[0-9]*$", "Only numbers are allowed")

class Person(models.Model):
    # all the boring fields


class PersonAddress(models.Model):
    # all the boring fields
    person = models.ForeignKey(
        Person, null=True, on_delete=models.SET_NULL, related_name="person_address",
    )
    postcode = models.CharField(
        blank=True, help_text="Include leading zero if exists",
        max_length=10, validators=[is_numeric],
    )

PersonAddress will be the inlineformset of Person as a Person can have multiple addresses PersonAddress将是Person的内联表单集,因为一个 Person 可以有多个地址

forms.py forms.py

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()


class PersonAddressForm(forms.ModelForm):
    class Meta:
        model = PersonAddress
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_method = "post"


PersonAddressFormSet = forms.models.inlineformset_factory(
    Person, PersonAddress, form=PersonAddressForm, extra=1, can_delete=True,
)

# min_num, validate_min don't help even though I read from other stackoverflow solution
# PersonAddressFormSet = forms.models.inlineformset_factory(
#     Person, PersonAddress, form=PersonAddressForm, extra=1, can_delete=True, min_num=1, validate_min=True,
# )

views.py视图.py

# Person CreateView
class PersonCreateView(SuccessMessageMixin, LoginRequiredMixin, CreateView):
    model = Person
    form_class = PersonForm

    def get_context_data(self, **kwargs):
        context = super(PersonCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            context["addresses"] = PersonAddressFormSet(self.request.POST, self.request.FILES)
        else:
            context["addresses"] = PersonAddressFormSet()
        return context

    # I think the problem is here, not 100% sure
    def form_valid(self, form):
        context = self.get_context_data()
        addresses = context["addresses"]
        self.object = form.save()
        if addresses.is_valid():
            addresses.instance = self.object
            addresses.save()

        # https://stackoverflow.com/questions/47476941/django-inlineformset-factory-error-messages-not-working
        # my attempt, got this error
        # TypeError: join() argument must be str, bytes, or os.PathLike object, not 'NoneType'
        # else:
        #    return render(self.request, self.template_name, context)

        return super(PersonCreateView, self).form_valid(form)


# PersonAddress CreateView
class PersonAddressCreateView(SuccessMessageMixin, LoginRequiredMixin, CreateView):
    model = PersonAddress
    form_class = PersonAddressForm

Problem问题

If I create a PersonAddress object with postcode that's non-numeric string, the PersonAddressCreateView HTML form will return validation error.如果我使用非数字字符串的postcode创建PersonAddress object,则PersonAddressCreateView HTML 表单将返回验证错误。

But if I do the same thing in PersonCreateView HTML form, there won't be any validation error.但是如果我在PersonCreateView HTML 表单中做同样的事情,就不会有任何验证错误。 Person object will be created, PersonAddress won't be created as the postcode is invalid.将创建Person PersonAddress ,不会创建人员地址,因为postcode无效。 What I am expecting is for the PersonCreateView HTML form to show me the validation error instead of saving the form.我期待的是PersonCreateView HTML 表单向我显示验证错误而不是保存表单。

I think the solution should have something to do with the PersonCreateView 's form_valid , but I am not sure.我认为解决方案应该与PersonCreateViewform_valid ,但我不确定。

Thanks in advance!提前致谢!

Indeed, the issue is in your form_valid implementation.实际上,问题出在您的form_valid实现中。 To be exact, you are just doing nothing when the PersonAddressFormSet is not valid.确切地说,当PersonAddressFormSet无效时,您什么也不做。 To fix that issue, try:要解决该问题,请尝试:

    def form_valid(self, form):
        context = self.get_context_data()
        addresses = context["addresses"]
        self.object = form.save()
        if addresses.is_valid():
            addresses.instance = self.object
            addresses.save()
        else:
            return self.form_invalid(form)
        return super(PersonCreateView, self).form_valid(form)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM