我有一个非常简单的基于类的视图:
在views.py中:
class IncidentEdit(UpdateView):
model=Incident
fields = visible_field_list
sucess_url = '/status'
按原样正常工作。我已关联CreateView
,DeleteView
等。我可以创建编辑和删除记录。现在要微调项目,我需要添加字段验证。
我的问题:在基于'model='
而不是'form='
的视图时,我在哪里放置基本验证码?
我可以更改所有内容以使用基于表单的视图,但整个想法是保持简单并且它有效,我只是没有表单验证,除了基本的' Field Required'在模型声明中定义的类型验证。
例如, 我需要确保一个字段等于另外两个字段的总和。喜欢,
ClassRoomTotal = NumBoys + NumGirls
如果总和与总数不匹配,则为validation error
字段提出ClassRoomTotal
。
提前致谢。
我知道这是一个简单的答案。
建议如,"您不能这样做,您必须使用form=IncidentForm
并定义表单类。"会有所帮助。
答案 0 :(得分:10)
class IncidentEdit(UpdateView):
...
def form_valid(self, form):
if form.cleaned_data['email'] in \
[i.email for i in Incident.objects.exclude(id=get_object().id)]:
# Assume incident have email and it should be unique !!
form.add_error('email', 'Incident with this email already exist')
return self.form_invalid(form)
return super(IncidentEdit, self).form_valid(form)
另外,希望此链接有用。 http://ccbv.co.uk/projects/Django/1.7/django.views.generic.edit/UpdateView/
答案 1 :(得分:4)
那么,
你不能这样做,你必须使用
form = IncidentForm
或者至少它是最简单的解决方案。
请注意,您必须使用form_class = IncidentForm
,而不是form = IncidentForm
并保留model = Incident
。
我没有看到使用ModelForm
作为会增加项目复杂性的东西,这正是他们的用例。另一种方式是让事情变得复杂。
可以这么简单:
class IncidentForm(ModelForm):
class Meta:
model = Incident
# Define fields you want here, it is best practice not to use '__all__'
fields = [...]
def clean(self):
cleaned_data = super(IncidentForm, self).clean()
field_1 = cleaned_data.get('field_1')
field_2 = cleaned_data.get('field_2')
field_3 = cleaned_data.get('field_3')
# Values may be None if the fields did not pass previous validations.
if field_1 is not None and field_2 is not None and field_3 is not None:
# If fields have values, perform validation:
if not field_3 == field_1 + field_2:
# Use None as the first parameter to make it a non-field error.
# If you feel is related to a field, use this field's name.
self.add_error(None, ValidationError('field_3 must be equal to the sum of field_1 and filed_2'))
# Required only if Django version < 1.7 :
return cleaned_data
class IncidentEdit(UpdateView):
model = Incident
form_class = IncidentForm
fields = visible_field_list
success_url = '/status'
答案 2 :(得分:0)
同样的问题让我感到困惑,非常感谢aumo和Vinayak因为他们的答案给了我太多的启发!
作为初学者,我总是尝试直接使用“基于模型+类的视图+模板”结构来避免我的应用程序失控。
与CBV中覆盖form_valid函数的行为相同(由Vinayak回答),通过自定义Mixin类来封闭函数可能看起来更好。我的代码asf(基于django版本2.0):
# models.py
class Incident(models.Model):
numboys = models.SmallIntegerField(default=0)
numgirls = models.SmallIntegerField(default=0)
classttl = models.SmallIntegerField(default=0)
# views.py
def retunTestPassedResp(request):
return HttpResponse()
class NumValidationMixin:
def form_valid(self, form):
data = self.request.POST
boys = data.get('numboys')
girls = data.get('numgirls')
ttl = data.get('classttl')
if boys and girls and ttl:
if int(ttl) == int(boys) + int(girls):
return super().form_valid(form)
# use form.errors to add the error msg as a dictonary
form.errors['input invalid'] = '%s + %s not equal %s'%(boys, girls, ttl)
form.errors['input invalid'] = 'losing input with boys or other'
return self.form_invalid(form)
class UpdateIncident(NumValidationMixin, UpdateView):
model = Incident
fields = ['numboys', 'numgirls', 'classttl']
success_url = reverse_lazy('test-passed')
# templates/.../Incident_form.html
[...]
<body>
{{form}}
{% if form.errors %}
<p>get error</p>
{{form.errors}}
{% endif %}
</body>
我也进行了单元测试,并且通过了。
# tests.py
class IncidentUpdateTest(TestCase):
def setUp(self):
Incident.objects.create()
def test_can_update_with_right_data(self):
[...]
def test_invalid_error_with_illegal_post(self):
response = self.client.post(
reverse('update-incident', args=(1,)),
data={'numboys': '1', 'numgirls': '1', 'classttl': '3'}
)
self.assertEqual(Incident.objects.first().classttl, 0)
# testing response page showing error msg
self.assertContains(response, 'not equal')
有关更精确的代码示例和解释,请参阅 django document。
我希望这个答案可以帮助那些像我一样的初学者和自学朋友。