from django.db import models # Create your models here. # 建立一個圖書管理系統的模型 class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) # 8個有效數,兩個浮點 date = models.DateField() publish = models.ForeignKey("Publish", on_delete=models.CASCADE) authors = models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name
$ python3 manage.py makemigrations $ python3 manage.py migrate
from django.contrib import admin # Register your models here. from .models import * admin.site.register(Book) admin.site.register(Author) admin.site.register(Publish)
建立超級用戶:php
manage.py@formsDemo2 > createsuperuser Username (leave blank to use 'hqs'): yuan Email address: Warning: Password input may be echoed. Password: yuan1234 Warning: Password input may be echoed. Password (again): yuan1234 Superuser created successfully.
from django.contrib import admin from django.urls import path from django.conf.urls import url from app01 import views urlpatterns = [ path('admin/', admin.site.urls), url(r'^books/$', views.book), url(r'^books/add', views.addbook), url(r'^books/edit/(\d+)', views.editbook), ]
from django.shortcuts import render, redirect # Create your views here. from .models import * def book(request): book_list = Book.objects.all() return render(request, 'books.html', locals()) def addbook(request): if request.method == "POST": title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") publish_id = request.POST.get("publish_id") # getlist(): Return the list of values for the key. author_pk_list = request.POST.getlist("author_pk_list") # 取到用戶輸入的書籍信息後添加到數據庫Book表中 book_obj = Book.objects.create(title=title, price=price, date=date, publish_id=publish_id) # 直接綁定主鍵,將做者對象添加到這本書的做者集合中 book_obj.authors.add(*author_pk_list) return redirect("/books/") publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, "addbook.html", locals()) def editbook(request, edit_book_id): if request.method == "POST": title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") publish_id = request.POST.get("publish_id") # getlist(): Return the list of values for the key. author_pk_list = request.POST.getlist("author_pk_list") # 取到用戶輸入的書籍信息後更新到數據庫Book表中 book_obj = Book.objects.filter(edit_book_id).update(title=title, price=price, date=date, publish_id=publish_id) # 直接綁定主鍵,將做者對象更新到這本書的做者集合中 book_obj.authors.set(*author_pk_list) # set()先清空,再設置 return redirect("/books/") # 去數據庫中取出數據 edit_book = Book.objects.filter(pk=edit_book_id).first() publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, "editbook.html", locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="/books/add"><button>添加書籍</button></a> <hr> <table border="1"><!--border給表格加框--> {% for book in book_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> <td>{{ book.date|date:"Y-m-d" }}</td> <td>{{ book.publish.name }}</td> <td>{{ book.authors.all }}</td> <td><a href="/books/edit/{{ book.pk }}">編輯</a></td> </tr> {% endfor %} </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加頁面</h3> <form action="" method="post"> {% csrf_token %} <p>書籍名稱 <input type="text" name="title"></p> <p>價格 <input type="text" name="price"></p> <p>日期 <input type="date" name="date"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endfor %} </select> </p> <p>做者 {# multiple屬性設置多選 #} <select name="author_pk_list" id="" multiple> {% for author in author_list %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>編輯頁面</h3> <form action="" method="post"> {% csrf_token %} <p>書籍名稱 <input type="text" name="title" value="{{ edit_book.title }}"></p> <p>價格 <input type="text" name="price" value="{{ edit_book.price }}"></p> <p>日期 <input type="date" name="date" value="{{ edit_book.date|date:'Y-m-d' }}"></p> <p>出版社 <select name="publish_id" id=""> {% for publish in publish_list %} {% if edit_book.publish == publish %} {# 數據庫有記錄的顯示爲selected狀 #} <option selected value="{{ publish.pk }}">{{ publish.name }}</option> {% else %} {# 數據庫中沒有記錄的顯示爲普通狀態 #} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </p> <p>做者 {# multiple屬性設置多選 #} <select name="author_pk_list" id="" multiple> {% for author in author_list %} {# 判斷是不是數據庫中數的做者 #} {% if author in edit_book.authors.all %} <option selected value="{{ author.pk }}">{{ author.name }}</option> {% else %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit"> </form> </body> </html>
假設你想在你的網站上建立一個簡單的表單,以得到用戶的名字。你須要相似這樣的模板:html
<form action="/your-name/" method="post"> <label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name"> <input type="submit" value="OK"> </form>
這是一個很是簡單的表單。實際應用中,一個表單可能包含幾十上百個字段,其中大部分須要預填充,並且咱們預料到用戶未來回編輯-提交幾回才能完成操做。前端
咱們可能須要在表單提交以前,在瀏覽器端做一些驗證。咱們可能想使用很是複雜的字段,以容許用戶作相似從日曆中挑選日期這樣的事情,等等。python
這個時候,讓Django 來爲咱們完成大部分工做是很容易的。git
參考:正則表達式
https://www.cnblogs.com/yuanchenqi/articles/7614921.html
https://www.cnblogs.com/wupeiqi/articles/6144178.html數據庫
Form
類,只帶有三個普通字段from django import forms from django.forms import widgets class BookForm(forms.Form): # 三個普通字段類型 title = forms.CharField(max_length=32, label="書籍名稱") price = forms.DecimalField(max_digits=8, decimal_places=2, label="價格") date = forms.DateField(label="日期", widget=widgets.TextInput(attrs={"type": "date"}) # <input type="date" > )
注意:django
1)字段容許的最大長度經過max_length
定義。它完成兩件事情。首先,它在HTML 的<input>
上放置一個maxlength="100"
(這樣瀏覽器將在第一時間阻止用戶輸入多於這個數目的字符)。它還意味着當Django 收到瀏覽器發送過來的表單時,它將驗證數據的長度。小程序
2)Form
的實例具備一個is_valid()
方法,它爲全部的字段運行驗證的程序。當調用這個方法時,若是全部的字段都包含合法的數據,它將:瀏覽器
True
cleaned_data
屬性中。 3)每一個表單字段都有一個對應的Widget
類,它對應一個HTML 表單Widget
,例如<input type="text">
。
在大部分狀況下,字段都具備一個合理的默認Widget。例如,默認狀況下,CharField
具備一個TextInput Widget
,它在HTML 中生成一個<input type="text">
。
from django import forms from django.forms import widgets class BookForm(forms.Form): # 三個普通字段類型 title = forms.CharField(max_length=32, label="書籍名稱") price = forms.DecimalField(max_digits=8, decimal_places=2, label="價格") date = forms.DateField(label="日期", widget=widgets.TextInput(attrs={"type": "date"}) # <input type="date" > ) # 特殊字段類型 # ChoiceField渲染select標籤 # gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "其餘"))) # 出版社:渲染select標籤 # publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name")) publish = forms.ModelChoiceField(queryset=Publish.objects.all()) # 做者 authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
注意:
1)ChoiceField(field)渲染select標籤,通常在數據與數據庫不要緊的時候使用
publish = forms.ChoiceField(choices=Publish.objects.all().values_list("pk", "name"))
2)ModelChoiceField(ChoiceField)繼承ChoiceFiled,用如下方式改寫,由於傳遞的參數是queryset所以不須要使用values_list了。
queryset傳遞的值是主鍵值和對象,若是類中有設置__str__則取其中的值。
publish = forms.ModelChoiceField(queryset=Publish.objects.all())
3)ModelMultipleChoiceField(ModelChoiceField)繼承ModelChoiceField,與數據庫打交道且是多選時使用。
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
addbook視圖函數:
def addbook(request): if request.method == "POST": form = BookForm(request.POST) # 實例化BookForm if form.is_valid(): # 若是是合格的數據 print("clean_data", form.cleaned_data) # 輸出:clean_data {'title': '水滸傳', 'price': Decimal('88'), 'date': datetime.date(2014, 4, 20), # 'publish': <Publish: 蘋果出版社>, 'authors': <QuerySet [<Author: egon>]>} title = form.cleaned_data.get("title") price = form.cleaned_data.get("price") date = form.cleaned_data.get("date") publish = form.cleaned_data.get("publish") authors = form.cleaned_data.get("authors") # 取到用戶輸入的書籍信息後添加到數據庫Book表中 book_obj = Book.objects.create(title=title, price=price, date=date, publish=publish) # 將做者對象添加到這本書的做者集合中 book_obj.authors.add(*authors) return redirect("/books/") form = BookForm() # 實例化BookForm publish_list = Publish.objects.all() author_list = Author.objects.all() return render(request, "addbook.html", locals())
addbook.html:
<form action="" method="post" novalidate> {% csrf_token %} <div> {{ form.title.label }} {{ form.title }} </div> <div> {{ form.price.label }} {{ form.price }} </div> <div> {{ form.date.label }} {{ form.date }} </div> <input type="submit"> </form>
根據{{ form }}
,全部的表單字段和它們的屬性將經過Django 的模板語言拆分紅HTML 標記 。
form標籤novalidate屬性:novalidate 屬性規定當提交表單時不對其進行驗證。若是使用該屬性,則表單不會驗證表單的輸入。
Django 原生支持一個簡單易用的跨站請求僞造的防禦。當提交一個啓用CSRF 防禦的POST
表單時,你必須使用上面例子中的csrf_token
模板標籤。
完整的表單,第一次渲染時,效果以下:
<form action="" method="post"> <input type="hidden" name="csrfmiddlewaretoken" value="lSKaxqL7dD9gmNfhksqykU1ERnlhMYx5RrjiJ8E34lWibOcOGVw41aBzc4kcyati"> <div> <p>Title</p> <input type="text" name="title" maxlength="32" required="" id="id_title"> </div> <div> <p>Price</p> <input type="number" name="price" step="0.01" required="" id="id_price"> </div> <div> <p>Date</p> <input type="date" name="date" required="" id="id_date"> </div> <input type="submit"> </form>
經過{{ form.publish }}和{{ form.authors }}獲取出版社和做者信息。經過Django 的模板語言拆分紅HTML 標記。
初始addbook.html寫法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加頁面</h3> <form action="" method="post" novalidate> {% csrf_token %} <div> {{ form.title.label }} {{ form.title }} </div> <div> {{ form.price.label }} {{ form.price }} </div> <div> {{ form.date.label }} {{ form.date }} </div> <div> {{ form.publish.label }} {{ form.publish }} </div> <div> {{ form.authors.label }} {{ form.authors }} </div> <input type="submit"> </form> </body> </html>
addbook.html精簡後寫法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加頁面</h3> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} </div> {% endfor %} <input type="submit"> </form> </body> </html>
顯示效果:
views.py:
from django.forms import ModelForm class BookForm(ModelForm): class Meta: model = Book fields = "__all__" # 對全部字段轉換
在視圖函數中,定義一個類,好比就叫BookForm,這個類要繼承ModelForm,在這個類中再寫一個原類Meta(規定寫法,並注意首字母是大寫的)。
注意對全部字段轉換是寫字符串,其餘時候是寫列表:
fields = ["title", "price"]
改寫addbook視圖函數:
def addbook(request): form = BookForm() # 實例化BookForm return render(request, "addbook.html", locals())
頁面訪問解析效果:
def addbook(request): if request.method == "POST": form = BookForm(request.POST) # 實例化BookForm if form.is_valid(): # 若是是合格的數據 form.save() return redirect("/books/") form = BookForm() # 實例化BookForm return render(request, "addbook.html", locals()) def editbook(request, edit_book_id): edit_book = Book.objects.filter(pk=edit_book_id).first() if request.method=="POST": # 默認是create操做,若是是想update,須要添加一個instance參數把要編輯的對象傳遞過來 form = BookForm(request.POST, instance=edit_book) # 傳遞須要更新的對象 if form.is_valid(): form.save() return redirect("/books/") # 建立form對象,傳入參數就能夠顯示以前客戶寫入的值,ModelForm具有instance參數 form = BookForm(instance=edit_book) # 接收實例對象 return render(request, "editbook.html", locals())
注意:
能夠接收實例對象,僅對edit視圖作以下改寫,就能夠拿到客戶以前提交的信息。
def editbook(request, edit_book_id): # 去數據庫中取出數據 edit_book = Book.objects.filter(pk=edit_book_id).first() # 建立form對象,傳入參數就能夠顯示以前客戶寫入的值,ModelForm具有instance參數 form = BookForm(instance=edit_book) # 接收實例對象 return render(request, "editbook.html", locals())
顯示效果:
if request.method == "POST": form = BookForm(request.POST) # 實例化BookForm if form.is_valid(): # 若是是合格的數據 form.save() return redirect("/books/")
區別就在於一點:實例化form類的時候,是否傳遞instance參數。
若是不用ModelForm,編輯的時候要顯示以前的數據,還得挨個取一遍值,若是ModelForm,只須要加一個instance=obj(obj是要修改的數據庫的一條數據的對象)就能夠獲得一樣的效果
保存的時候要注意,必定要注意有這個對象(instance=obj),不然不知道更新哪個數據。默認狀況下是執行create操做,若是是想update,須要添加一個instance參數把要編輯的對象傳遞過來。
ModelForm用起來是很是方便的,好比增長修改之類的操做。可是也帶來額外很差的地方,model和form之間耦合了。
若是不耦合的話,form.save()方法也沒法直接提交保存。 可是耦合的話使用場景一般侷限用於小程序,寫大程序就最好不用了。
保存數據的時候不須要挨個取數據了,直接save一下,就完成了取數據生成記錄的操做。
form.model.objects.create(request.POST)
編輯功能的editbook視圖函數,不須要作任何變更,save一下就執行了更新操做
form = BookForm(request.POST, instance=edit_book) # 傳遞須要更新的對象 if form.is_valid(): form.save() # edit_book.update(request.POST)
因爲編輯和添加模板中的form標籤內的內容徹底同樣,將其拷貝出來放在新建立的form.html模板中:
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} </div> {% endfor %} <input type="submit"> </form>
在addbook.html和editbook.html中改寫以下:
<body> <h3>編輯頁面</h3> {% include 'form.html' %} </body>
注意:
(1){% include %} 標籤容許在(模板中)包含其它的模板的內容。 標籤的參數是所要包含的模板名稱,能夠是一個變量,也能夠是用單/雙引號硬編碼的字符串。
from django.forms import ModelForm from django.forms import widgets as wid # 由於重名,因此起個別名 wid_text = wid.TextInput(attrs={'class':'form-control'}) required_msg = {'required':'不能爲空'} class BookForm(ModelForm): class Meta: model = Book fields = "__all__" # 對全部字段轉換 labels = { "title": "書籍名稱", "price": "書籍價格", "date": "日期", "publish": "出版社", "authors": "做者" } # widgets用法,好比把輸入用戶名的input框給爲Textarea widgets = { # 這個是參數widgets "title": wid_text, "price": wid_text, "date": wid.TextInput(attrs={"class": "form-control", 'type': 'date'}), "publish": wid.Select(attrs={"class": "form-control"}), "authors": wid.SelectMultiple(attrs={"class": "form-control"}), } # error_messages用法: error_messages = { 'title': {'required': "用戶名不能爲空", }, 'price': {'required': "價格不能爲空", }, 'date': {'required': "日期不能爲空", 'invalid': "日期格式錯誤"}, 'publish': {'required': "出版社不能爲空", }, 'authors': {'required': "做者不能爲空", }, }
這是由於ModelForm有一個參數是widgets與之重名,因此須要給它一個別名:
from django.forms import widgets as wid # 由於重名,因此起個別名
在input標籤添加form-contral樣式,能夠考慮在後臺的widget裏面添加,好比這樣:
from django.forms import widgets as wid #由於重名,因此起個別名 widgets = { "name":wid.TextInput(attrs={'class':'form-control'}), "age":wid.NumberInput(attrs={'class':'form-control'}), "email":wid.EmailInput(attrs={'class':'form-control'}) }
固然也能夠在js中,找到全部的input框,加上這個樣式,也行。
error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} # error_messages用法: error_messages = { 'title': {'required': "用戶名不能爲空", }, 'price': {'required': "價格不能爲空", }, 'date': {'required': "日期不能爲空", 'invalid': "日期格式錯誤"}, 'publish': {'required': "出版社不能爲空", }, 'authors': {'required': "做者不能爲空", }, }
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} <small> <span class="pull-right text-danger has-error"> {{ field.errors.0 }} </span> </small> </div> {% endfor %} <input type="submit"> </form>
注意在模板中經過{{ field.errors.0 }}取到錯誤提示信息。.0表示只取第一條。視圖函數也須要作修改才能顯示錯誤信息:
def addbook(request): form = BookForm() # 實例化BookForm if request.method == "POST": form = BookForm(request.POST) # 實例化BookForm if form.is_valid(): # 若是是合格的數據 form.save() return redirect("/books/") # form = BookForm() # 實例化BookForm return render(request, "addbook.html", locals())
須要注意的是,要把form=BookForm()這一步移到最上方,不然校驗失敗返回的form對象就變成沒有值的form對象了,也能夠改寫爲下面更清晰的寫法:
def addbook(request): if request.method == "POST": form = BookForm(request.POST) # 實例化BookForm if form.is_valid(): # 若是是合格的數據 form.save() return redirect("/books/") else: # 檢驗失敗,不寫下面的語句,返回的form對象就變成沒有值的form對象了 return render(request, "addbook.html", locals()) form = BookForm() # 實例化BookForm return render(request, "addbook.html", locals())
顯示效果:
前端手寫一個form表單,後臺使用forms組件,進行校驗也是能夠的!!
注意: <p>名稱 <input type="text" name="title"></p> 和 title = forms.CharField()
views.py:
from django import forms class BookForms(forms.Form): title = forms.CharField() price = forms.FloatField() def addbook(request): form = BookForms() if request.method == 'POST': form = BookForms(request.POST) # form = BookForm({'title':'php','price':111,'xxx':'egon'}) if form.is_valid(): print('clean_data',form.cleaned_data) # clean_data {'title': '水滸傳', 'price': 123.0} else: print('error',form.errors) return render(request,'addbook.html',locals())
addbook.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>添加書籍</h3> <form action="" method="post" novalidate> {% csrf_token %} <p>名稱 <input type="text" name="title"></p> <p>價格 <input type="text" name="price"></p> <p>xxx <input type="text" name="xxx"></p> <input type="submit"> </form> <form action="" method="post" novalidate> {% csrf_token %} {{ form.as_p }} {{ form.as_table }} {{ form.as_ul }} <input type="submit"> </form> </body> </html>
Field required=True, 是否容許爲空 widget=None, HTML插件 label=None, 用於生成Label標籤或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標籤旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否能夠編輯 label_suffix=None Label內容後綴 CharField(Field) max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除用戶輸入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 總長度 decimal_places=None, 小數位長度 BaseTemporalField(Field) input_formats=None 時間格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定製正則表達式 max_length=None, 最大長度 min_length=None, 最小長度 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否容許空文件 ImageField(FileField) ... 注:須要PIL模塊,pip3 install Pillow 以上兩個字典使用時,須要注意兩點: - form表單中 enctype="multipart/form-data" - view函數中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默認select插件 label=None, Label內容 initial=None, 初始值 help_text='', 幫助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查詢數據庫中的數據 empty_label="---------", # 默認空顯示內容 to_field_name=None, # HTML中value的值對應的字段 limit_choices_to=None # ModelForm中對queryset二次篩選 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換 empty_value= '' 空值的默認值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 對選中的每個值進行一次轉換 empty_value= '' 空值的默認值 ComboField(Field) fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 容許文件 allow_folders=False, 容許文件夾 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 SlugField(CharField) 數字,字母,下劃線,減號(連字符) ... UUIDField(CharField) uuid類型 ...
TextInput(Input) NumberInput(TextInput) EmailInput(TextInput) URLInput(TextInput) PasswordInput(TextInput) HiddenInput(TextInput) Textarea(Widget) DateInput(DateTimeBaseInput) DateTimeInput(DateTimeBaseInput) TimeInput(DateTimeBaseInput) CheckboxInput Select NullBooleanSelect SelectMultiple RadioSelect CheckboxSelectMultiple FileInput ClearableFileInput MultipleHiddenInput SplitDateTimeWidget SplitHiddenDateTimeWidget SelectDateWidget
# 單radio,值爲字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 單radio,值爲字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 單select,值爲字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 單select,值爲字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多選select,值爲列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 單checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多選checkbox,值爲列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
Django 和其餘 Web 框架的 HTTP 處理的流程大體相同,Django 處理一個 Request 的過程是首先經過中間件,而後再經過默認的 URL 方式進行的。咱們能夠在 Middleware 這個地方把全部 Request 攔截住,用咱們本身的方式完成處理之後直接返回 Response。
請求協議格式:請求首行,請求頭,請求體!
響應協議格式:響應首行,響應頭,響應體!
1. 加載配置
Django 的配置都在 「Project/settings.py」 中定義,能夠是 Django 的配置,也能夠是自定義的配置,而且都經過 django.conf.settings 訪問,很是方便。
2. 啓動
最核心動做的是經過 django.core.management.commands.runfcgi 的 Command 來啓動,它運行 django.core.servers.fastcgi 中的 runfastcgi,runfastcgi 使用了 flup 的 WSGIServer 來啓動 fastcgi 。而 WSGIServer 中攜帶了 django.core.handlers.wsgi 的 WSGIHandler 類的一個實例,經過 WSGIHandler 來處理由 Web 服務器(好比 Apache,Lighttpd 等)傳過來的請求,此時纔是真正進入 Django 的世界。
3. 處理 Request
當有 HTTP 請求來時,WSGIHandler 就開始工做了,它從 BaseHandler 繼承而來。WSGIHandler 爲每一個請求建立一個 WSGIRequest 實例,而 WSGIRequest 是從 http.HttpRequest 繼承而來。接下來就開始建立 Response 了。
4. 建立 Response
BaseHandler 的 get_response 方法就是根據 request 建立 response,而具體生成 response 的動做就是執行 urls.py 中對應的view函數了,這也是 Django 能夠處理「友好 URL 」的關鍵步驟,每一個這樣的函數都要返回一個 Response 實例。此時通常的作法是經過 loader 加載 template 並生成頁面內容,其中重要的就是經過 ORM 技術從數據庫中取出數據,並渲染到 Template 中,從而生成具體的頁面了。
5. 處理 Response
Django 返回 Response 給 flup,flup 就取出 Response 的內容返回給 Web 服務器,由後者返回給瀏覽器。
總之,Django 在 fastcgi 中主要作了兩件事:處理 Request 和建立 Response,而它們對應的核心就是「 urls 分析」、「模板技術」和「 ORM 技術」。
如圖所示,一個 HTTP 請求,首先被轉化成一個 HttpRequest 對象,而後該對象被傳遞給 Request 中間件處理,若是該中間件返回了Response,則直接傳遞給 Response 中間件作收尾處理。不然的話 Request 中間件將訪問 URL 配置,肯定哪一個 view 來處理,在肯定了哪一個 view 要執行,可是尚未執行該 view 的時候,系統會把 request 傳遞給 view 中間件處理器進行處理,若是該中間件返回了 Response,那麼該 Response 直接被傳遞給 Response 中間件進行後續處理,不然將執行肯定的 view 函數處理並返回 Response,在這個過程當中若是引起了異常並拋出,會被 Exception 中間件處理器進行處理。