Django——form组件和ModelForm

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

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

(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

二、运用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

  建立超级用户: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),
]
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="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>
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>
View Code

五、显示效果

  

  

六、构建表单总结

  假设你想在你的网站上建立一个简单的表单,以得到用户的名字。你须要相似这样的模板: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

2、利用forms组件实现

参考:正则表达式

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

一、视图中引入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" >
    )

注意: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">

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

二、视图

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

三、模板

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

  显示效果:

  

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

一、引入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())

  页面访问解析效果:

  

二、修改添加和编辑视图,处理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)

三、模板改写

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

四、修改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': "做者不能为空", },
}

五、修改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())

  显示效果:

  

 

4、前端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>

5、modelform详解

Django之Form组件

Django-组件拾遗

Django-form表单

6、form组件补充

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

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

三、经常使用选择插件

# 单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
# )

6、django请求流程

  Django 和其余 Web 框架的 HTTP 处理的流程大体相同,Django 处理一个 Request 的过程是首先经过中间件,而后再经过默认的 URL 方式进行的。咱们能够在 Middleware 这个地方把全部 Request 拦截住,用咱们本身的方式完成处理之后直接返回 Response。

 

 

 

  

一、http协议

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

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

三、流程图说明

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

相关文章
相关标签/搜索