我有一个要更新MyModel对象的表单。在模型上,存在一个unique_together约束,即fieldA和fieldB。在clean方法的表单中,我检查此唯一约束。
由于某些原因,我必须在更新中将fieldA显示为只读。因此,fieldA没有通过。我的问题是,如果表单未通过验证,则会重新显示该表单,但是我丢失了fieldA中的值。
我试图重置cleaned_data ['fieldA'],但是它不起作用。
知道要更改什么吗?
Forms.py
class MyModelUpdateForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.fields['fieldA'].widget.attrs['readonly'] = True
self.fields['fieldA'].widget.attrs['disabled'] = True
def clean(self):
cleaned_data = self.cleaned_data
fieldA= self.instance.fieldA
fieldB = cleaned_data.get("fieldB")
if MyModel.objects.filter(fieldA=fieldA, fieldB=fieldB).count() > 0:
#try to reset fieldA, since it is not passed through, since it is disabled
cleaned_data['fieldA'] = fieldA.pk #does not work
raise forms.ValidationError('some unique validation error')
return cleaned_data
Views.py:
myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)
if request.method == 'POST':
model_form = MyModelUpdateForm(request.POST, instance=myModelobject )
if model_form .is_valid():
....
最佳答案
对于表格的工作原理,我感到很有趣,并想出了多种解决方案,仅此而已。
由于禁用的是窗口小部件而不是字段,因此就表单而言,它始终不会为fieldA接收任何内容,并且始终会导致验证失败。
在clean()方法中尝试某些操作对无效表单无济于事,因为clean()
数据用于处理。
看起来用于HTML显示的表单提取数据的方式是field.data
,这是对field.widget.value_from_datadict(POST, FILES, field_name)
的调用,因此它将始终查看您的POST数据。
所以我认为您有一些选择。破解request.POST
,破解内部表单POST数据或破解value_from_datadict
。
破解request.POST
:直截了当,很有意义。
myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)
if request.method == 'POST':
POST = request.POST.copy()
POST['fieldA'] = myModelobject.fieldA
model_form = MyModelUpdateForm(POST, instance=myModelobject )
if model_form .is_valid():
# ...
入侵内部字典:
def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.data.update({ 'fieldA': self.instance.fieldA })
黑客
value_from_datadict
:有点荒谬,但是说明了您可以从源代码中学习到什么def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name
在这里学到了一些很酷的东西:)希望对您有所帮助。