问题描述
代码片段
Django 版本:3.1.7
models.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
将是 Person
的内联表单集,因为一个人可以有多个地址
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,**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,min_num=1,validate_min=True,# )
views.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,CreateView):
model = PersonAddress
form_class = PersonAddressForm
问题
如果我使用非数字字符串 PersonAddress
创建一个 postcode
对象,PersonAddressCreateView
HTML 表单将返回验证错误。
但是如果我在 PersonCreateView
HTML 表单中做同样的事情,就不会有任何验证错误。 Person
对象将被创建,PersonAddress
不会被创建,因为 postcode
无效。我期望 PersonCreateView
HTML 表单向我显示验证错误而不是保存表单。
我认为解决方案应该与 PersonCreateView
的 form_valid
有关,但我不确定。
提前致谢!
解决方法
确实,问题出在您的 form_valid
实现中。确切地说,当 PersonAddressFormSet
无效时,您什么都不做。要解决该问题,请尝试:
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)