前言:css
爲何要用form去驗證呢?html
咱們提交的是form表單,在看前端源碼時若是檢查到POST URL及咱們提交的字段,若是沒有驗證咱們是否能夠直接POST數據到URL,後臺並無進行校驗,直接處理,那樣會不會對咱們系統產生影響?答案是確定的,FORM的做用就是起到必定的數據保護做用加一層校驗將不合法數據丟棄前端
form表單補充,select框python
#!/usr/bin/env python # -*- coding: utf-8 -*- import re from django import forms from django.core.exceptions import ValidationError def phone_validate(value): phone_re = re.compile(r'^(13[0-9]|15[012356789]|17[0678]|18[0-9]|14[57])[0-9]{8}$') if not phone_re.match(value): raise ValidationError('手機號碼格式錯誤') class TestForm(forms.Form): user_type_choice = ( (0, u'普通用戶'), (1, u'管理員'), ) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, attrs={'class': "form-control"}))
注:mysql
widget 生成前端展現 .SELECT選擇下拉框,attrs屬性class前端顯示類web
生成的表單類中將具備和指定的模型字段對應的表單字段,順序爲fields 屬性中指定的順序。sql
Form field | |
---|---|
AutoField | Not represented in the form |
BigIntegerField | IntegerField with min_value set to -9223372036854775808 and max_value set to 9223372036854775807. |
BooleanField | BooleanField |
CharField | CharField with max_length set to the model field’s max_length |
CommaSeparatedIntegerField | CharField |
DateField | DateField |
DateTimeField | DateTimeField |
DecimalField | DecimalField |
EmailField | EmailField |
FileField | FileField |
FilePathField | FilePathField |
FloatField | FloatField |
ForeignKey | ModelChoiceField (see below) |
ImageField | ImageField |
IntegerField | IntegerField |
IPAddressField | IPAddressField |
GenericIPAddressField | GenericIPAddressField |
ManyToManyField | ModelMultipleChoiceField (see below) |
NullBooleanField | NullBooleanField |
PositiveIntegerField | IntegerField |
PositiveSmallIntegerField | IntegerField |
SlugField | SlugField |
SmallIntegerField | IntegerField |
TextField | CharField with widget=forms.Textarea |
TimeField | TimeField |
URLField | URLField |
完整示例:數據庫
1. 數據模型django
建立:bootstrap
1 from django.db import models 2 3 4 # Create your models here. 5 6 7 class Publisher(models.Model): 8 name = models.CharField(max_length=30, unique=True) 9 address = models.CharField(max_length=50) 10 city = models.CharField(max_length=60) 11 state_province = models.CharField(max_length=60) 12 country = models.CharField(max_length=60) 13 website = models.URLField() 14 15 def __str__(self): 16 return self.name 17 18 19 class Author(models.Model): 20 first_name = models.CharField(max_length=32) 21 last_name = models.CharField(max_length=32) 22 email = models.EmailField() 23 24 def __str__(self): 25 name = self.first_name + self.last_name 26 return name 27 28 29 class Book(models.Model): 30 name = models.CharField(max_length=128) 31 authors = models.ManyToManyField(Author) 32 publisher = models.ForeignKey(Publisher) 33 publish_date = models.DateField() 34 35 def __str__(self): 36 return self.authors
1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.mysql', 4 'NAME': os.environ.get("MYSQL_NAME", 'modelform'), 5 'USER': os.environ.get("MYSQL_USER", 'root'), 6 'PASSWORD': os.environ.get("MYSQL_PASSWD", 'password'), 7 'HOST': os.environ.get("MYSQL_HOST", '192.168.1.102'), 8 'PORT': os.environ.get("MYSQL_PORT", 3306), 9 } 10 }
生成:
python manage.py makemigrations
python manage.py migrate
只是舉例詳見參考
https://docs.djangoproject.com/en/1.11/topics/db/models/
http://www.cnblogs.com/jl-bai/p/5798860.html
注:
報錯:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'
緣由:無mysql客戶端
解決方案:
在project 的root_dir 下__init__文件中寫入
import pymysql pymysql.install_as_MySQLdb()
(一)數據前端展現
2. 後臺VIEWS
from django.views.generic.base import TemplateView from app01.forms import BookModelForm class Index(TemplateView): template_name = "index.html" def get(self, request, *args, **kwargs): form = BookModelForm() return self.render_to_response(context={"form": form})
3. ModelForm
#!/usr/bin/env python # -*- coding: utf-8 -*- from django import forms from app01.models import Book class BookModelForm(forms.ModelForm): class Meta: model = Book fields = ['name', 'authors', 'publish_date'] widgets = { 'name': forms.TextInput(attrs={'class': "form-control"}), 'authors': forms.Select(attrs={'class': "form-control"}), 'publish_date': forms.DateInput(attrs={'class': "form-control", 'placeholder': "YYYY-MM-DD"}) }
4. 前端展現
{% load staticfiles %} {% load i18n admin_static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>django model form</title> <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet"/> </head> <body> <div style="width: 980px;margin: 0 auto"> <div class="col-lg-6"> <form action="{% url 'index' %}" method="POST">{% csrf_token %} {{ form }} <input class="btn btn-primary m-r-5 m-b-5" type="submit" value="提 交"> </form> </div> </div> </body> </html>
訪問:
1. 驗證模型
與普通的表單驗證類型相似,模型表單的驗證在調用is_valid() 或訪問errors 屬性時隱式調用,或者經過full_clean() 顯式調用,儘管在實際應用中你將不多使用後一種方法。
模型的驗證(Model.full_clean())在表單驗證這一步的內部觸發,緊跟在表單的clean() 方法調用以後。
警告
Clean 過程會以各類方式修改傳遞給模型表單構造函數的模型實例。例如,模型的日期字段將轉換成日期對象。驗證失敗可能致使模型實例處於不一致的狀態,因此不建議從新使用它。
能夠重寫模型表單的clean() 來提供額外的驗證,方法和普通的表單同樣。
模型表單實例包含一個instance 屬性,表示與它綁定的模型實例。
警告
ModelForm.clean() 方法設置一個標識符, 使得模型驗證 這一步驗證標記爲unique、 unique_together 或unique_for_date|month|year 的模型字段的惟一性。
若是你須要覆蓋clean() 方法並維持這個驗證行爲,你必須調用父類的clean() 方法。
與django form表單驗證 中定義clean方法相同
表單字段級別或表單級別的錯誤信息永遠比模型字段級別的錯誤信息優先。
模型字段的錯誤信息只用於模型驗證步驟引起ValidationError 的時候,且不會有對應的表單級別的錯誤信息。
每一個ModelForm還具備一個save() 方法。這個方法根據表單綁定的數據建立並保存數據庫對象。模型表單的子類能夠用關鍵字參數instance 接收一個已經存在的模型實例;若是提供,save() 將更新這個實例。若是沒有提供,save() 將建立模型的一個新實例:
1 class Index(TemplateView): 2 template_name = "index.html" 3 4 def get(self, request, *args, **kwargs): 5 form = BookModelForm() 6 return self.render_to_response(context={"form": form}) 7 8 def post(self,request): 9 form = BookModelForm() 10 if form.is_valid(): 11 form.save() 12 return redirect("home") 13 return self.render_to_response(context={"form": form})
若是表單沒有驗證,save() 調用將經過檢查form.errors 來進行驗證。若是表單中的數據不合法,將引起ValueError —— 例如,若是form.errors 爲True。
class BookModelForm(forms.ModelForm): class Meta: model = Book fields = ['name', 'authors', 'publish_date'] widgets = { 'name': forms.TextInput(attrs={'class': "form-control"}), 'authors': forms.Select(attrs={'class': "form-control"}), 'publish_date': forms.DateInput(attrs={'class': "form-control", 'placeholder': "YYYY-MM-DD"}) }
在ModelForm中咱們一般使用fields 屬性顯式設置全部將要在表單中編輯的字段,若是不這樣作,當表單不當心容許用戶設置某些特定的字段,特別是有的字段添加到模型中的時候,將很容易致使安全問題。
另一種方式是自動包含全部的字段,或者排除某些字段。這種基本方式的安全性要差不少,並且已經致使大型的網站受到嚴重的利用。
class BookModelForm(forms.ModelForm): class Meta: model = Book fields = '__all__'
class BookModelForm(forms.ModelForm): class Meta: model = Book exclude = ()
exclude = () 與 fields = '__all__' 達到效果相同選取全部字段
若是 exclude=['name'],那麼排除「name"字段其餘字段都會顯示
若是一個模型在同一個模型中包含多個外鍵,則須要使用fk_name手動解決歧義。例如,考慮如下模型:
class Friendship(models.Model): from_friend = models.ForeignKey(Friend, related_name='from_friends') to_friend = models.ForeignKey(Friend, related_name='friends') length_in_months = models.IntegerField()
要解決此問題,您可使用fk_name到inlineformset_factory()
FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name='from_friend', ... fields=('to_friend', 'length_in_months'))
具體參考:
https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/