为什么在查看已提交的表单时模型会干净运行?



我有一个网站,允许用户多次提交相同的表格(但输入不同(,但也允许他们查看并编辑提交的每个表格。

问题在于";密钥名称"领域如果我查看了一个已经提交的表单(edit_keydef(,则会出现ValidationError消息,其中字段高亮显示为红色,事实上,我的意图是只有当他们即将提交但提供了与另一个表单相同的名称时,才会出现ValidationError。

我不明白为什么DJango在表单已经汇总的情况下运行clean((函数,即验证已经发生,数据已经提交

视图.py

def edit_keydef(request, id):
data = {'title': 'View or Edit Key Definition'}
template = 'generate_keys/edit_keydef.html'
keydef = get_object_or_404(KeyDefinition, pk=id)
if request.method == "POST":
keydetails_form_instance = KeyDefDetailsForm(request.POST, instance=keydef)
if 'Save' in request.POST:
if keydetails_form_instance.is_valid():
if keydetails_form_instance.cleaned_data['encoded_activation_key']:
activation_obj = Activation()
result = activation_obj.GenerateKey(keydef)
keydetails_form_instance.save()
return redirect('/key/edit/' + str(id))
else:
log.debug(keydetails_form_instance.errors)
if 'Generate' in request.POST:
if keydetails_form_instance.is_valid():
activation_obj = Activation()
result = activation_obj.GenerateKey(keydef)
if "error" in result:
data['error_msg'] = format_html(
'<p>Failed to generate activation key because:</p>'
+ '<p>'
+ str(result['error'])
+ '</p>'
)
else:
keydetails_form_instance.save()
return redirect('/key/edit/' + str(id))
else:
log.debug(keydetails_form_instance.errors)
else:
keydetails_form_instance = None
if not id:
keydetails_form_instance = KeyDefDetailsForm()
else:
# Retrieve a previously saved form.
try:
keydetails = KeyDefinition.objects.get(pk=id)
keydetails_form_instance = KeyDefDetailsForm(keydetails.to_dict(),
instance = keydetails)
except KeyDefinition.DoesNotExist as e:
return redirect('/record_does_not_exist')
# Form instance has been saved at this stage so update the variant list.
data['form'] = keydetails_form_instance
data['set_product_options_url'] = reverse_lazy('set_product_options', kwargs={'id':id})
return render(request, template, data)

型号.py

class KeyDefinition (models.Model) :
...

def clean (self) :

....

# ensure that each user can't have two keys with the same name
key_name_exists = KeyDefinition.objects.filter(key_name=self.key_name, developer_email=self.developer_email)
if key_name_exists:
raise ValidationError (
{'key_name' : ['This Key Name already exists']} 
)
class Meta:
verbose_name = "Key Definition"
unique_together = [['key_name', 'developer_email']]

表单.py

class KeyDefDetailsForm (ModelForm) :
def __init__(self, *args, **kwargs) :
super(ModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.fields['version'].widget.attrs['class'] = "major_minor"
def update_variants(self, keydef_obj):
self.fields.update({
'feature_variant': forms.ModelChoiceField(
widget = Select(),
queryset = FeatureVariant.objects.filter(product__feature_name=keydef_obj.feature),
required = False,
label = "Product"
)
})

def update_available_hosts(self, keydef_obj):
# only show hosts that have been created by this user
self.fields.update({
'available_hosts': forms.ModelChoiceField(
empty_label=None,
initial = AvailableHosts.objects.get(host_label=keydef_obj.host_label).id,
widget=Select(),
queryset = AvailableHosts.objects.filter(host_developer_email=keydef_obj.developer_email),
required = False,                
label = "Available Hosts"
)
}) 
class Meta :
model = KeyDefinition
fields = '__all__'
widgets = {
'customer_name' : TextInput(),
'host_method' : TextInput(),
'issue_date' : TextInput(attrs={'type':'date'}),
'expiry_date': TextInput(attrs={"type":"date"}),
'available_hosts' : Select(),
'country' : Select(),
'feature' : Select(),
'activation_request' : HiddenInput(),
'hostid_provision' : HiddenInput(),
}

KeyDefinition确实存在:正是您正在编辑的匹配项。验证表单时,clean()方法将始终运行。这就是为什么您应该排除该对象,因此使用:

class KeyDefinition(models.Model):
def clean(self):
# …
# ensure that each user can't have two keys with the same name
key_name_exists = (
KeyDefinition.objects.filter(
key_name=self.key_name, developer_email=self.developer_email
)
.exclude(pk=self.pk)
.exists()
)
if key_name_exists:
raise ValidationError({'key_name': ['This Key Name already exists']})
return super().clean()

因此,我们在这里用.exclude(pk=self.pk)排除我们自己的对象。


注意:使用.exists()[Django-doc]比检查QuerySet真实性更有效,因为这不会从查询集中加载记录,因此会最大限度地减少数据库之间使用的带宽以及Django/Python层。

最新更新