一、原生form实现书城增删改查

1、构建模型并完成数据库迁移

(1)构建书城模型

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

models.py

(2)数据库迁移

$ python3 manage.py makemigrations
$ python3 manage.py migrate

2、运用admin模块录入数据

from django.contrib import admin

# Register your models here.
from .models import * admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Publish)

admin.py

  创建超级用户:

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.

3、录入作者、出版社、书籍信息

  

4、代码

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),
]

urls.py

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())

views.py

<!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=""><!--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>

books.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>

addbock.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>

5、显示效果

  

  

6、构建表单总结

  假设你想在你的网站上创建一个简单的表单,以获得用户的名字。你需要类似这样的模板:

<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>

  这是一个非常简单的表单。实际应用中,一个表单可能包含几十上百个字段,其中大部分需要预填充,而且我们预料到用户将来回编辑-提交几次才能完成操作。

  我们可能需要在表单提交之前,在浏览器端作一些验证。我们可能想使用非常复杂的字段,以允许用户做类似从日历中挑选日期这样的事情,等等。

  这个时候,让Django 来为我们完成大部分工作是很容易的。

二、利用forms组件实现

参考:

  https://www.cnblogs.com/yuanchenqi/articles/7614921.html 
  https://www.cnblogs.com/wupeiqi/articles/6144178.html

1、视图中引入forms组件设计Form类

(1)定义一个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" >
)

注意:

  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">

(2)在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" >
)
# 特殊字段类型
# 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())

2、视图

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())

3、模板

(1)form类只含有三个普通字段

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>

(2)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>

  显示效果:

  

三、引入ModelForm组件进一步改写

1、引入ModelForm组件改写BookForm类

  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())

  页面访问解析效果:

  

2、修改添加和编辑视图,处理post请求

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())

注意:

(1)ModelForm的instance参数

  可以接收实例对象,仅对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())

  显示效果:

  

(2)处理POST请求,添加和编辑操作代码

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参数把要编辑的对象传递过来。

(3)model和form之间耦合

  ModelForm用起来是非常方便的,比如增加修改之类的操作。但是也带来额外不好的地方,model和form之间耦合了。

  如果不耦合的话,form.save()方法也无法直接提交保存。 但是耦合的话使用场景通常局限用于小程序,写大程序就最好不用了。

(4)添加记录的方法——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)

3、模板改写

  由于编辑和添加模板中的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 %} 标签允许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。

4、修改BookForm类,利用元类属性设置优化渲染

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': "作者不能为空", },
}

(1)导入widgets模块用法

  这是因为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框,加上这个样式,也行。

(2)使用error_messages参数修改错误提示

error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
# error_messages用法:
error_messages = {
'title': {'required': "用户名不能为空", },
'price': {'required': "价格不能为空", },
'date': {'required': "日期不能为空", 'invalid': "日期格式错误"},
'publish': {'required': "出版社不能为空", },
'authors': {'required': "作者不能为空", },
}

5、修改form.html模板和addbook视图函数,添加错误信息显示

<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组件

  前端手写一个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>

五、modelform详解

Django之Form组件

Django-组件拾遗

六、form组件补充

1、Django内置字段如下

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类型
...

2、Django内置插件

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

3、常用选择插件

# 单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请求流程

  Django 和其他 Web 框架的 HTTP 处理的流程大致相同,Django 处理一个 Request 的过程是首先通过中间件,然后再通过默认的 URL 方式进行的。我们可以在 Middleware 这个地方把所有 Request 拦截住,用我们自己的方式完成处理以后直接返回 Response。

  

1、http协议

请求协议格式:请求首行,请求头,请求体!
响应协议格式:响应首行,响应头,响应体!

2、HTTP请求处理流程

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 技术”。

3、流程图说明

  如图所示,一个 HTTP 请求,首先被转化成一个 HttpRequest 对象,然后该对象被传递给 Request 中间件处理,如果该中间件返回了Response,则直接传递给 Response 中间件做收尾处理。否则的话 Request 中间件将访问 URL 配置,确定哪个 view 来处理,在确定了哪个 view 要执行,但是还没有执行该 view 的时候,系统会把 request 传递给 view 中间件处理器进行处理,如果该中间件返回了 Response,那么该 Response 直接被传递给 Response 中间件进行后续处理,否则将执行确定的 view 函数处理并返回 Response,在这个过程中如果引发了异常并抛出,会被 Exception 中间件处理器进行处理。

Django——form组件和ModelForm的更多相关文章

  1. 6月28日 Django form组件 和 modelform组件

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  2. Django框架11 /form组件、modelForm组件

    Django框架11 /form组件.modelForm组件 目录 Django框架11 /form组件.modelForm组件 1. form组件介绍 2. form常用字段与插件 3. form所 ...

  3. django Form组件

    django Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建 ...

  4. 9.24 Django Form组件

    2018-9-23 20:10:04 这两天优化了自己图书管理系统 github 连接:https://github.com/TrueNewBee/pythonDemo 顺便整理了博客,写了好多总结, ...

  5. python 终极篇 --- form组件 与 modelForm

                                                           form组件                                       ...

  6. Django—Form组件

    Django From简介 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比 ...

  7. django form组件 cookies,session

    django form组件 渲染标签  就是组件里面的字段在前端展示叫做渲染标签 校验数据  用户输入的数据提交给后端组件叫做校验数据 forms组件中定义的字段都是必须传值的(required=Tr ...

  8. Python Web框架篇:Django Form组件

    Form简介 在HTTP中,表单(form标签),是用来提交数据的,其action属性说明了其传输数据的方法:如何传.如何接收. 访问网站时,表单可以实现客户端与服务器之间的通信.例如查询,就用到了表 ...

  9. Web框架django[Form]组件

    新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建Form类 # 创 ...

随机推荐

  1. 如何离线Windows server 2008R2 激活教程?

    服务器离线激活,可是费了老大劲了,不过最后还不是离线激活,还必须联网,也或许你运气好,不联网也能激活. 如果由于种种原因不能有线的话,那就可以试试这种方法了. 1.首先,开启无线LAN服务.(不会开启 ...

  2. MongDB from execCommand not master

    count failed: not master{ , "errmsg" : "not master" } at src/mongo/shell/query.j ...

  3. 关于 Linq to EF 的内存泄漏问题

    查到一些解决方案:             1, http://www.codethinked.com/keep-your-iqueryable-in-check 自定义常用方法,屏蔽IQuery功能 ...

  4. JS 命名规范

    JS的命名规则和规范 规则 - 必须遵守的,不遵守会报错 由字母.数字.下划线.$符号组成,不能以数字开头 不能是关键字和保留字,例如:for.while. 区分大小写 规范 - 建议遵守的,不遵守不 ...

  5. jenkins安装maven工具

    下载maven工具,然后解压到/usr/local下面 然后在jenkins上面添加maven工具.指定他的设置配置文件(全局) 指定maven的目录位置 应用保存即可 !!! 虽然maven安装简单 ...

  6. GTF/GFF文件的差异及其相互转换

    我们在做生物分析的时候,经常会碰到GFF格式的文件以及GTF格式的注释文件.他们有着相似的名字,甚至连内容都极为相似~那么,他们究竟差在哪里呢? GFF全称为general feature forma ...

  7. LeetCode记录之9——Palindrome Number

    LeetCode真是个好东西,本来闲了一下午不想看书,感觉太荒废时间了就来刷一道题.能力有限,先把easy的题目给刷完. Determine whether an integer is a palin ...

  8. docker 镜像编译

    docker为我们提供了,包含源码的镜像, 可以要从docker hub上下载镜像来编译docker源码. 1.  docker pull docker-dev:v1.2.0,其他版本就到docker ...

  9. SQL异常捕获

    直接上代码: GO BEGIN TRY DECLARE @res INT SET @res=1/0 PRINT 'no error' END TRY BEGIN CATCH PRINT 'Error ...

  10. TimesTen LINUX 安装日志

    $ ./setup.sh NOTE: Each TimesTen installation is identified by a unique instance name. The instance ...