眾所周知,django.forms
極其強大,不少的框架也借鑑了這個模式,如Scrapy
。在表單驗證時,django.forms
是一絕,也是物件導向的經典表現。但要用它來渲染表單那就不好玩了,除非寫框架。本文章主要縷一縷如何使用django.forms來做表單驗證。
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=50, verbose_name='標題')
content = models.TextField(verbose_name='內容')
create_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
from django.forms import ModelForm
from django import forms
from . models import Article
from django.core.exceptions import ValidationError
class ArticleForm(ModelForm):
class Meta:
model = Article
exclude = ['id']
def clean(self):
cleaned_data = super().clean()
title = cleaned_data.get('title')
if 'My' not in title:
raise ValidationError('標題中必須包含My字樣', code='title')
def add(request):
if request.method == 'GET':
return render(request, 'add.html')
else:
form = ArticleForm(request.POST)
# 主要了解的是表單的驗證
if form.is_valid():
form.save()
return HttpResponseRedirect('/show/')
else:
form.errors.as_data() # {'__all__': [ValidationError(['標題中必須包含My字樣'])]}
form.errors.get_context() # {'errors': dict_items([('__all__', ['標題中必須包含My字樣'])]), 'error_class': 'errorlist'}
d = form.errors.get_json_data() # {'__all__': [{'message': '標題中必須包含My字樣', 'code': 'title'}]}
return HttpResponse(d.get('__all__'))
如果是在admin中使用ModelForm的驗證,那也是非常方便的,如果我們要在使用者的前端響應中使用表單驗證,且又不通過django.forms渲染的表單來傳遞驗證結果,則需要看看原始碼:
ModelForm.errors
。errors
是ErrorDict()
的範例,ErrorDict
原始碼:
class ErrorDict(dict, RenderableErrorMixin):
"""
A collection of errors that knows how to display itself in various formats.
The dictionary keys are the field names, and the values are the errors.
"""
template_name = "django/forms/errors/dict/default.html"
template_name_text = "django/forms/errors/dict/text.txt"
template_name_ul = "django/forms/errors/dict/ul.html"
def __init__(self, *args, renderer=None, **kwargs):
super().__init__(*args, **kwargs)
self.renderer = renderer or get_default_renderer()
def as_data(self):
return {f: e.as_data() for f, e in self.items()}
def get_json_data(self, escape_html=False):
return {f: e.get_json_data(escape_html) for f, e in self.items()}
def get_context(self):
return {
"errors": self.items(),
"error_class": "errorlist",
}
三個方法返回的都是字典,但資料結構不同,可以看情況而定。值得注意的是,在ArticleForm
中,raise ValidationError時,如果code傳入引數時,它將會在get_context()
中顯式體現出來。
1、掌握這個原理,傳統的全棧開發可以節省更多的時間。
2、多看原始碼