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 中间件处理器进行处理。