用来校验所有的数据
Django forms
是一个强大的组件, 可以用来校验python的 dict object
通常情况下用来校验 但不限于 HTTP request
POST 请求,
实例 读取CSV数据保存
import csv
from django.utils.six import StringIO
from django import forms
from .models import Purchase, Seller
class PurchaseForm(forms.ModelForm):
class Meta:
model = Purchase
def clean_seller(self):
seller = self.cleaned_data['seller']
try:
Seller.objects.get(name=seller)
except Seller.DoesNotExist:
msg = '{0} does not exist in purchase #{1}.'.format( seller,
self.cleaned_data['purchase_number']
)
raise forms.ValidationError(msg)
return seller
def add_csv_purchases(rows):
rows = StringIO.StringIO(rows)
records_added = 0
errors = []
# Generate a dict per row, with the first CSV row being the keys.
for row in csv.DictReader(rows, delimiter=','):
# Bind the row data to the PurchaseForm.
form = PurchaseForm(row)
# Check to see if the row data is valid.
if form.is_valid():
# Row data is valid so save the record.
form.save()
records_added += 1
else:
errors.append(form.errors)
return records_added, errors
在HTML中使用 POST
方法提交表单
<form action="{ url 'flavor_add' }" method="POST">
在 HTTP form 提交过程 使用 CSRF Protection
保护
当然在开发API时, API的请求 每次都是登录,验证的, 基于 HTTP cookie的验证不太现实, 可能不需要 CSRF
- 通过
Ajax
发送数据也需要CSRF protection
需要设置 X-CSRFToken
的 HTTP header 请求头
Cross Site Request Forgery protection
Understand How to Add Django Form Instance Attributes
给 Form 对象增加属性
from django import forms
from .models import Taster
class TasterForm(forms.ModelForm):
class Meta:
model = Taster
def __init__(self, *args, **kwargs):
# set the user as an attribute of the form
self.user = kwargs.pop('user')
super(TasterForm, self).__init__(*args, **kwargs)
视图
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import UpdateView
from .forms import TasterForm
from .models import Taster
class TasterUpdateView(LoginRequiredMixin, UpdateView):
model = Taster
form_class = TasterForm
success_url = '/someplace/'
def get_form_kwargs(self):
"""This method is what injects forms with keyword arguments."""
# grab the current set of form #kwargs
kwargs = super(TasterUpdateView, self).get_form_kwargs()
# Update the kwargs with the user_id
kwargs['user'] = self.request.user
return kwargs
理解 form validation
是怎么实现的
调用 form.is_valid()
开始, 会有如下的操作流程
1 If the form has bound data, form.is_valid() calls the form.full_clean() method.
2 form.full_clean() iterates through the form fields and each field validates itself:
a Data coming into the field is coerced into Python via the to_python() method or raises
a ValidationError.
b Data is validated against field-specific rules, including custom validators. Failure raises a
ValidationError.
c If there are any custom clean_<field>() methods in the form, they are called at this
time.
3 form.full_clean() executes the form.clean() method.
4 If it’s a ModelForm instance, form._post_clean() does the following:
a Sets ModelForm data to the Model instance, regardless of whether form.is_valid()
is True or False.
b Calls the model’s clean() method. For reference, saving a model instance through the
ORM does not call the model’s clean() method.
-
ModelForm
数据先传给Form
对象 然后是Model
对象1 First, form data is saved to the form instance. 2 Later, form data is saved to the model instance.
保存验证失败的数据
# core/models.py
from django.db import models
class ModelFormFailureHistory(models.Model):
form_data = models.TextField()
model_data = models.TextField()
# flavors/views.py
import json
from django.contrib import messages
from django.core import serializers
from core.models import ModelFormFailureHistory
class FlavorActionMixin:
@property
def success_msg(self):
return NotImplemented
def form_valid(self, form):
messages.info(self.request, self.success_msg)
return super(FlavorActionMixin, self).form_valid(form)
def form_invalid(self, form):
"""Save invalid form and model data for later reference."""
form_data = json.dumps(form.cleaned_data)
# Serialize the form.instance
model_data = serializers.serialize('json', [form.instance])
# Strip away leading and ending bracket leaving only a dict
model_data = model_data[1:-1]
ModelFormFailureHistory.objects.create(
form_data=form_data,
model_data=model_data
)
return super(FlavorActionMixin,
self).form_invalid(form)
增加验证错误信息 Add Errors to Forms With Form.add_error()
from django import forms
class IceCreamReviewForm(forms.Form):
# Rest of tester form goes here
...
def clean(self):
cleaned_data = super(TasterForm, self).clean()
flavor = cleaned_data.get('flavor')
age = cleaned_data.get('age')
if flavor == 'coffee' and age < 3:
# Record errors that will be displayed later.
msg = 'Coffee Ice Cream is not for Babies.'
self.add_error('flavor', msg)
self.add_error('age', msg)
# Always return the full collection of cleaned data.
return cleaned_data