【精華】【學以至用】Django精華總結

簡單入門和梳理

一、WEB框架javascript

    MVC
        Model       View       Controller
        數據庫   模板文件    業務處理
    MTV
        Model    Template     View
        數據庫   模板文件    業務處理
    ############## WEB:MVC、MTVcss

二、Djangohtml

    #安裝
    pip3 install django
    
    # 建立Django工程
    django-admin startproject 【工程名稱】前端


        mysite
            - mysite        # 對整個程序進行配置
                - init
                - settings  # 配置文件
                - url       # URL對應關係
                - wsgi      # 遵循WSIG規範,uwsgi + nginx
            - manage.py     # 管理Django程序:
                                - python manage.py
                                - python manage.py startapp xx
                                - python manage.py makemigrations
                                - python manage.py migrate
       
    # 運行Django功能
    python manage.py runserver 127.0.0.1:8001

    # 建立app
    python manage.py startapp cmdb
    python manage.py startapp openstack
    python manage.py startapp xxoo....java

    # app目錄結構
    app:
        migrations     數據修改表結構
        admin          Django爲咱們提供的後臺管理
        apps           配置當前app
        models         ORM,寫指定的類  經過命令能夠建立數據庫結構
        tests          單元測試
        views          業務代碼python

    一、配置模板的路徑mysql

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


    二、配置靜態目錄static(    最後一行添加)jquery

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

 

<link rel="stylesheet" href="/static/commons.css" />

        三、app下views.pynginx

def func(request):
    # request.method   GET / POST
    
    # http://127.0.0.1:8009/home?nid=123&name=alex
    # request.GET.get('',None)   # 獲取請求發來的而數據
    # request.POST.get('',None)
    
    
    # return HttpResponse("字符串")
    # return render(request, "HTML模板的路徑")
    # return redirect('/只能填URL')

    四、模板渲染
            -- {{ 變量名 }}git

def func(request):
    return render(request, "index.html", {'current_user': "wangxihao"})
<!-- index.html -->			
<html>
..
<body>
    <div>{{current_user}}</div> <!--顯示:wangxihao-->
</body>

</html>

        -- For循環

def func(request):
    return render(request, "index.html", {'current_user': "w1", 'user_list': ['w1','w2']})
<!-- index.html	-->
<html>
..
<body>
    <div>{{current_user}}</div>
    <ul>
    {% for row in user_list %}
        {% if row == "w1" %}
            <li>{{ row }}</li>
        {% endif %}							
    {% endfor %}
    </ul>		
</body>
</html>

#####索引#####

# views
def func(request):
    return render(request, "index.html", {'current_user': "alex", 
			                  'user_list': ['alex','eric'], 
					  'user_dict': {'k1': 'v1', 'k2': 'v2'}})
<!-- index.html -->
<html>
..
<body>
	<div>{{current_user}}</div>					
	<a> {{ user_list.1 }} </a>
	<a> {{ user_dict.k1 }} </a>
	<a> {{ user_dict.k2 }} </a>
</body>
</html>

第二課

    一、Django請求生命週期
        -> URL對應關係(匹配) -> 視圖函數 -> 返回用戶字符串
        -> URL對應關係(匹配) -> 視圖函數 -> 打開一個HTML文件,讀取內容

    二、路由系統

  • url(r'^index/', views.index),    
    url(r'^home/', views.Home.as_view()),
  • url(r'^detail-(\d+).html', views.detail),  
  • url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

           實戰1:

url(r'^detail-(\d+)-(\d+).html', views.detail),

def func(request, nid, uid):
    pass

def func(request, *args):
    args = (2,9)

def func(request, *args, **kwargs):
    args = (2,9)

           實戰2:

url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

def func(request, nid, uid):
    pass
    
def funct(request, **kwargs):
    kwargs = {'nid': 1, 'uid': 3}
    
def func(request, *args, **kwargs):
    args = (2,9)

 

  • name
    對URL路由關係進行命名, ***** 之後能夠根據此名稱生成本身想要的URL *****
    url(r'^asdfasdfasdf/', views.index, name='i1'),
    url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'),
    url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),
    def func(request, *args, **kwargs):
        from django.urls import reverse
        
        url1 = reverse('i1')                              # asdfasdfasdf/
        url2 = reverse('i2', args=(1,2,))                 # yug/1/2/
        url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/
    <!-- xxx.html -->
    {% url "i1" %}               # asdfasdfasdf/
    {% url "i2" 1 2 %}           # yug/1/2/
    {% url "i3" pid=1 nid=9 %}   # buy/1/9/

    PS:當前的URL----request.path_info

  • 默認值

    # urls
    url(r'^index/', views.index, {'name': 'root'}),
    		
    # views
    def index(request,name):
        print(name)
        return HttpResponse('OK')

    **這裏沒有徹底弄明白~
    一種傳遞參數的方式。呵呵

  • 命名空間

    /admin/    include('app01.urls',namespace='m1')
    /crm/      include('app01.urls',namespace='m2')
    			
    app01.urls
    /index/(?P<arg1>\d+)    name = 'n1'
    			
    # 經過namespace:name,反向生成URL
    reverser('m1:n1' kwargs={'arg1':11})    # /admin/index/11
    reverser('m2:n1')                       # /crm/index
    
    # 模板語言下的reverser
    {% url 'm1:n1' arg1=11 %}    # /admin/index/11

    **這裏沒有徹底弄明白~   
    使用reverser的方法,解決調用同一views函數時,路徑的區分問題。基本用不到。呵呵
     

    三、視圖

        一、獲取用戶請求數據
            request.body  # 全部內容的原始值
                request.GET
                request.POST
                request.FILES
                request.xxxx.getlist
            request.meta  # 請求頭相關的內容
                request.COOKIES
                request.path_info
                request.method

 

        PS:
            GET:獲取數據                
            POST:提交數據
            
        二、checkbox等多選的內容
            request.POST.getlist()


        三、上傳文件

# 上傳文件,form標籤作特殊設置
obj = request.FILES.get('fafafa')
obj.name    //取文件名
obj.size    //取文件大小
//obj.chunks()  //取文件
f = open(obj.name, mode='wb')
for item in obj.chunks():
    f.write(item)
f.close()

  HTML中表單的特殊設置

<form action="{% url "url" %}" method="post" enctype="multipart/form-data">
<!-- form特殊設置:enctype="multipart/form-data" -->
</form>


        四、FBV & CBV
            function base view

def index(request,*args,**kwargs):
    if request.method == "POST":
        pass
    else request.method == "GET":
        pass

            class base view

from django.view import View

class Home(View):
    def get(self,reqeust,*args,**kwargs):
        pass

            建議:二者都用
       訂製CBV

from django.view import View

Class Foo(View):
    # 每次在執行Foo 方法時,能夠自定義,以前和以後的操做
    def dispatch(self,request):
        print("before")
        result = super(Foo,self).dispatch(request,*args,**kwargs)
        print("after")
        return result

    def get(self,request):
        print("get get get")
        return Httprespone("get OK")

    def post(self,request):
        print("post post post")
        return Httprespone("post OK")


        五、裝飾器

            FBV的裝飾器

def auth(func):
    def inner(reqeust,*args,**kwargs):
    v = reqeust.COOKIES.get('username111')
        if not v:
            return redirect('/login/')
        return func(reqeust, *args,**kwargs)
    return inner

@auth
def home(request):
    u = request.COOKIES.get("username")
    psw = request.COOKIES.get("psw")
    return render(reqeust,'index.html',{'current_user': v})

            CBV的裝飾器

from django import views
from django.utils.decorators import method_decorator

@method_decorator(auth,name='dispatch')    # 同二、給這個class的全部的方法增長裝飾器的另外一種方法
class Order(views.View):

# @method_decorator(auth)    # 二、給這個class中全部的方法增長裝飾器
# def dispatch(self, request, *args, **kwargs):
#     return super(Order,self).dispatch(request, *args, **kwargs)

# @method_decorator(auth)    # 一、單獨給一個方法提供裝飾器
def get(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

def post(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

# 回顧一下,CBV的書寫方式。
# urls.py
# url('/order/',views.order.as_views)

                六、請求的其餘信息

# views

def index(request):
    print(request.environ)     # environ 存放全部的請求信息

    # 除了request.environ之外全部的子方法,都是django封裝的。
    print(request.POST)
    print(request.GET)
    print(request.METHOD)
    print(request.FILE)

    for v,k in request.environ.items():
        print(v,k)             # 查看environ全部的信息

    # 查看訪問的客戶端信息
    print(request.environ['HTTP_USER_AGENT'])

    三、模板
        3.一、模板的繼承(母版block)

<!-- 母版HTML -->
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link href="公用的.css" rel="stylesheet" type="text/css" />
    {% block pir_css %}{% endblock %} <!-- 引用模塊私有的class -->
</head>
<body>
    {% block someCode %}{% endblock %}

    <script src="jquery.js"></script>
    {% block pir_js %}{% endblock %} <!-- 引用模塊私有的js-->
</body>
</html>
{% extends '母版.html' %}

<!-- 子版1.HTML -->  <!-- 子版2.html一樣-->
{% block pir_css %}
    <link href="someCode.css" rel="stylesheet" type="text/css" /> 
{% endblock %}

{% block someCode %}
<h1> block後面的 someCode 要對應母版的名字。 <h1>
{{ someCode }}<!-- 這是後臺傳遞過來的數據 -->
{% endblock %}

{% block pir_js %}
<script>
alert('這個頁面繼承了母版HTML')
</script>
{% endblock %}
# urls.py
from django.conf.urls import url,
from cmdb import views
urlpatterns = [
    url(r'^cmdb/$', views.index1),
    url(r'^cmdb/$', views.index2),
]

# views
def index1(request):
    return render(request,"子版1.html",{"someCode":"<div>HELLO WORLD!!</div>","OTHER":['other1','other2','other3']})

def index2(request):
    return render(request,"子版2.html",{"someCode":"<div>HELLO PYTHON!!</div>","OTHER":[111,222,333]})

        3.二、模板的導入

{% extends '母版.html' %}

<!-- 延用3.一、繼承的代碼,稍做修改。 -->

<!-- 子版1.HTML -->  <!-- 子版2.html一樣-->
{% block pir_css %}
    <link href="someCode.css" rel="stylesheet" type="text/css" /> 
{% endblock %}

{% block someCode %}
<h1> block後面的 someCode 要對應母版的名字。 <h1>
{{ someCode }}<!-- 這是後臺傳遞過來的數據 -->

<!-- 添加要引入的代碼 -->
{% include 'tag.html '%}

{% endblock %}

{% block pir_js %}
<script>
alert('這個頁面繼承了母版HTML')
</script>
{% endblock %}
<!-- tag.html -->

<!-- 被引入的小模板,一樣能夠被上級頁面渲染 -->
<div>{{ title }}</div>
<ul>
  {% for x in other %}
    <li>{{x}}</li>
  {% endfor %}
</ul>

        3.三、自定義模板

        3.3.一、simple_tag

a. app下建立templatetags目錄
b. 任意xxoo.py文件
c. 建立template對象 register
d. 
    @register.simple_tag
    def func(a1,a2,a3....)
        return "asdfasd"
e. settings中註冊APP
f. 頂部 {% load xxoo %}
g. {% 函數名 arg1 arg2 %}

缺點:
    不能做爲if條件
優勢:
    參數任意

        3.3.二、filter

a. app下建立templatetags目錄
b. 任意xxoo.py文件
c. 建立template對象 register
d. 
    @register.filter
    def func(a1,a2)
        return "asdfasd"
e. settings中註冊APP
f. 頂部 {% load xxoo %}
g. {{ 參數1|函數名:"參數二,參數三" }} {{ 參數1|函數名:數字 }}

缺點:
    最多兩個參數,不能加空格
優勢:
    能做爲if條件

    3.3.三、分頁
        一、XSS攻擊,默認DJango後臺傳遞不安全。解決辦法:
            1.1,前端模板使用

{{str | safe}}

            1.二、後端使用

from django.utils.safestring import make_safe

def index(request):
    str = "<h1>haha</h1>"
    str = make_safe(str)
    return render(request,"index.html",{"str1":str1})

        二、具體rerr代碼

from django.utils.safestring import mark_safe


class Page:
    def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
        self.current_page = current_page
        self.data_count = data_count
        self.per_page_count = per_page_count
        self.pager_num = pager_num

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_count

    @property
    def end(self):
        return self.current_page * self.per_page_count

    @property
    def total_count(self):
        v, y = divmod(self.data_count, self.per_page_count)
        if y:
            v += 1
        return v

    def page_str(self, base_url):
        page_list = []

        if self.total_count < self.pager_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.pager_num + 1) / 2:
                start_index = 1
                end_index = self.pager_num + 1
            else:
                start_index = self.current_page - (self.pager_num - 1) / 2
                end_index = self.current_page + (self.pager_num + 1) / 2
                if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.pager_num + 1

        if self.current_page == 1:
            prev = '<a class="page" href="javascript:void(0);">上一頁</a>'
        else:
            prev = '<a class="page" href="%s?p=%s">上一頁</a>' % (base_url, self.current_page - 1,)
        page_list.append(prev)

        for i in range(int(start_index), int(end_index)):
            if i == self.current_page:
                temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url, i, i)
            else:
                temp = '<a class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
            page_list.append(temp)

        if self.current_page == self.total_count:
            nex = '<a class="page" href="javascript:void(0);">下一頁</a>'
        else:
            nex = '<a class="page" href="%s?p=%s">下一頁</a>' % (base_url, self.current_page + 1,)
        page_list.append(nex)

        jump = """
        <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ % (base_url,)

        page_list.append(jump)

        page_str = mark_safe("".join(page_list))

        return page_str

        三、具體分頁調用方法

from utils import pagination # 導入上面的代碼

LIST = []               # 模擬數據
for i in range(500):    # 模擬數據
    LIST.append(i)      # 模擬數據

def user_list(request):
    current_page = request.GET.get('p', 1)
    current_page = int(current_page)

    page_obj = pagination.Page(current_page,len(LIST),val)

    data = LIST[page_obj.start:page_obj.end]

    page_str = page_obj.page_str("/user_list/")

    return render(request, 'user_list.html', {'li': data,'page_str': page_str})

模板語言的取值:   

render(
    request,
    "xxx.html",
    {
    'obj':1234,
    'k1':[1,2,3,4],
    'k2':{'name':'www','age':77}
    }
)

  HTML模板的取值:

<html>

<body>
<!-- 取單獨的值 -->
<p>{obj}</p>
<p>{k1.3}列表</p>
<p>{k2.name}字典</p>

<!-- 遍歷全部值 -->
{% for i in k1 %}
    <p>{{i}}</p>
{% endfor %}

{% for row in k2,keys %}
    <p>{{row}}</p>
{% endfor %}

{% for row in k2.value %}
    <p>{{row}}</p>
{% endfor %}

{% for k,v in k2.items %}
    {% forloop.counter # 正序循環次數的計數器從1開始 %}
    {% forloop.counter0 # 正序循環次數的計數器從0開始 %}
    {% forloop.revcounter # 倒敘循環次數的計數器從開始 %}
    {% forloop.revcounter0 # 倒敘循環次數的計數器從0開始 %}

    {% forloop.frist # 判斷是不是第一次循環 %}
    {% forloop.last # 判斷是不是最後一次循環 %}

    {% forloop.parentloop# 顯示父循環的次數,須要有父層循環 %}

    <p>{{k}}---{{v}}</p>
{% endfor %}

</body>
</html>

  四、ORM操做

select * from tb where id > 1
# 對應關係
models.tb.objects.filter(id__gt=1)
models.tb.objects.filter(id=1)
models.tb.objects.filter(id__lt=1)

        4.一、建立類
        ----先寫類:

from django.db import models

# app01_userinfo
class UserInfo(models.Model):
    # id列,自增,主鍵
    # 用戶名列,字符串類型,指定長度
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)

    ----註冊APP(settings.py)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
]

    ----執行命令

python manage.py  makemigrations
python manage.py  migrate

   ********** 注意 ***********
        Django默認使用MySQLdb模塊連接MySQL
        主動修改成pymysql,在project同名文件夾下的__init__文件中添加以下代碼便可:

pip install pymysql
import pymysql
pymysql.install_as_MySQLdb()

        4.二、字段

AutoField(Field)
    - int自增列,必須填入參數 primary_key=True

BigAutoField(AutoField)
    - bigint自增列,必須填入參數 primary_key=True

    注:當model中若是沒有自增列,則自動會建立一個列名爲id的列
    from django.db import models

    class UserInfo(models.Model):
        # 自動建立一個列名爲id的且爲自增的整數列
        username = models.CharField(max_length=32)

    class Group(models.Model):
        # 自定義自增列
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)

SmallIntegerField(IntegerField):
    - 小整數 -32768 ~ 32767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正小整數 0 ~ 32767
IntegerField(Field)
    - 整數列(有符號的) -2147483648 ~ 2147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正整數 0 ~ 2147483647

BigIntegerField(IntegerField):
    - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807


BooleanField(Field)
    - 布爾值類型

NullBooleanField(Field):
    - 能夠爲空的布爾值

CharField(Field)
    - 字符類型
    - 必須提供max_length參數, max_length表示字符長度

TextField(Field)
    - 文本類型

EmailField(CharField):
    - 字符串類型,Django Admin以及ModelForm中提供驗證機制

IPAddressField(Field)
    - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制

GenericIPAddressField(Field)
    - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
    - 參數:
        protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
        unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both"

URLField(CharField)
    - 字符串類型,Django Admin以及ModelForm中提供驗證 URL

SlugField(CharField)
    - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)

CommaSeparatedIntegerField(CharField)
    - 字符串類型,格式必須爲逗號分割的數字

UUIDField(Field)
    - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證

FilePathField(Field)
    - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
    - 參數:
            path,                      文件夾路徑
            match=None,                正則匹配
            recursive=False,           遞歸下面的文件夾
            allow_files=True,          容許文件
            allow_folders=False,       容許文件夾

FileField(Field)
    - 字符串,路徑保存在數據庫,文件上傳到指定目錄
    - 參數:
        upload_to = ""      上傳文件的保存路徑
        storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage

ImageField(FileField)
    - 字符串,路徑保存在數據庫,文件上傳到指定目錄
    - 參數:
        upload_to = ""      上傳文件的保存路徑
        storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
        width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
        height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)

DateTimeField(DateField)
    - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
    - 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
    - 時間格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field)
    - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型

FloatField(Field)
    - 浮點型

DecimalField(Field)
    - 10進制小數
    - 參數:
        max_digits,小數總長度
        decimal_places,小數位長度

BinaryField(Field)
    - 二進制類型
自定義無符號整數字段

    class UnsignedIntegerField(models.IntegerField):
        def db_type(self, connection):
            return 'integer UNSIGNED'

    PS: 返回值爲字段在數據庫中的屬性,Django字段默認的值爲:
        'AutoField': 'integer AUTO_INCREMENT',
        'BigAutoField': 'bigint AUTO_INCREMENT',
        'BinaryField': 'longblob',
        'BooleanField': 'bool',
        'CharField': 'varchar(%(max_length)s)',
        'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
        'DateField': 'date',
        'DateTimeField': 'datetime',
        'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
        'DurationField': 'bigint',
        'FileField': 'varchar(%(max_length)s)',
        'FilePathField': 'varchar(%(max_length)s)',
        'FloatField': 'double precision',
        'IntegerField': 'integer',
        'BigIntegerField': 'bigint',
        'IPAddressField': 'char(15)',
        'GenericIPAddressField': 'char(39)',
        'NullBooleanField': 'bool',
        'OneToOneField': 'integer',
        'PositiveIntegerField': 'integer UNSIGNED',
        'PositiveSmallIntegerField': 'smallint UNSIGNED',
        'SlugField': 'varchar(%(max_length)s)',
        'SmallIntegerField': 'smallint',
        'TextField': 'longtext',
        'TimeField': 'time',
        'UUIDField': 'char(32)',
# 注意事項
    1.觸發Model中的驗證和錯誤提示有兩種方式:
        a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息
        b. 使用ModelForm
        c. 調用Model對象的 clean_fields 方法,如:
            # models.py
            class UserInfo(models.Model):
                nid = models.AutoField(primary_key=True)
                username = models.CharField(max_length=32)

                email = models.EmailField(error_messages={'invalid': '格式錯了.'})

            # views.py
            def index(request):
                obj = models.UserInfo(username='11234', email='uu')
                try:
                    print(obj.clean_fields())
                except Exception as e:
                    print(e)
                return HttpResponse('ok')

           # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。

    2.Admin中修改錯誤提示
        # admin.py
        from django.contrib import admin
        from model_club import models
        from django import forms


        class UserInfoForm(forms.ModelForm):
            age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'})

            class Meta:
                model = models.UserInfo
                # fields = ('username',)
                fields = "__all__"
                exclude = ['title']
                labels = { 'name':'Writer', }
                help_texts = {'name':'some useful help text.',}
                error_messages={ 'name':{'max_length':"this writer name is too long"} }
                widgets={'name':Textarea(attrs={'cols':80,'rows':20})}

        class UserInfoAdmin(admin.ModelAdmin):
            form = UserInfoForm

        admin.site.register(models.UserInfo, UserInfoAdmin)

        4.三、字段的參數

null                數據庫中字段是否能夠爲空
    db_column           數據庫中字段的列名
    default             數據庫中字段的默認值
    primary_key         數據庫中字段是否爲主鍵
    db_index            數據庫中字段是否能夠創建索引
    unique              數據庫中字段是否能夠創建惟一索引
    unique_for_date     數據庫中字段【日期】部分是否能夠創建惟一索引
    unique_for_month    數據庫中字段【月】部分是否能夠創建惟一索引
    unique_for_year     數據庫中字段【年】部分是否能夠創建惟一索引

    verbose_name        Admin中顯示的字段名稱
    blank               Admin中是否容許用戶輸入爲空
    editable            Admin中是否能夠編輯
    help_text           Admin中該字段的提示信息
    choices             Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能爲空.", 'invalid': '格式錯誤'}

    validators          自定義錯誤驗證(列表類型),從而定製想要的驗證規則
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '優先錯信息1',
                                    'c2': '優先錯信息2',
                                    'c3': '優先錯信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
                                    EmailValidator(message='又錯誤了', code='c3'), ]
                            )

       元信息

class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
            db_table = "table_name"

            # 聯合索引
            # 遵循最左前綴模式
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 聯合惟一索引(固定值都搜索時)
            unique_together = (("driver", "restaurant"),)

            # admin中顯示的表名稱+s
            verbose_name

            # verbose_name 不加5
            verbose_name_plural

       4.四、操做ORM

# 增
models.User.objects.create(name='qianxiaohu',age=18)

dic = {'name': 'xx', 'age': 19}
models.User.objects.create(**dic)

obj = models.User(name='qianxiaohu',age=18)
obj.save()
# 刪
models.User.objects.filter(id=1).delete()
# 改
models.User.objects.filter(id__gt=1).update(name='xxx',age=84)
dic = {'name': 'xx', 'age': 19}
models.User.objects.filter(id__gt=1).update(**dic)

obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save()
# 查
models.User.objects.filter(id=1,name='root')
models.User.objects.filter(id__gt=1,name='root')
models.User.objects.filter(id__lt=1)
models.User.objects.filter(id__gte=1)
models.User.objects.filter(id__lte=1)

models.User.objects.filter(id=1,name='root')
dic = {'name': 'xx', 'age__gt': 19}
models.User.objects.filter(**dic)

v1 = models.Business.objects.all()                              # QuerySet ,內部元素都是對象
v2 = models.Business.objects.all().values('id','caption')       # QuerySet ,內部元素都是字典
v3 = models.Business.objects.all().values_list('id','caption')  # QuerySet ,內部元素都是元組

models.Business.objects.get(id=1)               # 獲取到的一個對象,若是不存在就報錯
models.Business.objects.filter(id=1).first()    # 得到對象或者None,不存在也不會報錯
# 獲取個數
models.Tb1.objects.filter(name='seven').count()

# 大於,小於
models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
models.Tb1.objects.filter(id__gte=1)              # 獲取id大於等於1的值
models.Tb1.objects.filter(id__lt=10)             # 獲取id小於10的值
models.Tb1.objects.filter(id__lte=10)             # 獲取id小於10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值

# in
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於十一、2二、33的數據
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

# isnull
Entry.objects.filter(pub_date__isnull=True)

# contains  --相似sql的like操做
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
models.Tb1.objects.exclude(name__icontains="ven")

# range
models.Tb1.objects.filter(id__range=[1, 2])   # 範圍bettwen and

# 其餘相似
startswith,istartswith, endswith, iendswith,

# order by
models.Tb1.objects.filter(name='seven').order_by('id')    # asc
models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

# group by
from django.db.models import Count, Min, Max, Sum
models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

# limit 、offset
models.Tb1.objects.all()[10:20]

# regex正則匹配,iregex 不區分大小寫
Entry.objects.get(title__regex=r'^(An?|The) +')
Entry.objects.get(title__iregex=r'^(an?|the) +')

# date
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

# year
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)

# month
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)

# day
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)

# week_day
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

# hour
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

# minute
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)

# second
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)

 

# 高級操做

# extra
extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
   Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
   Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
   Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
   Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

# F
from django.db.models import F
models.Tb1.objects.update(num=F('num')+1)


# Q
# 方式一:
Q(nid__gt=10)
Q(nid=8) | Q(nid__gt=10)
Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

# 方式二:
con = Q()
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))
q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))
con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)


# 執行原生SQL

from django.db import connection, connections
cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()

 

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 獲取全部的數據對象

def filter(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def exclude(self, *args, **kwargs)
    # 條件查詢
    # 條件能夠是:參數,字典,Q

def select_related(self, *fields)
     性能相關:表之間進行join連表操做,一次性獲取關聯的數據。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外鍵字段')
     model.tb.objects.all().select_related('外鍵字段__外鍵字段')

def prefetch_related(self, *lookups)
    性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。
            # 獲取全部用戶表
            # 獲取用戶類型表where id in (用戶表中的查到的全部用戶ID)
            models.UserInfo.objects.prefetch_related('外鍵字段')



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type='Excused', then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用於實現聚合group by查詢

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用於distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    注:只有在PostgreSQL中才能使用distinct進行去重

def order_by(self, *field_names)
    # 用於排序
    models.UserInfo.objects.all().order_by('-id','age')

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 構造額外的查詢條件或者映射,如:子查詢

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:若是存在order_by,reverse則是倒序,若是多個排序則一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列數據

 def only(self, *fields):
    #僅取某個表中的數據
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

 def using(self, alias):
     指定使用的數據庫,參數爲別名(setting中的設置)


##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################

def raw(self, raw_query, params=None, translations=None, using=None):
    # 執行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw('select id as nid from 其餘表')

    # 爲原生SQL設置參數
    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

    # 將獲取的到列名轉換爲指定列名
    name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

    # 指定數據庫
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


def values(self, *fields):
    # 獲取每行數據爲字典格式

def values_list(self, *fields, **kwargs):
    # 獲取每行數據爲元祖

def dates(self, field_name, kind, order='ASC'):
    # 根據時間進行某一部分進行去重查找並截取指定內容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 並獲取轉換後的時間
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates('ctime','day','DESC')

def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換爲指定時區時間
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo時區對象
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def none(self):
    # 空QuerySet對象


####################################
# METHODS THAT DO DATABASE QUERIES #
####################################

def aggregate(self, *args, **kwargs):
   # 聚合函數,獲取字典類型聚合結果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
   ===> {'k': 3, 'n': 4}

def count(self):
   # 獲取個數

def get(self, *args, **kwargs):
   # 獲取單個對象

def create(self, **kwargs):
   # 建立對象

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的個數
    objs = [
        models.DDD(name='r11'),
        models.DDD(name='r22')
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 若是存在,則獲取,不然,建立
    # defaults 指定建立時,其餘字段的值
    obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})

def update_or_create(self, defaults=None, **kwargs):
    # 若是存在,則更新,不然,建立
    # defaults 指定建立時或更新時的其餘字段
    obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})

def first(self):
   # 獲取第一個

def last(self):
   # 獲取最後一個

def in_bulk(self, id_list=None):
   # 根據主鍵ID進行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 刪除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有結果

數據庫操做--QuerySet中方法:

- QuerySet中的方法:
    - 返回QuerySet類型(select_related,prefetch_related)
        
        select_related
        # 一次完成參數內的跨表查詢,若是須要跨其餘表,則再發起一次請求。
            users = models.User.objects.all().select_related('ut')
            for row in users:
                print(row.user,row.pwd,row.ut_id)
                print(row.ut.name)
                print(row.tu.name) # 再發起一次SQL請求
        
        prefetch_related
            
            users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
            # select * from users where id > 30
            # 獲取上一步驟中全部的ut_id=[1,2]
            # select * from user_type where id in [1,2]
            # select * from user_type where id in [1,2]
            
            for row in users:
                print(row.user,row.pwd,row.ut_id)
                print(row.ut.name)

多表關係以及參數

ForeignKey(ForeignObject) # ForeignObject(RelatedField)
    to,                         # 要進行關聯的表名
    to_field=None,              # 要關聯的表中的字段名稱
    on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
                                    - models.CASCADE,刪除關聯數據,與之關聯也刪除
                                    - models.DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError
                                    - models.PROTECT,刪除關聯數據,引起錯誤ProtectedError
                                    - models.SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)
                                    - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
                                    - models.SET,刪除關聯數據,
                                                  a. 與之關聯的值設置爲指定值,設置:models.SET(值)
                                                  b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)

                                                    def func():
                                                        return 10

                                                    class MyModel(models.Model):
                                                        user = models.ForeignKey(
                                                            to="User",
                                                            to_field="id"
                                                            on_delete=models.SET(func),)
    related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
    related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
    limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                # 如:
                                        - limit_choices_to={'nid__gt': 5}
                                        - limit_choices_to=lambda : {'nid__gt': 5}

                                        from django.db.models import Q
                                        - limit_choices_to=Q(nid__gt=10)
                                        - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                        - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
    db_constraint=True          # 是否在數據庫中建立外鍵約束
    parent_link=False           # 在Admin中是否顯示關聯數據


OneToOneField(ForeignKey)
    to,                         # 要進行關聯的表名
    to_field=None               # 要關聯的表中的字段名稱
    on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲

                                ###### 對於一對一 ######
                                # 1. 一對一其實就是 一對多 + 惟一索引
                                # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段
                                # 以下會在A表中額外增長一個c_ptr_id列且惟一:
                                        class C(models.Model):
                                            nid = models.AutoField(primary_key=True)
                                            part = models.CharField(max_length=12)

                                        class A(C):
                                            id = models.AutoField(primary_key=True)
                                            code = models.CharField(max_length=1)

ManyToManyField(RelatedField)
    to,                         # 要進行關聯的表名
    related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
    related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
    limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                # 如:
                                        - limit_choices_to={'nid__gt': 5}
                                        - limit_choices_to=lambda : {'nid__gt': 5}

                                        from django.db.models import Q
                                        - limit_choices_to=Q(nid__gt=10)
                                        - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                        - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
    symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段
                                # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段
                                    models.BB.objects.filter(...)

                                    # 可選字段有:code, id, m1
                                        class BB(models.Model):

                                        code = models.CharField(max_length=12)
                                        m1 = models.ManyToManyField('self',symmetrical=True)

                                    # 可選字段有: bb, code, id, m1
                                        class BB(models.Model):

                                        code = models.CharField(max_length=12)
                                        m1 = models.ManyToManyField('self',symmetrical=False)

    through=None,               # 自定義第三張表時,使用字段用於指定關係表
    through_fields=None,        # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
                                    from django.db import models

                                    class Person(models.Model):
                                        name = models.CharField(max_length=50)

                                    class Group(models.Model):
                                        name = models.CharField(max_length=128)
                                        members = models.ManyToManyField(
                                            Person,
                                            through='Membership',
                                            through_fields=('group', 'person'),
                                        )

                                    class Membership(models.Model):
                                        group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                        person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                        inviter = models.ForeignKey(
                                            Person,
                                            on_delete=models.CASCADE,
                                            related_name="membership_invites",
                                        )
                                        invite_reason = models.CharField(max_length=64)
    db_constraint=True,         # 是否在數據庫中建立外鍵約束
    db_table=None,              # 默認建立第三張表時,數據庫中表的名稱
# 外鍵:
class UserType(models.Model):
    caption = models.CharField(max_length=32)
# id  caption
# 1,普通用戶
# 2,VIP用戶
# 3, 遊客

class User(models.Model):
    age = models.IntergerFiled()
    name = models.CharField(max_length=10)#字符長度
    # user_type_id = models.IntergerFiled() # 約束,
    user_type = models.ForeignKey("UserType",to_field='id') # 約束,

# name age  user_type_id
# 張揚  18     3
# 張A揚 18     2
# 張B揚 18     2

#外鍵:
v = models.User.objects.filter(nid__gt=0)
v[0].user_type.caption  ---->  經過.進行跨表

        4.五、AJAX

$.ajax({
    url: '/host',
    type: "POST",
    data: {'k1': 123,'k2': "root"},
    //data:{'k1':123,'list':[1,2,3,4]},
    //traditional:true,    //這個屬性表示,能夠傳遞列表

    //processData:false,    //JQ上傳文件時,設置不作特殊處理。
    //contentType:false,    //JQ上傳文件時,設置不作特殊處理。

    //後臺取值的時候使用 request.POST.getlist("list")  
    //格式,["1","2","3","4"]
    success: function(data){
        // data是服務器端返回的字符串
        var obj = JSON.parse(data);
    }
})

   建議:永遠讓服務器端返回一個字典

# views
 return HttpResponse(json.dumps(字典))

    4.六、一對多 and 正向操做 and 反向操做

def func():
    # User類中,on_delete=models.SET(func)的回調函數
    return 5


class UserType(models.Model):
    name = models.CharField(max_length=32)
    

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    ....         ForiegnKey(to="UserType",to_field='id',on_delete=models.SET(func))

# delete from user where id=1
# delete from UserType where id=1 # 報錯,由於User表中有數據正在使用UserType,因此會報錯。

# UserType.objects.filter(id=1).delete()    # 在新版django中,再也不報錯,直接刪除,並連帶User表中的關聯數據一塊兒刪除 
# 參考model建立表時的,on_delete方法進行設置。



# 正向 ---從User表中操做UserType
# v = User.objects.all()
# for item in v:
#     item.user
#     item.pwd
#     item.ut.name

# User.objects.all().values('user','ut__name')


# 反向  ---從UserType表中操做User
# v = UserType.objects.all()
# for item in v:
#     item.name
#     item.id
#     item.user_set.all()    # 若是在foreignKey(related_name=b),則 item.b.all()
                             # 若是在foreignKey(related-query_name=a),則 item.a_set.all() 
# models.UserType.objects.all().values('name','user__pwd')
# 若是在foreignKey(related_name=b)
# models.UserType.objects.all().values('b')

# 若是在foreignKey(related-query_name=a)
# models.UserType.objects.all().values('name','a__pwd')

    4.七、建立多對多

            方式一:自定義關係表

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
    name = models.CharField(max_length=32)
# 2

class HostToApp(models.Model):
    hobj = models.ForeignKey(to='Host',to_field='nid')
    aobj = models.ForeignKey(to='Application',to_field='id')

# HostToApp.objects.create(hobj_id=1,aobj_id=2)

            方式二:自動建立關係表

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
    name = models.CharField(max_length=32)
    r = models.ManyToManyField("Host")
    
#沒法直接對第三張表進行操做

obj = Application.objects.get(id=1)
obj.name

# 第三張表操做
obj.r.add(1)
obj.r.add(2)
obj.r.add(2,3,4)
obj.r.add(*[1,2,3,4])

obj.r.remove(1)
obj.r.remove(2,4)
obj.r.remove(*[1,2,3])

obj.r.clear()

obj.r.set([3,5,7])

# 全部相關的主機對象「列表」 QuerySet
obj.r.all()

# 篩選,篩選出主機名爲c1的主機
obj.r.filter(hostname="c1")

    4.八、數據驗證(偏弱)

# 這句話執行了,email就保存了1234156,儘管不合規。
models.tb.objects.create(user=name,email="1234156")

# 這句話執行了,email就保存了1234156,儘管不合規。
obj = models.tb(user=name,email="1234156")
obj.save()

# 這裏就出現了驗證功能。
obj = models.tb(user=name,email="1234156")
obj.full_clean()    # 執行這句的時候,驗證正則規則。若是不合規,就報錯了。錯誤類型是ValidationError
obj.save()

# ValidationError  引伸一下。
# 這裏有一個鉤子,雖然不知道有什麼用。
# xx.full_clean()中有一個方法叫作self.clean(),裏面是代碼是pass。而這個clean就是所謂的鉤子。
# 在執行正則驗證以後,都會再執行一次clean方法。儘管如今是空的,但咱們能夠作些東西。

#models.py
class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def clean(self):
        # 這裏有進行了一次數據庫操做,固然能夠自定義其餘操做。
        c = UserInfo.objects.filter(name=self.name).count()
        if c:
            from django.core.exceptions import ValidationError
            rasie ValidationError(message="用戶名已存在",code="exist")
            # 只能是ValidationError錯誤哦

# 儘管驗證功能,仍是讓驗證模塊去作最好了。因此只是知道一下就行了。

 

五、cookie

    5.一、cookie 是什麼?
            cookie,是客戶端上的瀏覽器儲存一個文件。字典格式的。瀏覽器訪問時會將本地的cookie發送的服務器。
            接收方式是

request.COOKIES
request.COOKIES.get("username")
request.COOKIES["username"]

# 加密傳輸cookie
request.get_signed_cookie("username", "kangbazi",salt="基於salt加密")

            設置cookie的方式

rep = HttpResponse(...) 或 rep = render(request, ...)
rep['name'] = "WXH"    # 給響應頭中添加數據(ResponseHeader)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...)
    參數:
        key,              鍵
        value='',         值
        max_age=None,     超時時間 -- 參數分鐘秒,倒計時
        expires=None,     超時時間(datetime格式)
        path='/',         Cookie生效的路徑,/ 表示根路徑,特殊的:跟路徑的cookie能夠被任何url的頁面訪問
        domain=None,      Cookie生效的域名
        secure=False,     https傳輸
        httponly=False    只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)

            JS也能夠操做cookie

<script src="/static/jq.cookie.js"></script>
<script>
//獲取cookie
$.cookie("key")

//設置cookie
$.cookie("key","value",{"path":"/home"})

//其餘參數參考django設置cookie的方式
</script>

六、session

    6.一、session的原理
            session是保存的在服務器端的鍵值對
            session是基於cookie的

    6.二、Session配置(缺乏cache)

# settings.py

# 配置文件中設置默認操做(通用配置):
SESSION_COOKIE_NAME = "sessionid"              # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
SESSION_COOKIE_PATH = "/"                	# Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None                	# Session的cookie保存的域名(默認)
ESSION_COOKIE_SECURE = False                	# 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True                	# 是否Session的cookie只支持http傳輸(默認)
SESSION_COOKIE_AGE = 1209600                    # Session的cookie失效日期(2周)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False		# 是否關閉瀏覽器使得Session過時(默認)
SESSION_SAVE_EVERY_REQUEST = False              # 是否每次請求都保存Session,默認修改以後才保存(默認)

    6.三、session的5種類型。

        6.3.一、數據庫(默認)

Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
     
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路徑(默認)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默認)
    SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(默認)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http傳輸(默認)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默認)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過時(默認)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都保存Session,默認修改以後才保存(默認)
 
 
 
b. 使用
 
    def index(request):
        # 獲取、設置、刪除Session中數據
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在則不設置
        del request.session['k1']
 
        # 全部 鍵、值、鍵值對
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()
 
 
        # 用戶session的隨機字符串
        request.session.session_key
 
        # 將全部Session失效日期小於當前日期的數據刪除
        request.session.clear_expired()
 
        # 檢查 用戶session的隨機字符串 在數據庫中是否
        request.session.exists("session_key")
 
        # 刪除當前用戶的全部Session數據
        request.session.delete("session_key")
 
        request.session.set_expiry(value)
            * 若是value是個整數,session會在些秒數後失效。
            * 若是value是個datatime或timedelta,session就會在這個時間後失效。
            * 若是value是0,用戶關閉瀏覽器session就會失效。
            * 若是value是None,session會依賴全局session失效策略。

        6.3.二、緩存

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
 
 
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路徑
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https傳輸cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http傳輸
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否關閉瀏覽器使得Session過時
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次請求都保存Session,默認修改以後才保存
 
 
 
b. 使用
 
    同上

        6.3.三、文件

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 
 
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路徑
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https傳輸cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http傳輸
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否關閉瀏覽器使得Session過時
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次請求都保存Session,默認修改以後才保存
 
b. 使用
 
    同上

        6.3.四、緩存+數據庫

數據庫用於作持久化,緩存用於提升效率
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
 
b. 使用
 
    同上

        6.3.五、加密cookie

a. 配置 settings.py
     
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
 
b. 使用
 
    同上

       6.四、 Session用戶驗證

def login(func):
    def wrap(request, *args, **kwargs):
        # 若是未登錄,跳轉到指定頁面
        if request.path == '/test/':
            return redirect('http://www.baidu.com')
        return func(request, *args, **kwargs)
    return wrap

 

七、CSRF-跨站請求僞造

    7.一、CSRF原理
        7.1.0、盜取Cookie,假裝登陸,隨心所欲。
        7.1.一、form添加 {% csrf_token %}
        7.1.二、django會在加載HTML時生成一個隨機字符串,保存到cookie中。
        7.1.三、在頁面POST提交時,同時會把這個隨機字符串提交到服務器。或者在cookie中讓django獲取。
        7.1.四、獲取的隨機字符串與django本地的隨機字符串作比較,來判斷是否阻止頁面提交。達到防止跨站請求僞造。
    7.二、Form提交(CSRF)

<form action='/login/' method='post'>
    {% csrf_token %}
    <input type='text' name='user' />
    <input type='password' name='pwd' />
    <input type='submit' value='提交' />
</form>
<!-- 只須要加入 {% csrf_token %} 便可 -->
<!-- 隨機字符串保存在cookie中 -->

    7.三、Ajax提交(CSRF)
            CSRF請求頭 X-CSRFToken

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        var csrftoken = $.cookie('csrftoken');
  
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({    //ajax的全局配置
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>

    7.四、CSRF的全局與個例

# 全局:
# 在settings.py 中 註釋或者不註釋-中間件 
django.middleware.csrf.CsrfViewMiddleware

# 局部:
# 在單獨的views中的方法,添加裝飾器。

from django.views.decorators.csrf import csrf_exempt,csrf_protect

    @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。
    @csrf_exempt,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。

八、中間件

    中間件,也叫管道。在 setting.py 中的 MIDDLEWARE_CLASSES 聲明。

    中間件的做用是,請求觸發以後,如今進入中間件,在進入url.py。離開時,最後執行中間件。

    中間件是一個類,繼承 middlewareMixin。好比CsrfViewMiddleware(MiddlewareMixin)
    值得一說的是,MiddlewareMixin方法中有兩個重要的方法。

    process_requestprocess_response  

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

    如何寫一箇中間件?

    一、建立一箇中間件的類,並繼承MiddlewaveMixin

from django.utils.deprecation import MiddlewareMixin

class MiddlewaveRow1(MiddlewareMixin):

    # process_request:訪問時觸發
    def process_request(self,request):
        print('MiddlewaveRow1--process_reques')

    # process_response:離開(返回)時觸發
    def process_response(self,request,response):
        print('MiddlewaveRow1--process_response')
        return response

class MiddlewaveRow2(MiddlewareMixin):

    # process_request:訪問時觸發
    def process_request(self,request):
        print('MiddlewaveRow2--process_reques')

    # process_response:離開(返回)時觸發
    def process_response(self,request,response):
        print('MiddlewaveRow2--process_response')
        return response

    二、將建立的中間件加載到中間件池子中。

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
   # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'Middlewave_pool.MiddlewavePool.MiddlewaveRow1',
    'Middlewave_pool.MiddlewavePool.MiddlewaveRow2',
]

    三、隨便訪問一個頁面吧,再回到IDE看控制檯輸出的信息。

    四、中間件引伸一下,若是在中間件process_request方法中,添加return方法。則,直接從當前中間件的process_response方法向出站方向執行。
        不會進入下一個中間件,也不會進入url.py

    五、中間件的另外3種方法:
        process_view(self,request,xx_view,xx_args,xx_kwargs)
        此方法是在全部process_request執行完成後,讀取url列表,獲取view(不執行)
        注:xx_view 是url指向的view方法。
        注:xx_args 是url指向的view方法的默認參數。        例如,url(r'test/(\d+)',views.test)   ,xx_args就是(\d+)
        注:xx_kwargs 是url指向的view方法的指名參數。    例如,url(r'test/(?P<nid>(\d+))',views.test)   ,xx_kwargs就是{nid:(\d+)}

        process_exception(self,request,excepton)
        此方法默認不執行,只有在views執行報錯時在觸發。
        注:excepton中存放的就是views的錯誤信息。

        process_template_response(self,request,response)
        此方法默認不執行,只有在返回時,使用render方法時纔會觸發。    
        注:然並卵……

    六、中間件的聲明週期
   

        補充:

#中間件中能夠定義四個方法,分別是:

# 第一次進來時,只有request,穿過全部中間層,取得views方法和views參數後,離開。
process_request(self,request)

# 第二次帶着views方法和參數,再走一遍中間件。中間能夠處理一些事情了。
process_view(self, request, callback, callback_args, callback_kwargs)
# 到這裏,process_request和process_view不能有return,不然直接跳轉到process_response

#只有在離開時使用render()方法,纔會觸發。
process_template_response(self,request,response)

# 頁面報錯時,在這裏處理錯誤。
process_exception(self, request, exception)

# 頁面正常返回時,在這裏定製需求。
process_response(self, request, response)

九、緩存

    Django中提供了5種緩存方式:

    一、開發調試

# 此爲開始調試用,實際內部不作任何操做
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 緩存超時時間(默認300,None表示永不過時,0表示當即過時)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大緩存個數(默認300)
                    'CULL_FREQUENCY': 3,                                      # 緩存到達最大個數以後,剔除緩存個數的比例,即:1/CULL_FREQUENCY(默認3)
                },
                'KEY_PREFIX': '',                                             # 緩存key的前綴(默認空)
                'VERSION': 1,                                                 # 緩存key的版本(默認1)
                'KEY_FUNCTION' 函數名                                          # 生成key的函數(默認函數會生成爲:【前綴:版本:key】)
            }
        }


    # 自定義key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func

    二、內存

# 此緩存將內容保存至內存的變量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其餘配置同開發調試版本

    三、文件

# 此緩存將內容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其餘配置同開發調試版本

    四、數據庫

# 此緩存將內容保存至數據庫

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 數據庫表
            }
        }

    # 注:執行建立表命令 python manage.py createcachetable

    五、Memcache緩存(python-memcached模塊)

# 此緩存使用python-memcached模塊鏈接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

    六、Memcache緩存(pylibmc模塊)

# 此緩存使用pylibmc模塊鏈接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

    緩存的應用三種應用:

    一、全站

使用中間件,通過一系列的認證等操做,若是內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶以前,判斷緩存中是否已經存在,若是不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其餘中間件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""

    二、單獨視圖

方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]

    三、局部模板

a. 引入TemplateTag

        {% load cache %}

    b. 使用緩存

        {% cache 5000 緩存key %}
            緩存內容
        {% endcache %}

十、內置信號和自定義信號

    內置信號:

Model signals
    pre_init                    # django的modal執行其構造方法前,自動觸發
    post_init                   # django的modal執行其構造方法後,自動觸發
    pre_save                    # django的modal對象保存前,自動觸發
    post_save                   # django的modal對象保存後,自動觸發
    pre_delete                  # django的modal對象刪除前,自動觸發
    post_delete                 # django的modal對象刪除後,自動觸發
    m2m_changed                 # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發
    class_prepared              # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發
Management signals
    pre_migrate                 # 執行migrate命令前,自動觸發
    post_migrate                # 執行migrate命令後,自動觸發
Request/response signals
    request_started             # 請求到來前,自動觸發
    request_finished            # 請求結束後,自動觸發
    got_request_exception       # 請求異常後,自動觸發
Test signals
    setting_changed             # 使用test測試修改配置文件時,自動觸發
    template_rendered           # 使用test測試渲染模板時,自動觸發
Database Wrappers
    connection_created          # 建立數據庫鏈接時,自動觸發

    對於Django內置的信號,僅需註冊指定信號,當程序執行相應操做時,自動觸發註冊函數:

from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception

from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed

from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created


def callback(sender, **kwargs):
    print("xxoo_callback")
    print(sender,kwargs)

xxoo.connect(callback)
# xxoo指上述導入的內容
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

    自定義信號:

        一、定義信號

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

        二、註冊信號

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
 
pizza_done.connect(callback)

        三、觸發信號

from 路徑 import pizza_done
 
pizza_done.send(sender='seven',toppings=123, size=456)

十一、FORM操做

    Django的Form主要具備一下幾大功能:

  • 生成HTML標籤
  • 驗證用戶數據(顯示錯誤信息)
  • HTML Form提交保留上次提交數據
  • 初始化頁面顯示內容                                                               

    11.一、小試牛刀
            建立form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
class MyForm(Form):
    user = fields.CharField(
        widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
    )
 
    gender = fields.ChoiceField(
        choices=((1, '男'), (2, '女'),),
        initial=2,
        widget=widgets.RadioSelect
    )
 
    city = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    )
 
    pwd = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

            views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        obj = MyForm()
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        obj = MyForm(request.POST, request.FILES)
        if obj.is_valid():
            values = obj.clean()
            print(values)
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', {'form': obj})
    else:
        return redirect('http://www.google.com')

            HTML

<form action="/" method="POST" enctype="multipart/form-data">
    <p>{{ form.user }} {{ form.errors.user.0 }}</p>
    <p>{{ form.gender }} {{ form.errors.gender.0 }}</p>
    <p>{{ form.city }} {{ form.errors.city.0 }}</p>
    <p>{{ form.pwd }} {{ form.errors.pwd.0 }}</p>
    <input type="submit"/>
</form>

        其餘form標籤

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}

        {{ form.xxoo.label }}
        {{ form.xxoo.id_for_label }}
        {{ form.xxoo.label_tag }}
        {{ form.xxoo.errors }}
        <p>{{ form.user }} {{ form.user.errors.0 }}</p>

        {{ form.as_p }}
        {{ form.as_ul }}
        <table>{{ form.as_table }}</table>
        <input type="submit" />
</form>

    11.二、Form類
        建立Form類時,主要涉及到 【字段】 和 【插件】,字段用於對用戶請求數據的驗證,插件用於自動生成HTML;

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

        注:UUID是根據MAC以及當前時間等建立的不重複的隨機字符串

        Django內置插件:

# from django.forms import widgets
# class MyForm(Form):
#     user = fields.CharField(
#         widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
#     )

# widgets.xxoo  xxoo就是對應如下HTML標籤的生成器。

TextInput(Input)                    # type="text"
NumberInput(TextInput)              # type="number"
EmailInput(TextInput)               # type="email"
URLInput(TextInput)                 # type="url"
PasswordInput(TextInput)            # type="password"
HiddenInput(TextInput)              # type="hidden",隱藏的輸入
Textarea(Widget)                    # 文本域,textarea標籤
DateInput(DateTimeBaseInput)        # type="text",帶有可選參數format('%Y年%m月%d日,%b縮寫月,%B全拼月')
DateTimeInput(DateTimeBaseInput)    # type="text",帶有可選參數format('%y兩位年-%Y-%m-%d %H:%M:%S.%f')
TimeInput(DateTimeBaseInput)        # type="text",帶有可選參數format('%H:%M:%S.%f')
CheckboxInput                       # type="checkbox"
Select                              # 下拉菜單,select標籤,內涵choices方法
NullBooleanSelect                   # 選項爲‘Unknown’、‘Yes’ 和‘No’。
SelectMultiple                      # <select multiple='multiple'>
RadioSelect                         # 相似Select,可是渲染成<li> 標籤中的一個單選按鈕列表type='radio'
CheckboxSelectMultiple              # 相似SelectMultiple,可是渲染成一個複選框列表type='checkbox'
FileInput                           # type="file"
ClearableFileInput                  # 帶有一個額外的複選框,如該字段不是必選的且有初始的數據,能夠清除字段的值。
MultipleHiddenInput                 # 一個處理多個隱藏的Widget 的Widget,用於值爲一個列表的字段,有choices
SplitDateTimeWidget                 # 有兩個可選參數:DateInput 用於日期,TimeInput 用於時間。
SplitHiddenDateTimeWidget           # 相似SplitDateTimeWidget,可是日期和時間都使用HiddenInput
SelectDateWidget                    # 封裝三個Select Widget:分別用於年、月、日。
                                     # 注意,這個Widget 與標準的Widget 位於不一樣的文件中。
                                     # 參數:years,months,empty_label(空值初始化)

     11.三、經常使用選擇插件

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

        拓展: 在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
            方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )

    # 由於CharField沒有choiecs屬性,因此沒法user.choiecs
    user2 = fields.CharField(widget=widgets.select(choices=[]))
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
        # user2的建立方式是CharField , user的建立方式是choiceField
        self.fields['user2'].widget.choices = models.XXX.objects.all().value_list('id','caption')

            方式二: 使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

# model中的NNewTpye類方法,必須設置__str__(),指定返回的內容。不然authors中存入的是 "NNewType objects"

    11.四、自定義驗證規則

        方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')],
    )

        方式二:

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
 
 
# 自定義驗證規則
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手機號碼格式錯誤')
 
 
class PublishForm(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '標題不能爲空',
                                            'min_length': '標題最少爲5個字符',
                                            'max_length': '標題最多爲20個字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '標題5-20個字符'}))
 
 
    # 使用自定義驗證規則
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手機不能爲空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手機號碼'}))
 
    email = fields.EmailField(required=False,
                            error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'},
                            widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))

        方式三:

from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator
 
    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
        email = fields.EmailField()
 
        def clean_username(self):
            """
            Form中字段中定義的格式匹配完以後,執行此方法進行驗證
            :return:
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已經被玩爛了...', 'invalid')
            return value

        方式四: 同時生成多個標籤進行驗證

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
from django.core.validators import RegexValidator
 
 
############## 自定義字段 ##############
class PhoneField(fields.MultiValueField):
    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'incomplete': 'Enter a country calling code and a phone number.',
        }
        # Or define a different message for each field.
        f = (
            fields.CharField(
                error_messages={'incomplete': 'Enter a country calling code.'},
                validators=[
                    RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
                ],
            ),
            fields.CharField(
                error_messages={'incomplete': 'Enter a phone number.'},
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
            ),
            fields.CharField(
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
                required=False,
            ),
        )
        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                         **kwargs)
 
    def compress(self, data_list):
        """
        當用戶驗證都經過後,該值返回給用戶
        :param data_list:
        :return:
        """
        return data_list
 
############## 自定義插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(ws)
 
    def decompress(self, value):
        """
        處理初始值,當初始值initial不是列表時,調用該方法
        :param value:
        :return:
        """
        if value:
            return value.split(',')
        return [None, None, None]

    11.五、初始化數據

        在Web應用程序中開發編寫功能時,時經常使用到獲取數據庫中的數據並將值初始化在HTML中的標籤上。

         Form

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
 
class MyForm(Form):
    user = fields.CharField()
 
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )

         Views

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
 
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')

         HTML

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
 
    <input type="submit"/>
</form>

    11.六、動態操做select數據

# views

from django.shortcuts import render
from app01.forms import UserInfoForm

def index(request):
    obj = UserInfoForm()    # 實例化form對象
    # obj = UserInfoForm({'字段':"默認值"})    # 初始化Form

    # 每一個用到usertype的地方,都要寫一句這個太麻煩,因此寫在構造函數中,一勞永逸。
    # obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')

    return render(request, 'index.html', {'obj': obj})
# forms.py

from django import forms
from django.forms import fields
from django.forms import widgets

from app01 import models

class UserInfoFrom(forms.Form):
    user = fields.CharField(
        required=False,
        widget=widgets.Textarea(attrs={"class": "c1"})
    )
    pwd = fields.CharField(
        max_length=12,
        widget=widgets.PasswordInput(attrs={"class": "c1"})
    )
    user_type = fields.ChoiceField(
        # choices=[("0", "遊客"), ("1", "普通用戶"), ("2", "超級用戶")],    # 此爲默認方法
        choices=models.UserType.objects.values_list("id", "name"),          # 此方法爲-數據庫讀取
        # 上面這個方法存在的問題是,當修改數據庫後,只有服務器重啓後,頁面才刷新
        # 因此使用構造函數的方法 __init__()
        widget=widgets.Select()
    )
    
    def __init__(self, *args, **kwargs):
        super(UserInfoFrom, self).__init__(*args, **kwargs)
        # 每次刷新頁面時,會從新讀取數據庫。
        self.fields['UserType'].choices = models.UserType.objects.values_list("id", "name")
        # 下面使用的是CharField方法時。
        self.fields['UserType'].widgets.choices = models.UserType.objects.values_list("id", "name")

        Form驗證----內置鉤子

# views.py
def register(request):
    from app01.forms import ResisterForm
    obj = ResisterForm(request.POST)
    if obj.is_valid():
        return render(request, 'register.html', {'obj': obj})
# forms.py
class RegisterForm(forms.Form):
    user = fields.CharField()
    pwd = fields.CharField()

    # form 的第一類鉤子,字段的鉤子
    def clean_user(self):
        # 此鉤子是單純只處理user字段的驗證,其餘字段可單獨再次驗證。
        # 好比,def clean_pwd(self): ... 是單獨處理pwd字段。
        c = models.UserInfo.objects.filter(name=self.cleaned_data["user"]).count()
        if not c:
            return self.cleaned_data['user']
        else:
            from django.core.exceptions import ValidationError
            raise ValidationError("用戶名已存在", code="xx")

    #form 的第二類鉤子,總體的鉤子
    def clean(self):
        c = models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
        if c:
            # 這裏返回的是總體的數據,而不是分字段中的 self.cleaned_data['user']。
            return self.cleaned_data
        else:
            from django.core.exceptions import ValidationError
            raise ValidationError("用戶名密碼錯誤")

    # form 的第三類鉤子
    def _post_clean(self):
        pass

        from錯誤信息

# views.py
def register(request):
    from app01.forms import ResisterForm
    from django.core.exceptions import NON_FIELD_ERRORS
    obj = ResisterForm(request.POST)
    if obj.is_valid():
        # obj.cleaned_data
        return render(request, 'register.html', {'obj': obj})
    else:
        # obj.errors
        """
        {
            "__all__":[],        # 總體錯誤信息
            "NON_FIELD_ERRORS":[],        # 總體錯誤信息的另外一個方式
            "user":[{"code":"required","message":"xxxxx"}],
            "pwd":[{"code":"required","message":"xxxxx"}],
        }
        """
        return render(request, 'register.html', {'obj_error': obj.errors})

        form序列化錯誤信息

# views
import json
from django.shortcuts import HttpResponse
from django.core.exceptions import ValidationError

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ValidationError):
            return {'code': o.code, 'messages': o.messages}
        else:
            return json.JSONEncoder.default(self, o)

def login(request):
    if request.method == "GET":
        return render(request, "login.html")
    if request.method == "POST":
        ret = {'status': True, 'error': None, 'data': None}
        obj = LoginForm(request.POST)
        if obj.is_valid:
            print(obj.cleaned_data)
        else:
            ret["status"] = False
            ret['error'] = obj.errors.as_data()
        # json.dumps(str, cls=xx) cls參數是指定每次轉碼時觸發的函數
        result = json.dumps(ret, cls=JsonCustomEncoder)
        return HttpResponse(result)

        form序列化操做總結---- 萬變不離其宗

# views
# --------ErrorDict--------
# 自定義 encoder
import json
from django.core.exceptions import ValidationError

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ValidationError):
            return {'code': o.code, 'messages': o.messages}
        else:
            return json.JSONEncoder.default(self, o)



# --------QuerySet--------
# 第一種方式:serializers 模塊
from django.core import serializers
v = models.tb.objects.all()         # v是一個queryset類型
data = serializers.serialize("json", v)     # 進行序列化~~但格式是django指定的格式

# 第二種方式:
import json
from datetime import date
from datetime import datetime
from django.shortcuts import HttpResponse

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime):
            # 還記得strftime方法嗎?按照指定格式輸出字符串
            return field.strftime("%Y-%m-%d %H:%M:%S")
        elif isinstance(field, date):
            return field.strftime("%Y-%m-%d")
        else:
            # 若是是其餘類型,則按照默認方式轉碼
            return json.JSONEncoder.default(self, field)

def index(request):
    v = models.tb.objects.values("id", "name", "ctime")     # 這裏的ctime 是時間格式的呦~
    v = list(v)
    v = json.dumps(v, cls=JsonCustomEncoder)
    return HttpResponse(v)

十二、ModelForm---(不建議使用,應該使用Form和Model分離的方式)

    一、數據庫操做
    二、數據驗證
    適合小項目。或者,自定製admin

ModelForm
    a.  class Meta:
            model,                           # 對應Model的
            fields=None,                     # 加載Model中指定的字段,全選則fields="__all__"
            exclude=None,                    # 加載Model中沒有指定的字段
            labels=None,                     # 提示信息,相似Model的verbose_name
            help_texts=None,                 # 幫助提示信息
            widgets=None,                    # 自定義插件 django.forms import widgets as Fwidget |widgets={"指定的fields":fwidgets.Textarea}
            error_messages=None,             # 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS)
                                             # 錯誤信息例子:error_messages = {"name":{"required":"名字不能爲空"}}
            field_classes=None               # 自定義字段類 (也能夠自定義字段)
            localized_fields=('birth_date',) # 本地化,如:根據不一樣時區顯示數據
            如:
                數據庫中
                    2016-12-27 04:10:57
                setting中的配置
                    TIME_ZONE = 'Asia/Shanghai'
                    USE_TZ = True
                則顯示:
                    2016-12-27 12:10:57
    b. 驗證執行過程
        is_valid -> full_clean -> 鉤子 -> 總體錯誤
 
    c. 字典字段驗證
        def clean_字段名(self):
            # 能夠拋出異常
            # from django.core.exceptions import ValidationError
            return "新值"
    d. 用於驗證
        model_form_obj = XXOOModelForm()
        model_form_obj.is_valid()
        model_form_obj.errors.as_json()
        model_form_obj.clean()
        model_form_obj.cleaned_data
    e. 用於建立
        model_form_obj = XXOOModelForm(request.POST)
        #### 頁面顯示,並提交 #####
        # 默認保存多對多
            obj = form.save(commit=True)
        # 不作任何操做,內部定義 save_m2m(用於保存多對多)
            obj = form.save(commit=False)
            obj.save()      # 保存單表信息
            obj.save_m2m()  # 保存關聯多對多信息
 
    f. 用於更新和初始化
        obj = model.tb.objects.get(id=1)
        model_form_obj = XXOOModelForm(request.POST,instance=obj)
        ...
 
        PS: 單純初始化
            model_form_obj = XXOOModelForm(initial={...})

 

1四、Ajax操做

    一、原生ajax

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息