如何在 Django 中通过 modelformset_factory 验证?
How can I pass modelformset_factory validation in Django?
我有 2 个具有一对一关系的模型,如下所示。
class Kategori(models.Model):
urun = models.CharField(db_column='Urun', max_length=255, blank=True, null=True) # Field name made lowercase.
kategori = models.CharField(db_column='Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(db_column='Ust_Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(db_column='URUN_ADI', max_length=255, blank=True, null=True) # Field name made lowercase.
ur_id = models.CharField(db_column='UR_ID', max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(db_column='MARKA', max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(db_column='CESIDI', max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(db_column='MIKTAR', blank=True, null=True) # Field name made lowercase.
birim = models.CharField(db_column='BIRIM', max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(db_column='ADET', blank=True, null=True) # Field name made lowercase.
class categoryprob(models.Model):
urun = models.OneToOneField(Kategori,on_delete=models.CASCADE,related_name="prob")
kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(blank=True, null=True) # Field name made lowercase.
birim = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(blank=True, null=True) # Field name made lowercase.
我正在尝试根据 categoryprob
输入更新 Kategori
模型对象。我准备了一个表格来获取 Kategori
个对象,具体取决于它们在 categoryprob
的概率,如下所示。
from django import forms
from mailservice.models import categoryprob,Kategori
PASS_PROB = 0.8
class predictionForm(forms.ModelForm):
class Meta:
model = Kategori
fields = ["urun","kategori","ust_kategori","urun_adi","marka","cesidi","miktar","birim","adet"]
widgets = {
'kategori': forms.Select(choices=set(Kategori.objects.all().values_list('kategori','kategori'))),
'ust_kategori': forms.Select(choices=set(Kategori.objects.all().values_list('ust_kategori','ust_kategori'))),
'marka': forms.Select(choices=set(Kategori.objects.all().values_list('marka','marka'))),
'cesidi': forms.Select(choices=set(Kategori.objects.all().values_list('cesidi','cesidi'))),
'miktar': forms.Select(choices=set(Kategori.objects.all().values_list('miktar','miktar'))),
'birim': forms.Select(choices=set(Kategori.objects.all().values_list('birim','birim'))),
'adet': forms.Select(choices=set(Kategori.objects.all().values_list('adet','adet'))),
}
labels ={
'urun':""
}
def __init__(self, *args, **kwargs):
super(predictionForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
prob = categoryprob.objects.get(urun=instance)
self.fields['urun'].widget.attrs['readonly'] = True
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].widget.attrs['disabled'] = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.ust_kategori) > PASS_PROB:
self.fields['ust_kategori'].widget.attrs['disabled'] = True
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.urun_adi) > PASS_PROB:
self.fields['urun_adi'].widget.attrs['disabled'] = True
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:green'
if float(prob.marka) > PASS_PROB:
self.fields['marka'].widget.attrs['disabled'] = True
self.fields['marka'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['marka'].widget.attrs['style'] = 'border-color:green'
if float(prob.cesidi) > PASS_PROB:
self.fields['cesidi'].widget.attrs['disabled'] = True
self.fields['cesidi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['cesidi'].widget.attrs['style'] = 'border-color:green'
if float(prob.miktar) > PASS_PROB:
self.fields['miktar'].widget.attrs['disabled'] = True
self.fields['miktar'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['miktar'].widget.attrs['style'] = 'border-color:green'
if float(prob.birim) > PASS_PROB:
self.fields['birim'].widget.attrs['disabled'] = True
self.fields['birim'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['birim'].widget.attrs['style'] = 'border-color:green'
if float(prob.adet) > PASS_PROB:
self.fields['adet'].widget.attrs['disabled'] = True
self.fields['adet'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['adet'].widget.attrs['style'] = 'border-color:green'
我使用 modelformset_factory
将其中的 3 个渲染在一起。当我按如下方式在模板上渲染时,一切正常。
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
当我使用post方法提交时如下:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
formset.is_valid return 一直都是假的。
我不知道如何一次验证所有表单。你有什么建议吗?
模板输出图片:
request.POST的输出:
<QueryDict: {'form-TOTAL_FORMS': ['3'], 'form-INITIAL_FORMS': ['3'], 'form-MIN_NUM_FORMS': ['0'], 'form-MAX_NUM_FORMS': ['1000'], 'csrfmiddlewaretoken': ['*****'], 'form-0-id': ['125'], 'form-0-urun': ['_MotorinEcoForce'], 'form-0-urun_adi': ['asdasd'], 'form-1-id': ['186'], 'form-1-urun': ['7 stick sakız karpuz aromalı 12 adet'], 'form-1-marka': ['7 days'], 'form-2-id': ['159'], 'form-2-urun': ['7 Days Kruvasan Kayısılı Tekli 72 g'], 'form-2-kategori': ['Sebze']}>
可以说有两种形式,一种是bound形式,一种是unbound形式。这些有什么区别?好吧,绑定表单会传递一些数据 MyForm(request.POST, request.FILES)
,而未绑定表单不会传递任何数据 MyForm()
。从逻辑上讲,未绑定的表单永远不会有效,因为它 从未提交过 并且假定创建它只是为了显示/呈现表单。
这个逻辑同样适用于表单集,因此由于您没有将任何数据传递给您的表单集,它永远不会有效。另一件需要考虑的事情是您没有为表单集呈现 hidden 字段。表单集会创建某些隐藏字段,以便它可以识别哪个子表单用于哪些对象以及其他一些操作,例如删除等。如果没有这些隐藏字段,您的表单集也将无效。
因此您的视图应该是这样的:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
# Will get inefficient later on when you have many objects in the database, look for a different solution
formset = CategoryFormSet(request.POST, request.FILES) # Make a bound formset in case of a POST request
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
您的模板应如下所示:
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
{# Render hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
您还可以通过向其小部件添加禁用属性来将字段设置为禁用,这意味着它们不会与表单一起发布,但由于字段 本身 未被禁用它寻找他们的数据,找不到它并将其设置为 None
,而不是您想禁用该字段本身:
class predictionForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
...
# truncated for shortness
# similar needs to be done for other fields too
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].disabled = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
...
我有 2 个具有一对一关系的模型,如下所示。
class Kategori(models.Model):
urun = models.CharField(db_column='Urun', max_length=255, blank=True, null=True) # Field name made lowercase.
kategori = models.CharField(db_column='Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(db_column='Ust_Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(db_column='URUN_ADI', max_length=255, blank=True, null=True) # Field name made lowercase.
ur_id = models.CharField(db_column='UR_ID', max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(db_column='MARKA', max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(db_column='CESIDI', max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(db_column='MIKTAR', blank=True, null=True) # Field name made lowercase.
birim = models.CharField(db_column='BIRIM', max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(db_column='ADET', blank=True, null=True) # Field name made lowercase.
class categoryprob(models.Model):
urun = models.OneToOneField(Kategori,on_delete=models.CASCADE,related_name="prob")
kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(blank=True, null=True) # Field name made lowercase.
birim = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(blank=True, null=True) # Field name made lowercase.
我正在尝试根据 categoryprob
输入更新 Kategori
模型对象。我准备了一个表格来获取 Kategori
个对象,具体取决于它们在 categoryprob
的概率,如下所示。
from django import forms
from mailservice.models import categoryprob,Kategori
PASS_PROB = 0.8
class predictionForm(forms.ModelForm):
class Meta:
model = Kategori
fields = ["urun","kategori","ust_kategori","urun_adi","marka","cesidi","miktar","birim","adet"]
widgets = {
'kategori': forms.Select(choices=set(Kategori.objects.all().values_list('kategori','kategori'))),
'ust_kategori': forms.Select(choices=set(Kategori.objects.all().values_list('ust_kategori','ust_kategori'))),
'marka': forms.Select(choices=set(Kategori.objects.all().values_list('marka','marka'))),
'cesidi': forms.Select(choices=set(Kategori.objects.all().values_list('cesidi','cesidi'))),
'miktar': forms.Select(choices=set(Kategori.objects.all().values_list('miktar','miktar'))),
'birim': forms.Select(choices=set(Kategori.objects.all().values_list('birim','birim'))),
'adet': forms.Select(choices=set(Kategori.objects.all().values_list('adet','adet'))),
}
labels ={
'urun':""
}
def __init__(self, *args, **kwargs):
super(predictionForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
prob = categoryprob.objects.get(urun=instance)
self.fields['urun'].widget.attrs['readonly'] = True
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].widget.attrs['disabled'] = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.ust_kategori) > PASS_PROB:
self.fields['ust_kategori'].widget.attrs['disabled'] = True
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.urun_adi) > PASS_PROB:
self.fields['urun_adi'].widget.attrs['disabled'] = True
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:green'
if float(prob.marka) > PASS_PROB:
self.fields['marka'].widget.attrs['disabled'] = True
self.fields['marka'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['marka'].widget.attrs['style'] = 'border-color:green'
if float(prob.cesidi) > PASS_PROB:
self.fields['cesidi'].widget.attrs['disabled'] = True
self.fields['cesidi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['cesidi'].widget.attrs['style'] = 'border-color:green'
if float(prob.miktar) > PASS_PROB:
self.fields['miktar'].widget.attrs['disabled'] = True
self.fields['miktar'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['miktar'].widget.attrs['style'] = 'border-color:green'
if float(prob.birim) > PASS_PROB:
self.fields['birim'].widget.attrs['disabled'] = True
self.fields['birim'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['birim'].widget.attrs['style'] = 'border-color:green'
if float(prob.adet) > PASS_PROB:
self.fields['adet'].widget.attrs['disabled'] = True
self.fields['adet'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['adet'].widget.attrs['style'] = 'border-color:green'
我使用 modelformset_factory
将其中的 3 个渲染在一起。当我按如下方式在模板上渲染时,一切正常。
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
当我使用post方法提交时如下:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
formset.is_valid return 一直都是假的。
我不知道如何一次验证所有表单。你有什么建议吗?
模板输出图片:
request.POST的输出:
<QueryDict: {'form-TOTAL_FORMS': ['3'], 'form-INITIAL_FORMS': ['3'], 'form-MIN_NUM_FORMS': ['0'], 'form-MAX_NUM_FORMS': ['1000'], 'csrfmiddlewaretoken': ['*****'], 'form-0-id': ['125'], 'form-0-urun': ['_MotorinEcoForce'], 'form-0-urun_adi': ['asdasd'], 'form-1-id': ['186'], 'form-1-urun': ['7 stick sakız karpuz aromalı 12 adet'], 'form-1-marka': ['7 days'], 'form-2-id': ['159'], 'form-2-urun': ['7 Days Kruvasan Kayısılı Tekli 72 g'], 'form-2-kategori': ['Sebze']}>
可以说有两种形式,一种是bound形式,一种是unbound形式。这些有什么区别?好吧,绑定表单会传递一些数据 MyForm(request.POST, request.FILES)
,而未绑定表单不会传递任何数据 MyForm()
。从逻辑上讲,未绑定的表单永远不会有效,因为它 从未提交过 并且假定创建它只是为了显示/呈现表单。
这个逻辑同样适用于表单集,因此由于您没有将任何数据传递给您的表单集,它永远不会有效。另一件需要考虑的事情是您没有为表单集呈现 hidden 字段。表单集会创建某些隐藏字段,以便它可以识别哪个子表单用于哪些对象以及其他一些操作,例如删除等。如果没有这些隐藏字段,您的表单集也将无效。
因此您的视图应该是这样的:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
# Will get inefficient later on when you have many objects in the database, look for a different solution
formset = CategoryFormSet(request.POST, request.FILES) # Make a bound formset in case of a POST request
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
您的模板应如下所示:
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
{# Render hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
您还可以通过向其小部件添加禁用属性来将字段设置为禁用,这意味着它们不会与表单一起发布,但由于字段 本身 未被禁用它寻找他们的数据,找不到它并将其设置为 None
,而不是您想禁用该字段本身:
class predictionForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
...
# truncated for shortness
# similar needs to be done for other fields too
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].disabled = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
...