Python 14:Django

Python 14:Djangojavascript


一、web框架php

二、Django基本配置css

三、視圖html

四、路由系統前端

五、分頁java

六、ORM操做python

七、ajaxmysql

八、文件上傳jquery

九、Model操做nginx

十、Form組件驗證

十一、ModelForm操做

十二、cookie

1三、session

1四、跨站請求僞造

1五、中間件

1六、緩存

1七、信號

1八、動態驗證碼

1九、KindEditor

20、組合搜索

2一、JSONP跨域請求


1、web框架

一、web框架本質

對於全部的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端

 1 import socket
 2 def handle_request(client):
 3     buf = client.recv(1024)
 4     client.send("HTTP/1.1 200 OK\r\n\r\n".encode('utf-8'))
 5     client.send("Hello!!".encode('utf-8'))
 6 def main():
 7     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 8     sock.bind(('localhost',8000))
 9     sock.listen(5)
10     while True:
11         connection, address = sock.accept()
12         handle_request(connection)
13         connection.close()
14 if __name__ == '__main__':
15     main()
web

上述經過socket來實現了其本質,而對於真實開發中的python web程序來講,通常會分爲兩部分:服務器程序和應用程序。服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask、web.py 等。

WSGI(Web Server Gateway Interface)是一種規範,它定義了使用python編寫的web app與web server之間接口格式,實現web app與web server間的解耦

python標準庫提供的獨立WSGI服務器稱爲wsgiref

 1 from wsgiref.simple_server import make_server
 2 
 3 def RunServer(environ, start_response):
 4     #environ 客戶端發來的全部數據
 5     #start_response 封裝要返回給用戶的數據,響應頭
 6     start_response('200 OK', [('Content-Type', 'text/html')])
 7     #返回的內容
 8     return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]
 9 
10 if __name__ == '__main__':
11     httpd = make_server('', 8000, RunServer)
12     print("Serving HTTP on port 8000...")
13     httpd.serve_forever()
wsgi

二、自定義web框架

最簡單的web框架

 1 from wsgiref.simple_server import make_server
 2 
 3 def handle_index():
 4     return ['<h1>Hello,Index!</h1>'.encode('utf-8')]
 5 def handle_date():
 6     return ['<h1>Hello,Date!</h1>'.encode('utf-8')]
 7 
 8 
 9 def RunServer(environ, start_response):
10     #environ 客戶端發來的全部數據
11     #start_response 封裝要返回給客戶的數據,響應頭狀態
12     start_response('200 OK', [('Content-Type', 'text/html')])
13 
14     current_url = environ['PATH_INFO']
15     if current_url == '/index':
16         return handle_index()
17     elif current_url == '/date':
18         return handle_date()
19     else:
20         #返回的內容
21         return ['<h1>404</h1>'.encode('utf-8')]
22 
23 if __name__ == '__main__':
24     httpd = make_server('', 8000, RunServer)
25     print("Serving HTTP on port 8000...")
26     httpd.serve_forever()
web框架
 1 from wsgiref.simple_server import make_server
 2 
 3 def handle_index():
 4     return ['<h1>Hello,Index!</h1>'.encode('utf-8')]
 5 def handle_date():
 6     return ['<h1>Hello,Date!</h1>'.encode('utf-8')]
 7 
 8 URL_DICT= {
 9     '/index':handle_index,
10     '/date':handle_date
11 }
12 def RunServer(environ, start_response):
13     #environ 客戶端發來的全部數據
14     #start_response 封裝要返回給客戶的數據,響應頭狀態
15     start_response('200 OK', [('Content-Type', 'text/html')])
16     current_url = environ['PATH_INFO']
17     func = None
18     if current_url in URL_DICT:
19         func = URL_DICT[current_url]
20     if func:
21         return func()
22     else:
23         return ['<h1>404</h1>'.encode('utf-8')]
24     # if current_url == '/index':
25     #     return handle_index()
26     # elif current_url == '/date':
27     #     return handle_date()
28     # else:
29     #     #返回的內容
30     #     return ['<h1>404</h1>'.encode('utf-8')]
31 if __name__ == '__main__':
32     httpd = make_server('', 8000, RunServer)
33     print("Serving HTTP on port 8000...")
34     httpd.serve_forever()
調整url

在上一步驟中,對於全部的login、index均返回給用戶瀏覽器一個簡單的字符串,在現實的Web請求中通常會返回一個複雜的符合HTML規則的字符串,因此咱們通常將要返回給用戶的HTML寫在指定文件中,而後再返回;同理也能夠將定義的函數和數據庫內容放到單獨的文件當中。

 1 import time
 2 def handle_index():
 3     v = str(time.time())
 4     f = open('View/index.html',mode='rb')
 5     data = f.read()
 6     f.close()
 7     data = data.replace(b'@uuu', v.encode('utf-8'))
 8     return [data,]
 9 
10 def handle_date():
11     return ['<h1>Hello,Date!</h1>'.encode('utf-8')]
account
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>INDEX @uuu</h1>
</body>
</html>
index.html
 1 from wsgiref.simple_server import make_server
 2 from Controller import account
 3 
 4 URL_DICT= {
 5     '/index':account.handle_index,
 6     '/date':account.handle_date
 7 }
 8 
 9 def RunServer(environ, start_response):
10     #environ 客戶端發來的全部數據
11     #start_response 封裝要返回給客戶的數據,響應頭狀態
12     start_response('200 OK', [('Content-Type', 'text/html')])
13     current_url = environ['PATH_INFO']
14     func = None
15     if current_url in URL_DICT:
16         func = URL_DICT[current_url]
17     if func:
18         return func()
19     else:
20         return ['<h1>404</h1>'.encode('utf-8')]
21     # if current_url == '/index':
22     #     return handle_index()
23     # elif current_url == '/date':
24     #     return handle_date()
25     # else:
26     #     #返回的內容
27     #     return ['<h1>404</h1>'.encode('utf-8')]
28 if __name__ == '__main__':
29     httpd = make_server('', 8000, RunServer)
30     print("Serving HTTP on port 8000...")
31     httpd.serve_forever()
s2

三、web框架

MVC

Model       View         Controller

數據庫    模板文件    業務處理

MTV

Model      Template      View

數據庫     模板文件   業務處理

2、Django基本配置

一、建立Django程序

pip3 install django

添加環境變量C:\Python35\Scripts

建立Django工程:

終端命令:django-admin startproject 【工程名稱】(IDE建立Django程序時,本質上都是自動執行上述命令)

運行Django功能:python manage.py runserver 127.0.0.1:8001

二、目錄詳解

django_zz

  - django_zz # 對整個程序進行配置

    - init

    - settings # 配置文件

    - url # URL對應關係

    - wsgi # 一套接口規則、遵循WSIG規範,上線時不能用自帶的wsgi須要(uwsgi + nginx)

  - manage.py # 管理Django程序:

    - python manage.py 

    - python manage.py startapp xx

    - python manage.py makemigrations

    - python manage.py migrate

三、建立app

  -python manage.py startapp cmdb

  -python manage.py startapp openstack

  -python manage.py startapp .......

 (代碼放在建立的app下的view中)

1 from django.shortcuts import render
2 
3 # Create your views here.
4 from django.shortcuts import HttpResponse
5 
6 def home(request):
7     return HttpResponse('<h1>CMDB</h1>')
View

URL對應關係

1 from django.contrib import admin
2 from django.urls import path
3 from cmdb import views
4 
5 urlpatterns = [
6     path('admin/', admin.site.urls),
7     path('h.html/', views.home),
8 ]
url

app目錄:

  - migrations 數據修改表結構(Django自動生成)

  - admin Django爲咱們提供的後臺管理

  - apps 配置當前app

  - models ORM,寫指定的類 經過命令能夠建立數據庫結構

  - tests 單元測試

  - views 業務代碼

四、建立完project後作的事情

a.建立app

cd 工程名

python manage.py startapp cmdb

b.配置模板的路徑(新版Django自動配置)

project/project/settings.py中

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',
      ],
    },
  },
]

c.配置靜態文件目錄(static)

project/project/settings.py末尾

STATICFILES_DIRS = (

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

)

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

d.settings中

找到middlerware

註釋:# 'django.middleware.csrf.CsrfViewMiddleware',

e.定義路由規則

在url.py中寫對應關係:"login" --> 函數名

path('login', views.login),

path('home', views.home),

f.定義視圖函數

app下views.py

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

from django.shortcuts import render

# Create your views here.
from django.shortcuts import HttpResponse
from django.shortcuts import render
from django.shortcuts import redirect

def home(request):
    if request.method == 'POST':
        #獲取用戶提交的數據POST請求
        u = request.POST.get('username')
        e = request.POST.get('email')
        g = request.POST.get('gender')
        temp = {'username':u,'email':e,'gender':g}
        USER_LIST.append(temp)
    # return HttpResponse('<h1>CMDB</h1>')
    return render(request,'home.html',{'user_list': USER_LIST})

USER_LIST = [
    {'username':'zz','email':'qq@qq','gender':'m'}
]

# for item in range(20):
#     temp = {'username':'zz' + str(item),'email':'ee@ee','gender':'m'}
#     USER_LIST.append(temp)


def login(request):
    #獲取用戶提交方法

    error_msg = ''
    print(request.method)
    if request.method == 'POST':
        #用戶經過post提交過來的數據
        # user = request.POST['user']
        # pwd = request.POST['pwd']
        # print(user,pwd)
        user = request.POST.get('user',None)
        pwd = request.POST.get('pwd',None)
        print(user,pwd)
        if user == 'root' and pwd == '123':
            return redirect('/home')
        else:
            #用戶密碼不匹配
            error_msg = '用戶名或密碼錯誤'
    return render(request,'login.html',{'error_msg':error_msg})


# def login(request):
    # string = '''
    # <form>
    #     <input type='text' />
    # </form>
    # '''


    # f = open('templates/login.html','r',encoding='utf-8')
    # data = f.read()
    # f.close()
    # return HttpResponse(data)

    # return render(request,'login.html')
views

g.模板語言

一、特殊的模板語言

元組列表直接循環,字典循環不加括號

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <ul>
 9 {#        {% for item in user_dict.values %}#}
10 {#        {% for item in user_dict.keys %}#}
11         {% for k,item in user_dict.items %}
12             <li>{{ k }}:{{ item }}</li>
13         {% endfor %}
14     </ul>
15 
16 </body>
17 </html>
index.html
 1 USER_DICT = {
 2     '1':{'name':'root1','email':'root@aaa.com'},
 3     '2':{'name':'root2','email':'root@aaa.com'},
 4     '3':{'name':'root3','email':'root@aaa.com'},
 5     '4':{'name':'root4','email':'root@aaa.com'},
 6     '5':{'name':'root5','email':'root@aaa.com'},
 7 }
 8 
 9 
10 
11 def index(request):
12     return render(request,'index.html',{'user_dict':USER_DICT})
views.py
  1 特殊的模板語言
  2         
  3             -- {{ 變量名 }}
  4         
  5                 def func(request):
  6                     return render(request, "index.html", {'current_user': "alex"})
  7         
  8                     
  9                 index.html
 10                 
 11                 <html>
 12                 ..
 13                     <body>
 14                         <div>{{current_user}}</div>
 15                     </body>
 16                 
 17                 </html>
 18                 
 19                 ====> 最後生成的字符串
 20                 
 21                 <html>
 22                 ..
 23                     <body>
 24                         <div>alex</div>
 25                     </body>
 26                 
 27                 </html>
 28             -- For循環
 29                 def func(request):
 30                     return render(request, "index.html", {'current_user': "alex", 'user_list': ['alex','eric']})
 31         
 32                     
 33                 index.html
 34                 
 35                 <html>
 36                 ..
 37                     <body>
 38                         <div>{{current_user}}</div>
 39                         
 40                         <ul>
 41                             {% for row in user_list %}
 42                             
 43                                 {% if row == "alex" %}
 44                                     <li>{{ row }}</li>
 45                                 {% endif %}
 46                                 
 47                             {% endfor %}
 48                         </ul>
 49                         
 50                     </body>
 51                 
 52                 </html>
 53                 
 54             #####索引################# 
 55                 def func(request):
 56                     return render(request, "index.html", {
 57                                 'current_user': "alex", 
 58                                 'user_list': ['alex','eric'], 
 59                                 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
 60         
 61                     
 62                 index.html
 63                 
 64                 <html>
 65                 ..
 66                     <body>
 67                         <div>{{current_user}}</div>
 68                         
 69                         <a> {{ user_list.1 }} </a>
 70                         <a> {{ user_dict.k1 }} </a>
 71                         <a> {{ user_dict.k2 }} </a>
 72                         
 73                     </body>
 74                 
 75                 </html>
 76             
 77             ###### 條件
 78             
 79                 def func(request):
 80                     return render(request, "index.html", {
 81                                 'current_user': "alex", 
 82                                 "age": 18,
 83                                 'user_list': ['alex','eric'], 
 84                                 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
 85         
 86                     
 87                 index.html
 88                 
 89                 <html>
 90                 ..
 91                     <body>
 92                         <div>{{current_user}}</div>
 93                         
 94                         <a> {{ user_list.1 }} </a>
 95                         <a> {{ user_dict.k1 }} </a>
 96                         <a> {{ user_dict.k2 }} </a>
 97                         
 98                         {% if age %}
 99                             <a>有年齡</a>
100                             {% if age > 16 %}
101                                 <a>老男人</a>
102                             {% else %}
103                                 <a>小鮮肉</a>
104                             {% endif %}
105                         {% else %}
106                             <a>無年齡</a>
107                         {% endif %}
108                     </body>
109                 
110                 </html>
模板語言

二、模板繼承

母版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %}</title>
    <link rel="stylesheet" href="/static/commons.css"/>
    <style>
        .pg-header{
            height: 48px;
            background-color: black;
            color: white;
        }
    </style>
{#    爲子板提供單獨css樣式#}
    {% block css %}{% endblock %}
</head>
<body>
    <div class="pg-header">
        系統管理
    </div>
    {% block content %} {% endblock %}
    <script src="/static/js.js"></script>
{#    爲子板提供單獨js樣式#}
    {% block js %} {% endblock %}
</body>
</html>
master.html

子板

{#繼承那個模板#}
{% extends 'master.html' %}
{#替換模板的那個模塊#}
{% block title %}用戶管理{% endblock %}
{% block content %}
    <h1>用戶管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
        {% endfor %}
    </ul>
{% endblock %}
{#設置單獨css樣式#}
{% block css %}
    <style>
        body{
            background-color: aqua;
        }
    </style>
{% endblock %}
tlp1.html

三、模板導入

模版

<form>
    <input type="text"/>
    <input type="submit"/>
</form>
tag.html

導入模板

{#繼承那個模板#}
{% extends 'master.html' %}
{% block content %}
    <h1>用戶管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
            {#導入模板#}
            {% include 'tag.html' %}
        {% endfor %}
    </ul>
    {#導入模板#}
    {% include 'tag.html' %}
    {% include 'tag.html' %}    
{% endblock %}
tpl.html

四、自定義simple_tag

4.一、在某個app下建立templatetags目錄

4.二、建立任意.py文件,例:zz.py

4.三、編寫函數(template對象名稱必須是register)

 1 from django import template
 2 from django.utils.safestring import mark_safe
 3 
 4 register = template.Library()
 5 @register.simple_tag
 6 def jj(a1,a2):
 7     return a1 + a2
 8 
 9 @register.simple_tag
10 def pp():
11     return 123
zz.py

4.四、在settings中配置當前app,否則django沒法找到自定義的simple_tag

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

4.五、在使用自定義simple_tag的html文件中導入以前建立的 xx.py 文件名(在頂部)  

{% load zz %}

4.六、使用simple_tag

{% 函數名 arg1 arg2%}
{% pp %}
 1 {% load zz %}
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title></title>
 7 </head>
 8 <body>
 9     {{ name }}
10     {{ name|lower  }}
11     {% jj 3 7%}
12     {% pp %}
13 </body>
14 </html>
zz.html

 五、自定義filter

函數(最多隻能有兩個參數)

1 from django import template
2 from django.utils.safestring import mark_safe
3 
4 register = template.Library()
5 
6 @register.filter
7 def qq(a1,a2):
8     return a1 + a2
zz.py

使用filter:

{{ '參數1'|函數名:'參數2' }}

filter主要用在if...else判斷裏,用於if條件 

3、視圖

一、獲取用戶請求數據

  request.GET

  request.POST

  request.FILES

PS:

  GET:獲取數據 

  POST:提交數據

獲取cookie信息

request.cookie

獲取用戶請求相關信息及請求頭

from django.core.handleers.wsgi import WSGIRequest

request.environ

request.environ['HTTP_USER_AGENT'] 

二、checkbox等多選的內容

  request.POST.getlist()

三、上傳文件

# 上傳文件,form標籤作特殊設置:<form action="/login/" method="post" enctype="multipart/form-data">

  obj = request.FILES.get('fafafa')

  obj.name

  f = open(obj.name, mode='wb')

  for item in obj.chunks():

  f.write(item)

  f.close()

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/login/" method="post" enctype="multipart/form-data">
 9         <p>
10             <input type="text" name="user" placeholder="用戶名"/>
11         </p>
12         <p>
13             <input type="password" name="pwd" placeholder="密碼"/>
14         </p>
15         <p>
16             男:<input type="radio" name="gender" value="1"/>
17             女:<input type="radio" name="gender" value="2"/>
18             你猜:<input type="radio" name="gender" value="3"/>
19         </p>
20         <p>
21             男:<input type="checkbox" name="favor" value="1"/>
22             女:<input type="checkbox" name="favor" value="2"/>
23             你猜:<input type="checkbox" name="favor" value="3"/>
24         </p>
25         <p>
26             <select name="city">
27                 <option value="bj">北京</option>
28                 <option value="sh">上海</option>
29                 <option value="tj">天津</option>
30             </select>
31         </p>
32         <p>
33             <input type="file" name="fff"/>
34         </p>
35 
36         <input type="submit" value="提交"/>
37 
38     </form>
39 </body>
40 </html>
login.html
 1 from django.shortcuts import render,HttpResponse,redirect
 2 
 3 # Create your views here.
 4 def index(request):
 5     return HttpResponse('index')
 6 # def login(request):
 7 #     if request.method == 'GET':
 8 #         return render(request,'login.html')
 9 #     elif request.method == 'POST':
10 #         u = request.POST.get('user')
11 #         p = request.POST.get('pwd')
12 #         if u == 'zz'and p == '123':
13 #             return redirect('/index/')
14 #         else:
15 #             return render(request,'login.html')
16 #     else:
17 #         return redirect('/index/')
18 #     return render(request,'login.html')
19 
20 def login(request):
21     if request.method == 'GET':
22         return render(request,'login.html')
23     elif request.method == 'POST':
24         #radio
25         # v = request.POST.get('gender')
26         # print(v)
27 
28         #checkbox
29         # v = request.POST.getlist('favor')
30         # print(v)
31 
32         # select
33         # v = request.POST.get('city')
34         # print(v)
35 
36         #file
37         # v = request.POST.get('fff')
38         # print(v)  #只會拿到文件 名��
39         import os
40         v = request.FILES.get('fff')
41         print(v,type(v),v.name)
42 
43         file_path = os.path.join('upload',v.name)
44         f = open(file_path,mode='wb')
45         for i  in v.chunks():
46             f.write(i)
47         f.close()
48 
49 
50     else:
51         return redirect('/index/')
52     return render(request,'login.html')
views.py
 1 """s14day19 URL Configuration
 2 
 3 The `urlpatterns` list routes URLs to views. For more information please see:
 4     https://docs.djangoproject.com/en/2.1/topics/http/urls/
 5 Examples:
 6 Function views
 7     1. Add an import:  from my_app import views
 8     2. Add a URL to urlpatterns:  path('', views.home, name='home')
 9 Class-based views
10     1. Add an import:  from other_app.views import Home
11     2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
12 Including another URLconf
13     1. Import the include() function: from django.urls import include, path
14     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
15 """
16 from django.contrib import admin
17 from django.urls import path
18 from app01 import views
19 
20 urlpatterns = [
21     path('admin/', admin.site.urls),
22     path('index/', views.index),
23     path('login/', views.login),
24 
25 ]
urls.py

四、FBV & CBV

function base view

url.py

  index -> 函數名

view.py

  def 函數(request):

    ...(函數內容)

前面寫的都是FBV對應關係

 1 """s14day19 URL Configuration
 2 
 3 The `urlpatterns` list routes URLs to views. For more information please see:
 4     https://docs.djangoproject.com/en/2.1/topics/http/urls/
 5 Examples:
 6 Function views
 7     1. Add an import:  from my_app import views
 8     2. Add a URL to urlpatterns:  path('', views.home, name='home')
 9 Class-based views
10     1. Add an import:  from other_app.views import Home
11     2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
12 Including another URLconf
13     1. Import the include() function: from django.urls import include, path
14     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
15 """
16 from django.contrib import admin
17 from django.urls import path
18 from app01 import views
19 
20 urlpatterns = [
21     path('admin/', admin.site.urls),
22     path('index/', views.index),
23     path('login/', views.login),
24 
25 ]
urls.py
 1 from django.shortcuts import render,HttpResponse,redirect
 2 
 3 # Create your views here.
 4 def index(request):
 5     return HttpResponse('index')
 6 # def login(request):
 7 #     if request.method == 'GET':
 8 #         return render(request,'login.html')
 9 #     elif request.method == 'POST':
10 #         u = request.POST.get('user')
11 #         p = request.POST.get('pwd')
12 #         if u == 'zz'and p == '123':
13 #             return redirect('/index/')
14 #         else:
15 #             return render(request,'login.html')
16 #     else:
17 #         return redirect('/index/')
18 #     return render(request,'login.html')
19 
20 def login(request):
21     if request.method == 'GET':
22         return render(request,'login.html')
23     elif request.method == 'POST':
24         #radio
25         # v = request.POST.get('gender')
26         # print(v)
27 
28         #checkbox
29         # v = request.POST.getlist('favor')
30         # print(v)
31 
32         # select
33         # v = request.POST.get('city')
34         # print(v)
35 
36         #file
37         # v = request.POST.get('fff')
38         # print(v)  #只會拿到文件 名��
39         import os
40         v = request.FILES.get('fff')
41         print(v,type(v),v.name)
42 
43         file_path = os.path.join('upload',v.name)
44         f = open(file_path,mode='wb')
45         for i  in v.chunks():
46             f.write(i)
47         f.close()
48 
49 
50     else:
51         return redirect('/index/')
52     return render(request,'login.html')
views.py

====》Django兩種對應關係

  /index/ -> 函數名

  /index/ -> 類

CBV對應關係

class base view

1 urlpatterns = [
2     path('admin/', admin.site.urls),
3     path('index/', views.index),
4     path('login/', views.login),
5     # path('home/', views.home),
6     path('home/', views.Home.as_view()),
7 
8 ]
urls.py
 1 from django.shortcuts import render,HttpResponse,redirect
 2 
 3 # Create your views here.
 4 from django.views import  View
 5 class Home(View):
 6     def dispatch(self,request,*args,**kwargs):
 7         print('before')
 8         result = super(Home,self).dispatch(request,*args,**kwargs)
 9         print('after')
10         return result
11     def get(self,request):
12         print(request.method)
13         return render(request,'home.html')
14     def post(self,request):
15         print(request.method)
16         return render(request,'home.html')
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/home/" method="post">
 9         <input type="text" name="user"/>
10         <input type="submit"/>
11     </form>
12 </body>
13 </html>
home.html

====》建議:二者都用

五、CBV和FBV用戶認證裝飾器

 1 user_info={
 2     "zz":{'pwd':'123'}
 3 }
 4 def login(requset):
 5     if requset.method == 'GET':
 6         return render(requset,'login.html')
 7     if requset.method == 'POST':
 8         u = requset.POST.get('username')
 9         p = requset.POST.get('pwd')
10         dic = user_info.get(u)
11         if not dic:
12             return render(requset,'login.html')
13         if dic['pwd'] == p:
14             res = redirect('/index/')
15             res.set_cookie('username',u)
16             return res
17         else:
18             return render(requset,'login.html')
19 
20 def auth(func):
21     def inner(request,*args,**kwargs):
22         v = request.COOKIES.get('username')
23         if not v:
24             return redirect('/login/')
25         return func(request,*args,**kwargs)
26     return inner
27 
28 @auth
29 def index(request):
30     v = request.COOKIES.get('username')
31     return render(request,'index.html',{'current_user':v})
FBV裝飾器
 1 from django import views
 2 from django.utils.decorators import method_decorator
 3 #對全部方法生效
 4 @method_decorator(auth,name='dispatch')
 5 class Order(views.View):
 6     # 對全部的方法都生效
 7     # @method_decorator(auth)
 8     # def dispatch(self, request, *args, **kwargs):
 9     #     return super(Order,self).dispatch(request,*args,**kwargs)
10 
11     # 只對單一方法作裝飾(django自帶)
12     # @method_decorator(auth)
13     def get(self,request):
14         v = request.COOKIES.get('username')
15         return render(request,'index.html',{'current_user':v})
16     def post(self,request):
17         v = request.COOKIES.get('username')
18         return render(request,'index.html',{'current_user':v})
CBV裝飾器

4、路由系統

一、單一路由對應

from django.urls import path

  path('admin/', admin.site.urls),

  path('index/', views.index),

from django.conf.urls import url

  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 PS:
 2     def detail(request, *args,**kwargs):
 3         pass
 4 實戰:
 5     a. 
 6         url(r'^detail-(\d+)-(\d+).html', views.detail),        
 7         def func(request, nid, uid):            
 8             pass    
 9         def func(request, *args):
10             args = (2,9)           
11         def func(request, *args, **kwargs):
12             args = (2,9)
13     b. 
14         url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)        
15         def func(request, nid, uid):
16             pass            
17         def funct(request, **kwargs):
18             kwargs = {'nid': 1, 'uid': 3}            
19         def func(request, *args, **kwargs):
20             args = (2,9)
正則路由

三、設置路由映射名稱

本質:對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'),

設置名稱以後,能夠在不一樣的地方調用,如:

(模板中使用生成URL     {% url 'h2' 2012 %}

函數中使用生成URL     reverse('h2', args=(2012,))      路徑:django.urls.reverse

Model中使用獲取URL  自定義get_absolute_url() 方法)

 1 def func(request, *args, **kwargs):
 2     from django.urls import reverse    
 3     url1 = reverse('i1')                              # asdfasdfasdf/
 4     url2 = reverse('i2', args=(1,2,))                 # yug/1/2/
 5     url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/
 6 xxx.html    
 7     {% url "i1" %}               # asdfasdfasdf/
 8     {% url "i2" 1 2 %}           # yug/1/2/
 9     {% url "i3" pid=1 nid=9 %}   # buy/1/9/
10 注:
11     # 當前的URL
12     request.path_info 
對應關係

四、多級路由:根據app對路由規則進行分類

project/urls.py

1 from django.conf.urls import url,include
2 from django.contrib import admin
3 urlpatterns = [
4     url(r'^cmdb/', include("app01.urls")),
5     url(r'^monitor/', include("app02.urls")),
6 ]
project/urls.py

app01/urls.py

1 from django.conf.urls import url,include
2 from django.contrib import admin
3 from app01 import views
4 urlpatterns = [
5     url(r'^login/', views.login),
6 ]
app01/urls.py

app02/urls.py

1 from django.conf.urls import url,include
2 from django.contrib import admin
3 from app02 import views
4 urlpatterns = [
5     url(r'^login/', views.login),
6 ]
app02/urls.py

五、添加額外參數

url(r'^manage/(?P<name>\w*)', views.manage,{'id':333}),

六、命名空間

不使用命名空間,且兩個APP某條url使用相同的name屬性

from django.conf.urls import url,include
urlpatterns = [
    url(r'^a/', include('app01.urls')),
    url(r'^b/', include('app02.urls')),
]
project/urls
from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^index/', views.index, name='index')
]
app01/urls
from django.conf.urls import url
from app02 import views
urlpatterns = [
    url(r'^index/', views.index, name='index')
]
app02/urls
from django.shortcuts import render,HttpResponse
from django.urls import reverse
def index(request):
    print('app01')
    return HttpResponse(reverse('index'))
app01/views.py
from django.shortcuts import render,HttpResponse
from django.urls import reverse
def index(request):
    print('app02')
    return HttpResponse(reverse('index'))
app02/views.py

顯示結果:

#app01:(print:app01)/b/index/

#app02:(print:app02)/b/index/

緣由:因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回

咱們在開發項目時,會常用name屬性反解出URL,當不當心定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間:

namespace參數:

from django.conf.urls import url,include
urlpatterns = [
    url(r'^a/', include('app01.urls',namespace='aaa')),
    url(r'^b/', include('app02.urls',namespace='bbb')),
]
project/urls
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
    url(r'^index/', views.index, name='index')
]
app01/urls
from django.conf.urls import url
from app02 import views
app_name = 'app02'
urlpatterns = [
    url(r'^index/', views.index, name='index')
]
app02/urls
from django.shortcuts import render,HttpResponse
from django.urls import reverse
def index(request):
    v = reverse('app01:index')
    print(v)
    print(reverse('aaa:index'))
    return HttpResponse(reverse('aaa:index'))
app01/views.py
from django.shortcuts import render,HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
    v = reverse('app02:index')
    print(v)
    print(reverse('bbb:index'))
    return HttpResponse(reverse('bbb:index'))
app02/views.py

頁面顯示結果:

http://127.0.0.1:8000/a/index/:/a/index/

http://127.0.0.1:8000/b/index/:/b/index/ 

5、分頁

一、自定義分頁

from django.shortcuts import render,HttpResponse
from django.urls import reverse
from django.utils.safestring import mark_safe
LIST = []
for i in range(1009):
    LIST.append(i)
def user_list(request):
    current_page = request.GET.get('p',1)
    current_page = int(current_page)
    per_page_count = 10
    pager_num = 9
    start = (current_page -1) * per_page_count
    end = current_page * per_page_count
    data = LIST[start:end]
    all_count = len(LIST)
    count,y = divmod(all_count,per_page_count)
    if y:
        count += 1
    page_list = []
    # start_index = current_page - 5
    # end_index = current_page + 6
    if count < pager_num:
        start_index = 1
        end_index = count+1
    else:
        if current_page <=(pager_num + 1)/2:
            start_index = 1
            end_index = pager_num + 1
        else:
            start_index = current_page - (pager_num - 1)/2
            end_index = current_page + (pager_num + 1)/2
            if (current_page + (pager_num - 1)/2) > count:
                end_index = count + 1
                start_index = count - pager_num + 1
    if current_page == 1:
        prev = '<a class="page" href="#">上一頁</a>'
    else:
        prev = '<a class="page" href="/user_list/?p=%s">上一頁</a>'%(current_page-1)
    page_list.append(prev)
    for i in range(int(start_index),int(end_index)):
        if i == current_page:
            temp = '<a class="page active" href="/user_list/?p=%s">%s</a>'%(i,i)
        else:
            temp = '<a class="page" href="/user_list/?p=%s">%s</a>'%(i,i)
        page_list.append(temp)
    if current_page == count:
        nex = '<a class="page" href="javascript:void(0);">下一頁</a>'
    else:
        nex = '<a class="page" href="/user_list/?p=%s">下一頁</a>'%(current_page+1)
    page_list.append(nex)

    jump = """
    <input type="text"/><a onclick='jumpTo(this,"/user_list/?p=");'>GO</a>
    <script>
        function jumpTo(ths,base){
            var val = ths.previousSibling.value;
            location.href = base + val;
        }
    </script>
    """
    page_list.append(jump)
    page_str = ''.join(page_list)
    page_str = mark_safe(page_str)
    return render(request,'user_list.html',{'li':data,'page_str':page_str})
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pagination .page{
            display: inline-block;
            padding: 5px;
            margin: 5px;
        }
        .pagination .page.active{
            color: white;
            background-color: black;
        }
    </style>
</head>
<body>
    <ul>
        {% for item in li %}
            {% include 'li.html' %}
        {% endfor %}
    </ul>
    <div class="pagination">
        {{ page_str }}
    </div>

</body>
</html>
user_list.html

二、生成公共模塊:

from django.shortcuts import render,HttpResponse
from django.urls import reverse
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 all_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.all_count < self.pager_num:
            start_index = 1
            end_index = self.all_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.all_count:
                    end_index = self.all_count + 1
                    start_index = self.all_count - self.pager_num + 1
        if self.current_page == 1:
            prev = '<a class="page" href="#">上一頁</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.all_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 = ''.join(page_list)
        page_str = mark_safe(page_str)
        return page_str





LIST = []
for i in range(1009):
    LIST.append(i)
def user_list(request):
    current_page = request.GET.get('p',1)
    current_page = int(current_page)
    page_obj = Page(current_page,len(LIST),)
    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})
pagination.py

6、ORM操做

一、基本操做

a.語句對應關係:

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

 1 # 獲取個數
 2         #
 3         # models.Tb1.objects.filter(name='seven').count()
 4 
 5         # 大於,小於
 6         #
 7         # models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
 8         # models.Tb1.objects.filter(id__gte=1)              # 獲取id大於等於1的值
 9         # models.Tb1.objects.filter(id__lt=10)             # 獲取id小於10的值
10         # models.Tb1.objects.filter(id__lte=10)             # 獲取id小於10的值
11         # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
12 
13         # in
14         #
15         # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於十一、2二、33的數據
16         # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
17 
18         # isnull
19         # Entry.objects.filter(pub_date__isnull=True)
20 
21         # contains
22         #
23         # models.Tb1.objects.filter(name__contains="ven")
24         # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
25         # models.Tb1.objects.exclude(name__icontains="ven")
26 
27         # range
28         #
29         # models.Tb1.objects.filter(id__range=[1, 2])   # 範圍bettwen and
30 
31         # 其餘相似
32         #
33         # startswith,istartswith, endswith, iendswith,
34 
35         # order by
36         #
37         # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
38         # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
39 
40         # group by
41         #
42         # from django.db.models import Count, Min, Max, Sum
43         # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
44         # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
45 
46         # limit 、offset
47         #
48         # models.Tb1.objects.all()[10:20]
49 
50         # regex正則匹配,iregex 不區分大小寫
51         #
52         # Entry.objects.get(title__regex=r'^(An?|The) +')
53         # Entry.objects.get(title__iregex=r'^(an?|the) +')
54 
55         # date
56         #
57         # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
58         # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
59 
60         # year
61         #
62         # Entry.objects.filter(pub_date__year=2005)
63         # Entry.objects.filter(pub_date__year__gte=2005)
64 
65         # month
66         #
67         # Entry.objects.filter(pub_date__month=12)
68         # Entry.objects.filter(pub_date__month__gte=6)
69 
70         # day
71         #
72         # Entry.objects.filter(pub_date__day=3)
73         # Entry.objects.filter(pub_date__day__gte=3)
74 
75         # week_day
76         #
77         # Entry.objects.filter(pub_date__week_day=2)
78         # Entry.objects.filter(pub_date__week_day__gte=2)
79 
80         # hour
81         #
82         # Event.objects.filter(timestamp__hour=23)
83         # Event.objects.filter(time__hour=5)
84         # Event.objects.filter(timestamp__hour__gte=12)
85 
86         # minute
87         #
88         # Event.objects.filter(timestamp__minute=29)
89         # Event.objects.filter(time__minute=46)
90         # Event.objects.filter(timestamp__minute__gte=29)
91 
92         # second
93         #
94         # Event.objects.filter(timestamp__second=31)
95         # Event.objects.filter(time__second=2)
96         # Event.objects.filter(timestamp__second__gte=31)
進階操做

b.建立:

先寫類:

from django.db import models

# Create your models here.

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

註冊app:

1 INSTALLED_APPS = [
2     'django.contrib.admin',
3     'django.contrib.auth',
4     'django.contrib.contenttypes',
5     'django.contrib.sessions',
6     'django.contrib.messages',
7     'django.contrib.staticfiles',
8     'app01',
9 ]
settings下的INSTALLED_APPS

執行命令:

python manage.py makemigrations

python manage.py migrate

c.連接其餘數據庫

Django默認使用的是sqlite

 1 DATABASES = {
 2     'default': {
 3     'ENGINE': 'django.db.backends.mysql',
 4     'NAME':'dbname',
 5     'USER': 'root',
 6     'PASSWORD': 'xxx',
 7     'HOST': '',
 8     'PORT': '',
 9     }
10 }
11 
12 # 因爲Django內部鏈接MySQL時使用的是MySQLdb模塊,而python3中還無此模塊,因此須要使用pymysql來代替  
13 # 以下設置放置的與project同名的配置的 __init__.py文件中  
14 import pymysql
15 pymysql.install_as_MySQLdb() 
連接mysql

 二、其餘操做

 1 from app01 import models
 2 def orm(request):
 3     # 建立1
 4     models.UserInfo.objects.create(username = 'root',passwoed = '123')
 5     # 建立2
 6     dic = {'username':'zz','passwoed':'123'}
 7     models.UserInfo.objects.create(**dic)
 8     # 建立3
 9     obj = models.UserInfo(username = 'mysql',passwoed = '123')
10     obj.save()
11 
12     #
13     result = models.UserInfo.objects.all()  #查全部
14     result = models.UserInfo.objects.filter(username = 'root',passwoed = '123') #按條件查
15     # result,QuerySet =>Django => []
16     # [obj(id,usermane,password),obj.obj]
17     for row in result:
18         print(row.id,row.username,row.passwoed)
19     print(result)
20 
21     #
22     models.UserInfo.objects.filter(id=2).delete()
23 
24     # 更新
25     models.UserInfo.objects.all().update(passwoed = 888)
26     models.UserInfo.objects.filter(id = 3).update(passwoed = 123)
27 
28     return HttpResponse('orm')
orm增刪改查
 1 '''
 2 # extra
 3 extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
 4    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
 5    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
 6    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
 7    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
 8 
 9 # F
10 from django.db.models import F
11 models.Tb1.objects.update(num=F('num')+1)
12 
13 # Q
14 # 方式一:
15 Q(nid__gt=10)
16 Q(nid=8) | Q(nid__gt=10)
17 Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
18 
19 # 方式二:
20 con = Q()
21 q1 = Q()
22 q1.connector = 'OR'
23 q1.children.append(('id', 1))
24 q1.children.append(('id', 10))
25 q1.children.append(('id', 9))
26 q2 = Q()
27 q2.connector = 'OR'
28 q2.children.append(('c1', 1))
29 q2.children.append(('c1', 10))
30 q2.children.append(('c1', 9))
31 con.add(q1, 'AND')
32 con.add(q2, 'AND')
33 models.Tb1.objects.filter(con)
34 
35 # 執行原生SQL
36 from django.db import connection, connections
37 cursor = connection.cursor()  # cursor = connections['default'].cursor()
38 cursor.execute("""SELECT * from auth_user where id = %s""", [1])
39 row = cursor.fetchone()
40 '''
進階操做

示例:

基於ORM實現用戶登陸:

1 urlpatterns = [
2     url(r'^login/', views.login),
3 ]
urls.py
 1 def login(request):
 2     if request.method == 'GET':
 3         return render(request,'login.html')
 4     elif request.method == 'POST':
 5         #數據庫中執行select * from user where username = 'x' and password = 'x'
 6         u = request.POST.get('user')
 7         p = request.POST.get('pwd')
 8 
 9         # obj = models.UserInfo.objects.filter(username=u,passwoed=p).first()
10         # print(obj)
11 
12         # count = models.UserInfo.objects.filter(username=u,passwoed=p).count()
13         # print(count)
14 
15         obj = models.UserInfo.objects.filter(username=u,passwoed=p).first()
16         if obj:
17             return redirect('/cmdb/index/')
18         else:
19             return render(request,'login.html')
20     else:
21         return redirect('/index/')
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/cmdb/login/" method="post" enctype="multipart/form-data">
 9         <p>
10             <input type="text" name="user" placeholder="用戶名"/>
11         </p>
12         <p>
13             <input type="password" name="pwd" placeholder="密碼"/>
14         </p>
15         <input type="submit" value="提交"/>
16     </form>
17 </body>
18 </html>
login.html

用戶登陸成功跳轉用戶管理界面,基於ORM實現用戶的增刪改查功能:

1 urlpatterns = [
2     url(r'^login/', views.login),
3     url(r'^index/', views.index),
4     url(r'^user_info/', views.user_info),
5     url(r'^userdetail-(?P<nid>\d+)/', views.user_detail),
6     url(r'^userdel-(?P<nid>\d+)/', views.user_del),
7     url(r'^useredit-(?P<nid>\d+)/', views.user_edit),
8     url(r'^orm/', views.orm),
9 ]
urls.py
 1 def user_info(request):
 2     if request.method == 'GET':
 3         user_list = models.UserInfo.objects.all()
 4         # return render(request,'user_info.html')
 5         return render(request,'user_info.html',{'user_list':user_list})
 6     elif request.method == "POST":
 7         u = request.POST.get('user')
 8         p = request.POST.get('pwd')
 9         models.UserInfo.objects.create(username=u,passwoed=p)
10         return redirect('/cmdb/user_info')
11 
12 def user_detail(request,nid):
13     obj = models.UserInfo.objects.filter(id=nid).first()
14     # models.UserInfo.objects.get(id=nid) #取單條數據若是不存在報錯
15     return render(request,'user_detail.html',{'obj':obj})
16 def user_del(request,nid):
17     models.UserInfo.objects.filter(id=nid).delete()
18     return redirect('/cmdb/user_info')
19 def user_edit(request,nid):
20     if request.method == 'GET':
21         obj = models.UserInfo.objects.filter(id=nid).first()
22         return render(request,'user_edit.html',{'obj':obj})
23     elif request.method == 'POST':
24         nid = request.POST.get('id')
25         u = request.POST.get('username')
26         p = request.POST.get('passwoed')
27         models.UserInfo.objects.filter(id=nid).update(username=u,passwoed=p)
28     return redirect('/cmdb/user_info')
29 
30 
31 def detail(request,nid):
32     # return HttpResponse(nid)
33     # nid = request.GET.get('nid')
34     detail_info = USER_DICT[nid]
35     return render(request,'detail.html',{'detail_info':detail_info})
Views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6     <style>
 7         body{
 8             margin: 0;
 9         }
10         .menu{
11             display: block;
12             padding: 5px;
13         }
14     </style>
15 </head>
16 <body>
17 <!--
18 {#    <ul>#}
19 {#        {% for item in user_dict.values %}#}
20 {#        {% for item in user_dict.keys %}#}
21 {#        {% for k,item in user_dict.items %}#}
22 {#            <li><a target="_blank" href="/detail/?nid={{ k }}">{{ item.name }}</a></li>#}
23 {#        {% endfor %}#}
24 {#    </ul>#}
25 {##}
26 {#    <form action="{% url 'indexx' %}" method="POST">#}
27 {#        <p><input type="text" name="user" placeholder="用戶名"/></p>#}
28 {#        <p><input type="text" name="email" placeholder="郵箱"/></p>#}
29 {#        <input type="submit" value="提交"/>#}
30 {#    </form>#}
31 {##}
32 {#    <ul>#}
33 {#        {% for k,item in user_dict.items %}#}
34 {#            <li><a target="_blank" href="/detail-{{ k }}.html">{{ item.name }}</a></li>#}
35 {#        {% endfor %}#}
36 {#    </ul>#}
37 -->
38 
39 
40     <div style="height: 48px;background-color: black;color: white">
41         歡迎!!!!!
42     </div>
43     <div>
44         <div style="position: absolute;top: 48px;bottom: 0;left: 0;background-color: brown;width: 200px">
45             <a class="menu" href="/cmdb/user_info/">用戶管理</a>
46             <a class="menu" href="/cmdb/user_group">用戶組管理</a>
47 
48         </div>
49         <div style="position: absolute;top: 48px;left: 210px;bottom:0;right: 0;overflow: auto ">
50 
51         </div>
52     </div>
53 </body>
54 </html>
index.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6     <style>
 7         body{
 8             margin: 0;
 9         }
10         .menu{
11             display: block;
12             padding: 5px;
13         }
14     </style>
15 </head>
16 <body>
17 
18     <div style="height: 48px;background-color: black;color: white">
19         歡迎!!!!!
20     </div>
21     <div>
22         <div style="position: absolute;top: 48px;bottom: 0;left: 0;background-color: brown;width: 200px">
23             <a class="menu" href="/cmdb/user_info">用戶管理</a>
24             <a class="menu" href="/cmdb/user_group">用戶組管理</a>
25 
26         </div>
27         <div style="position: absolute;top: 48px;left: 210px;bottom:0;right: 0;overflow: auto ">
28             <h3>添加用戶</h3>
29             <form method="POST" action="/cmdb/user_info/">
30                 <input type="text" name="user"/>
31                 <input type="text" name="pwd"/>
32                 <input type="submit" value="添加"/>
33             </form>
34             <h3>用戶列表</h3>
35             <ul>
36                 {% for row in user_list %}
37                     <li>
38                         <a href="/cmdb/userdetail-{{ row.id }}/">{{ row.username }}</a> |
39                         <a href="/cmdb/userdel-{{ row.id }}/">刪除</a> |
40                         <a href="/cmdb/useredit-{{ row.id }}/">編輯</a> |
41                     </li>
42                 {% endfor %}
43             </ul>
44         </div>
45     </div>
46 </body>
47 </html>
user_info.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6     <style>
 7         body{
 8             margin: 0;
 9         }
10         .menu{
11             display: block;
12             padding: 5px;
13         }
14     </style>
15 </head>
16 <body>
17     <div style="height: 48px;background-color: black;color: white">
18         歡迎!!!!!
19     </div>
20     <div>
21         <div style="position: absolute;top: 48px;bottom: 0;left: 0;background-color: brown;width: 200px">
22             <a class="menu" href="/cmdb/user_info">用戶管理</a>
23             <a class="menu" href="/cmdb/user_group">用戶組管理</a>
24         </div>
25         <div style="position: absolute;top: 48px;left: 210px;bottom:0;right: 0;overflow: auto ">
26             <h1>用戶詳細信息</h1>
27             <h5>{{ obj.username }}</h5>
28             <h5>{{ obj.passwoed }}</h5>
29         </div>
30     </div>
31 </body>
32 </html>
user_detail.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6     <style>
 7         body{
 8             margin: 0;
 9         }
10         .menu{
11             display: block;
12             padding: 5px;
13         }
14     </style>
15 </head>
16 <body>
17     <div style="height: 48px;background-color: black;color: white">
18         歡迎!!!!!
19     </div>
20     <div>
21         <div style="position: absolute;top: 48px;bottom: 0;left: 0;background-color: brown;width: 200px">
22             <a class="menu" href="/cmdb/user_info/">用戶管理</a>
23             <a class="menu" href="/cmdb/user_group">用戶組管理</a>
24         </div>
25         <div style="position: absolute;top: 48px;left: 210px;bottom:0;right: 0;overflow: auto ">
26             <h1>編輯用戶</h1>
27             <form method="post" action="/cmdb/useredit-{{ obj.id }}/">
28                 <input style="display: none" type="text" name="id" value="{{ obj.id }}" />
29                 <input type="text" name="username" value="{{ obj.username }}"/>
30                 <input type="text" name="passwoed" value="{{ obj.passwoed }}"/>
31                 <input type="submit" value="提交">
32             </form>
33         </div>
34     </div>
35 </body>
36 </html>
user_edit.html

三、建立數據庫表

# app下的models.py

python manage.py makemigrations

python manage.py migrat 

字段:

字符串類型:數字、時間、二進制、自增(primary_key=True) 

 1 AutoField(Field)
 2     - int自增列,必須填入參數 primary_key=True
 3 BigAutoField(AutoField)
 4     - bigint自增列,必須填入參數 primary_key=True
 5     注:當model中若是沒有自增列,則自動會建立一個列名爲id的列
 6     from django.db import models
 7     class UserInfo(models.Model):
 8         # 自動建立一個列名爲id的且爲自增的整數列
 9         username = models.CharField(max_length=32)
10     class Group(models.Model):
11         # 自定義自增列
12         nid = models.AutoField(primary_key=True)
13         name = models.CharField(max_length=32)
14 SmallIntegerField(IntegerField):
15     - 小整數 -32768 ~ 32767
16 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
17     - 正小整數 0 ~ 32767
18 IntegerField(Field)
19     - 整數列(有符號的) -2147483648 ~ 2147483647
20 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
21     - 正整數 0 ~ 2147483647
22 BigIntegerField(IntegerField):
23     - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
24 BooleanField(Field)
25     - 布爾值類型
26 NullBooleanField(Field):
27     - 能夠爲空的布爾值
28 CharField(Field)
29     - 字符類型
30     - 必須提供max_length參數, max_length表示字符長度
31 TextField(Field)
32     - 文本類型
33 EmailField(CharField):
34     - 字符串類型,Django Admin以及ModelForm中提供驗證機制
35 GenericIPAddressField(Field)
36     - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
37     - 參數:
38         protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
39         unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both"
40 URLField(CharField)
41     - 字符串類型,Django Admin以及ModelForm中提供驗證 URL
42 SlugField(CharField)
43     - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)
44 CommaSeparatedIntegerField(CharField)
45     - 字符串類型,格式必須爲逗號分割的數字
46 UUIDField(Field)
47     - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
48 FilePathField(Field)
49     - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
50     - 參數:
51             path,                      文件夾路徑
52             match=None,                正則匹配
53             recursive=False,           遞歸下面的文件夾
54             allow_files=True,          容許文件
55             allow_folders=False,       容許文件夾
56 FileField(Field)
57     - 字符串,路徑保存在數據庫,文件上傳到指定目錄
58     - 參數:
59         upload_to = ""      上傳文件的保存路徑
60         storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
61 ImageField(FileField)
62     - 字符串,路徑保存在數據庫,文件上傳到指定目錄
63     - 參數:
64         upload_to = ""      上傳文件的保存路徑
65         storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
66         width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
67         height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)
68 DateTimeField(DateField)
69     - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
70 DateField(DateTimeCheckMixin, Field)
71     - 日期格式      YYYY-MM-DD
72 TimeField(DateTimeCheckMixin, Field)
73     - 時間格式      HH:MM[:ss[.uuuuuu]]
74 DurationField(Field)
75     - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型
76 FloatField(Field)
77     - 浮點型
78 DecimalField(Field)
79     - 10進制小數
80     - 參數:
81         max_digits,小數總長度
82         decimal_places,小數位長度
83 BinaryField(Field)
84     - 二進制類型
字段
 1 null                數據庫中字段是否能夠爲空
 2 db_column           數據庫中字段的列名
 3 default             數據庫中字段的默認值
 4 primary_key         數據庫中字段是否爲主鍵
 5 db_index            數據庫中字段是否能夠創建索引
 6 unique              數據庫中字段是否能夠創建惟一索引
 7 unique_for_date     數據庫中字段【日期】部分是否能夠創建惟一索引
 8 unique_for_month    數據庫中字段【月】部分是否能夠創建惟一索引
 9 unique_for_year     數據庫中字段【年】部分是否能夠創建惟一索引
10 verbose_name        Admin中顯示的字段名稱
11 blank               Admin中是否容許用戶輸入爲空
12 editable            Admin中是否能夠編輯
13 help_text           Admin中該字段的提示信息
14 choices             Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
15                     如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
16 error_messages      自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息;
17                     字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
18                     如:{'null': "不能爲空.", 'invalid': '格式錯誤'}
19 validators          自定義錯誤驗證(列表類型),從而定製想要的驗證規則
20                     from django.core.validators import RegexValidator
21                     from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
22                     MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
23                     如:
24                     test = models.CharField(
25                         max_length=32,
26                         error_messages={
27                             'c1': '優先錯信息1',
28                             'c2': '優先錯信息2',
29                             'c3': '優先錯信息3',
30                         },
31                         validators=[
32                             RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
33                             RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
34                             EmailValidator(message='又錯誤了', code='c3'), ]
35                     )
參數

四、一對多

建立外鍵(on_delete=models.CASCADE)

外鍵默認生成數據庫時存儲的爲:外間字段_id

建立數據時能夠根據外鍵的id直接建立:models.tb.object.create(name='root', user_group_id=1)

去對象中取某個單值:

userlist = models.tb.object.all()
  for row in userlist:
  row.id
  row.user_group_id
  row.user_group.caption

 1 from django.db import models
 2 
 3 # Create your models here.
 4 
 5 class Business(models.Model):
 6     caption = models.CharField(max_length=32)
 7     code = models.CharField(max_length=32,null=True,default='sa')
 8 
 9 class Host(models.Model):
10     nid = models.AutoField(primary_key=True)
11     hostname = models.CharField(max_length=32,db_index=True)
12     ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
13     port = models.IntegerField()
14     b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
15 
16 #
17 # 緣由:
18 # 在django2.0後,定義外鍵和一對一關係的時候須要加on_delete選項,此參數爲了不兩個表裏的數據不一致問題,否則會報錯:
19 # TypeError: __init__() missing 1 required positional argument: 'on_delete'
20 # 舉例說明:
21 # user=models.OneToOneField(User)
22 # owner=models.ForeignKey(UserProfile)
23 # 須要改爲:
24 # user=models.OneToOneField(User,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值
25 # owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值
26 # 參數說明:
27 # on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值
28 # CASCADE:此值設置,是級聯刪除。
29 # PROTECT:此值設置,是會報完整性錯誤。
30 # SET_NULL:此值設置,會把外鍵設置爲null,前提是容許爲null。
31 # SET_DEFAULT:此值設置,會把設置爲外鍵的默認值。
32 # SET():此值設置,會調用外面的值,能夠是一個函數。
33 # 通常狀況下使用CASCADE就能夠了
建立一對多表結構(models)

跨表操做

外鍵:

  v = models.Host.objects.filter(nid__gt=0)

  v[0].b.caption ----> 經過.進行跨表

一對多跨表操做的的三種方式 

def host(request):
    v1 = models.Host.objects.filter(nid__gt=0)
    #QuerySet [hostboj(ip,host,另一個對象(...)),]
    # for row in v1:
        # print(row.nid,row.hostname,row.ip,row.port,row.b_id,row.b)
        # print(row.b.fk.name)
    # return HttpResponse('host')

    v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
    #QuerySet [{}]
    print(v2)
    for row in v2:
        print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])

    v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')
    #QuerySet [()]
    print(v3)
    return render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3})
一對多跨表(views.py)
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <h1>業務線列表(對象)</h1>
 9     <table border="1">
10         <thead>
11             <tr>
12                 <th>主機名</th>
13                 <th>IP</th>
14                 <th>端口</th>
15                 <th>業務線名稱</th>
16             </tr>
17         </thead>
18         <tbody>
19             {% for row in v1 %}
20                 <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
21                     <td>{{ row.hostname }}</td>
22                     <td>{{ row.ip }}</td>
23                     <td>{{ row.port }}</td>
24                     <td>{{ row.b.caption }}</td>
25                 </tr>
26             {% endfor %}
27         </tbody>
28     </table>
29 
30     <h1>業務線列表(字典)</h1>
31     <table border="1">
32         <thead>
33             <tr>
34                 <th>主機名</th>
35                 <th>業務線名稱</th>
36             </tr>
37         </thead>
38         <tbody>
39             {% for row in v2 %}
40                 <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
41                     <td>{{ row.hostname }}</td>
42                     <td>{{ row.b__caption }}</td>
43                 </tr>
44             {% endfor %}
45         </tbody>
46     </table>
47 
48     <h1>業務線列表(元組)</h1>
49     <table border="1">
50         <thead>
51             <tr>
52                 <th>主機名</th>
53                 <th>業務線名稱</th>
54             </tr>
55         </thead>
56         <tbody>
57             {% for row in v3 %}
58                 <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
59                     <td>{{ row.1 }}</td>
60                     <td>{{ row.3 }}</td>
61                 </tr>
62             {% endfor %}
63         </tbody>
64     </table>
65 
66 </body>
67 </html>
host.html

五、獲取表單的三種方式 

v1 = models.Business.objects.all()
# QuerySet ,內部元素都是對象

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

# QuerySet ,內部元素都是元組
v3 = models.Business.objects.all().values_list('id','caption')

# 獲取到的一個對象,若是不存在就報錯
models.Business.objects.get(id=1)
對象或者None = models.Business.objects.filter(id=1).first()

def business(request):
    v1 = models.Business.objects.all()
    #QuerySet
    # [obj(id,caption,code),obj(id,caption,code),obj(id,caption,code)]
    v2 = models.Business.objects.all().values('id','caption')
    # select * from tb
    # select id,caption from ...
    #QuerySet
    # [{'id':1,'caption':'運維部'},{},{}]
    v3 = models.Business.objects.all().values_list('id','caption')
    #QuerySet
    # [(1,運維部),(2,開發),()]
    return render(request,'business.html',{'v1':v1,'v2':v2,'v3':v3})
三種方式(views.py)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>業務線列表(對象)</h1>
    <ul>
        {% for row in v1 %}
            <li>{{ row.id }} - {{ row.caption }} - {{ row.code }}</li>
        {% endfor %}
    </ul>
    <h1>業務線列表(字典)</h1>
    <ul>
        {% for row in v2 %}
            <li>{{ row.id }} - {{ row.caption }}</li>
        {% endfor %}
    </ul>
    <h1>業務線列表(元組)</h1>
    <ul>
        {% for row in v3 %}
            <li>{{ row.0 }} - {{ row.1 }}</li>
        {% endfor %}
    </ul>
</body>
</html>
business.html

六、多對多

建立

方式一:自定義關係表

 1 class Host(models.Model):
 2     nid = models.AutoField(primary_key=True)
 3     hostname = models.CharField(max_length=32,db_index=True)
 4     ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
 5     port = models.IntegerField()
 6     b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
 7 class Application(models.Model):
 8     name = models.CharField(max_length=32)
 9 class HostToApp(models.Model):
10     hobj = models.ForeignKey(to="Host",to_field='nid',on_delete=models.CASCADE)
11     aobj = models.ForeignKey(to="Application",to_field='id',on_delete=models.CASCADE)
方式一

方式二:自動建立關係表

1 class Host(models.Model):
2     nid = models.AutoField(primary_key=True)
3     hostname = models.CharField(max_length=32,db_index=True)
4     ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
5     port = models.IntegerField()
6     b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
7 class Application(models.Model):
8     name = models.CharField(max_length=32)
9     r = models.ManyToManyField('Host')
方式二

沒法直接對第三張表進行操做

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

obj.name

#間接對第三張表操做

#添加數據

obj.r.add(1)  -->在第三張表中插入1對應Application中的id=1

obj.r.add(1,2,3)   -->增長多個關係

obj.r.add(*[1,2,3,4])   -->增長多個關係

#刪除數據

obj.r.remove(1)

obj.r.remove(1,2,3) 

obj.r.remove(*[1,2,3,4])   -->刪除多個關係

obj.r.clear()  -->刪除全部Application中的id=1的全部對應關係

#修改數據

obj.r.set([3,4,5])  -->修改,執行完成此條語句數據庫中只會存在(1,3)(1,4)(1,5)的對應關係,其餘內容所有清除(至關於全刪除在添加)

#獲取數據

obj.r.all()

示例:

 1 from django.db import models
 2 
 3 # Create your models here.
 4 # class Foo(models.Model):
 5 #     name = models.CharField(max_length=32)
 6 
 7 class Business(models.Model):
 8     caption = models.CharField(max_length=32)
 9     code = models.CharField(max_length=32,null=True,default='sa')
10     # fk = models.ForeignKey('Foo')
11 
12 class Host(models.Model):
13     nid = models.AutoField(primary_key=True)
14     hostname = models.CharField(max_length=32,db_index=True)
15     ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
16     port = models.IntegerField()
17     b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
18 class Application(models.Model):
19     name = models.CharField(max_length=32)
20     r = models.ManyToManyField('Host')
21 
22 # class HostToApp(models.Model):
23 #     hobj = models.ForeignKey(to="Host",to_field='nid',on_delete=models.CASCADE)
24 #     aobj = models.ForeignKey(to="Application",to_field='id',on_delete=models.CASCADE)
25 #
models.py
 1 def app(request):
 2     if request.method == 'GET':
 3         app_list = models.Application.objects.all()
 4         # for row in app_list:
 5         #     print(row.name,row.r.all())
 6         host_list = models.Host.objects.all()
 7         return render(request,'app.html',{'app_list':app_list,'host_list':host_list})
 8     elif request.method == 'POST':
 9         app_name = request.POST.get('app_name')
10         host_list = request.POST.getlist('host_list')
11         print(app_name,host_list)
12         obj = models.Application.objects.create(name=app_name)
13         obj.r.add(*host_list)
14         return redirect('/app')
15 def ajax_add_app(request):
16     ret = {'status':True,'error':None,'data':None}
17     print(request.POST.get('app_name'))
18     print(request.POST.getlist('host_list'))
19     # app_name = request.POST.get('app_name')
20     # host_list = request.POST.getlist('host_list')
21     # obj = models.Application.objects.create(name=app_name)
22     # obj.r.add(*host_list)
23     return HttpResponse(json.dumps(ret))
views.py
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title></title>
  6     <style>
  7         .host-tag{
  8            display: inline-block;
  9             padding: 3px;
 10             border: 1px solid red;
 11             background: pink;
 12 
 13         }
 14         .hide{
 15             display: none;
 16         }
 17         .shade{
 18             position: fixed;
 19             top: 0;
 20             right: 0;
 21             left: 0;
 22             bottom: 0;
 23             background-color: black;
 24             opacity: 0.6;
 25             z-index: 100;
 26         }
 27         .add-mode, .edit-mode{
 28             position: fixed;
 29             height: 300px;
 30             width: 400px;
 31             top: 100px;
 32             left: 50%;
 33             z-index: 101;
 34             border: 1px solid red;
 35             background-color: white;
 36             margin-left: -200px;
 37         }
 38     </style>
 39 </head>
 40 <body>
 41     <h1>應用列表</h1>
 42     <div>
 43         <input id="add_app" type="button" value="添加"/>
 44     </div>
 45     <table border="1">
 46         <thead>
 47             <tr>
 48                 <td>應用名稱</td>
 49                 <td>應用主機列表</td>
 50             </tr>
 51         </thead>
 52         <tbody>
 53             {% for app in app_list %}
 54                 <tr>
 55                     <td>{{ app.name }}</td>
 56                     <td>
 57                         {% for host in app.r.all %}
 58                             <span class="host-tag">{{ host.hostname }}</span>
 59                         {% endfor %}
 60                     </td>
 61                 </tr>
 62             {% endfor %}
 63         </tbody>
 64     </table>
 65 
 66     <div class="shade hide"></div>
 67 
 68     <div class="add-mode hide">
 69         <form method="POST" action="/app" id="add_form">
 70             <div class="group">
 71                 <input id="app_name" type="text" placeholder="應用名稱" name="app_name"/>
 72             </div>
 73             <div class="group">
 74                 <select id="host_list" name="host_list" multiple>
 75                     {% for op in host_list  %}
 76                         <option value="{{ op.nid }}">{{ op.hostname }}</option>
 77                     {% endfor %}
 78 
 79                 </select>
 80             </div>
 81             <input type="submit" value="提交"/>
 82             <input id="add_submit_ajax" type="button" value="Ajax提交"/>
 83         </form>
 84     </div>
 85     <div class="edit-mode hide">
 86         <form id="edit_form" method="POST" action="/host">
 87             <input type="text" name="nid" style="display: none"/>
 88             <input type="text" placeholder="主機名" name="hostname"/>
 89             <input type="text" placeholder="IP" name="ip"/>
 90             <input type="text" placeholder="端口" name="port"/>
 91             <select name="b_id">
 92                 {% for op in b_list  %}
 93                     <option value="{{ op.id }}">{{ op.caption }}</option>
 94                 {% endfor %}
 95             </select>
 96             <a id="ajax_submit_edit" style="display: inline-block;padding: 5px;background-color: blue;color: white">確認編輯</a>
 97         </form>
 98     </div>
 99     <script src="/static/jquery-1.12.4.js"></script>
100     <script>
101         $(function(){
102             $('#add_app').click(function(){
103                 $('.shade,.add-mode').removeClass('hide')
104             });
105             $('#cancle').click(function(){
106                 $('.shade,.add-mode').addClass('hide')
107             });
108             $('#add_submit_ajax').click(function(){
109                 $.ajax({
110                     url:'/ajax_add_app',
111 {#                    data:{'user':123,'host_list':[1,2,3,4]},#}
112                     data:$('#add_form').serialize(),
113                     type:'POST',
114                     dataType:'JSON',
115                     traditional:true,  {# 給後臺發送列表需添加此參數 #}
116                     success:function(obj){
117                         console.log(obj)
118                     },
119                     error:function(){
120                     }
121                 })
122             })
123         })
124     </script>
125 </body>
126 </html>
app.html

7、ajax

一、概述

對於WEB應用程序:用戶瀏覽器發送請求,服務器接收並處理請求,而後返回結果,每每返回就是字符串(HTML),瀏覽器將字符串(HTML)渲染並顯示瀏覽器上

傳統操做:一個簡單操做須要從新加載全局數據

ajax:Asynchronous JavaScript and XML (異步的JavaScript和XML),一種建立交互式網頁應用的網頁開發技術方案。

異步的JavaScript:使用 【JavaScript語言】 以及 相關【瀏覽器提供類庫】 的功能向服務端發送請求,當服務端處理完請求以後,【自動執行某個JavaScript的回調函數】,

請求和響應的整個過程是【偷偷】進行的,頁面上無任何感知。

利用AJAX能夠作:

一、註冊時,輸入用戶名自動檢測用戶是否已經存在。
二、登錄時,提示用戶名密碼錯誤
三、刪除數據行時,將行ID發送到後臺,後臺在數據庫中刪除,數據庫刪除成功後,在頁面DOM中將數據行也刪除。

二、原生ajax

Ajax主要就是使用 【XmlHttpRequest】對象來完成請求的操做,該對象在主流瀏覽器中均存在(除早起的IE),Ajax首次出現IE5.5中存在(ActiveX控件)

XmlHttpRequest對象的主要方法:

 1 a. void open(String method,String url,Boolen async)
 2    用於建立請求    
 3    參數:
 4        method: 請求方式(字符串類型),如:POST、GET、DELETE...
 5        url:    要請求的地址(字符串類型)
 6        async:  是否異步(布爾類型) 
 7 b. void send(String body)
 8     用於發送請求 
 9     參數:
10         body: 要發送的數據(字符串類型) 
11 c. void setRequestHeader(String header,String value)
12     用於設置請求頭 
13     參數:
14         header: 請求頭的key(字符串類型)
15         vlaue:  請求頭的value(字符串類型) 
16 d. String getAllResponseHeaders()
17     獲取全部響應頭 
18     返回值:
19         響應頭數據(字符串類型) 
20 e. String getResponseHeader(String header)
21     獲取響應頭中指定header的值 
22     參數:
23         header: 響應頭的key(字符串類型) 
24     返回值:
25         響應頭中指定的header對應的值 
26 f. void abort() 
27     終止請求
XmlHttpRequest對象的主要方法

XmlHttpRequest對象的主要屬性:

 1 a. Number readyState
 2    狀態值(整數) 
 3    詳細:
 4       0-未初始化,還沒有調用open()方法;
 5       1-啓動,調用了open()方法,未調用send()方法;
 6       2-發送,已經調用了send()方法,未接收到響應;
 7       3-接收,已經接收到部分響應數據;
 8       4-完成,已經接收到所有響應數據; 
 9 b. Function onreadystatechange
10    當readyState的值改變時自動觸發執行其對應的函數(回調函數) 
11 c. String responseText
12    服務器返回的數據(字符串類型) 
13 d. XmlDocument responseXML
14    服務器返回的數據(Xml對象) 
15 e. Number states
16    狀態碼(整數),如:200、404... 
17 f. String statesText
18    狀態文本(字符串),如:OK、NotFound...
XmlHttpRequest對象的主要屬性

示例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <input type="text"/>
 9     <input type="button" value="Ajax" onclick="Ajax1()"/>
10 
11     <script type="text/javascript" src="/static/jquery-1.12.4.js"></script>
12     <script>
13         function getXHR(){
14             var xhr = null;
15             if(XMLHttpRequest){
16                 xhr = new XMLHttpRequest();
17             }else{
18                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
19             }
20             return xhr;
21         }
22         function Ajax1() {
23             {# 打開#}
24             var xhr = new XMLHttpRequest();
25 {#            xhr.open("GET",'/ajax_json/',true);#}
26             xhr.open('POST','/ajax_json/',true);
27             xhr.onreadystatechange =function () {
28             {# onreadystatechange是readyState的回調函數,判斷值爲多少的時候執行什麼動做#}
29                 if(xhr.readyState == 4){
30                     //表示接收完畢,如下打印返回值
31                     var obj = JSON.parse(xhr.responseText);
32                     console.log(obj);
33                 }
34             };
35             {# 發請求時候額外帶個頭寫法,CSRF可以使用#}
36             xhr.setRequestHeader('k1','v1');
37             //django的post源碼裏已指定固定格式,不然後端沒法收到數據
38             xhr.setRequestHeader('content-type','application/x-www-form-urlencoded; charset-UTF-8');
39             {# 發送,send發送格式固定#}
40             xhr.send('name=root;pwd=123');
41         }
42     </script>
43 </body>
44 </html>
ajax.html
1 def ajax(request):
2     return render(request,'ajax.html')
3 def ajax_json(request):
4     print(request.POST)
5     ret = {'status':True,'data':request.POST.get('username')}
6     import json
7     return HttpResponse(json.dumps(ret))
views.py
1     url(r'^ajax/$',views.ajax),
2     url(r'^ajax_json/$',views.ajax_json),
urls.py

跨瀏覽器支持:

XmlHttpRequest:IE7+, Firefox, Chrome, Opera, etc.

ActiveXObject("Microsoft.XMLHTTP"):IE6, IE5

1         function GetXHR(){
2             var xhr = null;
3             if(XMLHttpRequest){
4                 xhr = new XMLHttpRequest();
5             }else{
6                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
7             }
8             return xhr;
9         }
跨瀏覽器支持

三、jQuery Ajax

jQuery其實就是一個JavaScript的類庫,其將複雜的功能作了上層封裝,使得開發者能夠在其基礎上寫更少的代碼實現更多的功能。

jQuery Ajax本質 XMLHttpRequest 或 ActiveXObject 

對於傳統的form,能夠經過表單的方式將token再次發送到服務端,而對於ajax的話,使用以下方式。

$.ajax({  # 提交到後臺

  url: '/host', # 提交到哪裏

  type: "POST", # 提交方式

  # 第一種寫法
  data: {'k1': 123,'k2': "root"}, # 提交數據

  # 第二種寫法

  data:$('#add_form').serialize(), #代替上一句,將form表單裏全部數據統一打包發到後臺

  # 注意若是data字典中還包含1個字典,這個包含的字典須要轉爲字符串才能夠發送:JSON.stringfy({'k1','v1'})

  dataType:'JSON', # 這裏是jquery功能,將傳回來的數據進行json解析,就不須要下面的函數再次進行解析了,下面函數中的參數就爲obj對象

  traditional:true, # 能夠將data中的列表數據傳到後臺,python使用get_list來接收列表數據。

  success: function(data){ # 回調函數,等待接收上面提交後的返回數據

  // data是服務器端返回的字符串
  var obj = JSON.parse(data);
  }

  error:function(){ #當前臺發送了一個請求到後臺,後臺未捕捉到發了個未知的錯誤,才觸發這裏執行
})

 1 jQuery.get(...)
 2     全部參數:
 3         url: 待載入頁面的URL地址
 4         data: 待發送 Key/value 參數。
 5         success: 載入成功時回調函數。
 6         dataType: 返回內容格式,xml, json,  script, text, html
 7 jQuery.post(...)
 8     全部參數:
 9         url: 待載入頁面的URL地址
10         data: 待發送 Key/value 參數
11         success: 載入成功時回調函數
12         dataType: 返回內容格式,xml, json,  script, text, html
13 jQuery.getJSON(...)
14     全部參數:
15         url: 待載入頁面的URL地址
16         data: 待發送 Key/value 參數。
17         success: 載入成功時回調函數。
18 jQuery.getScript(...)
19     全部參數:
20         url: 待載入頁面的URL地址
21         data: 待發送 Key/value 參數。
22         success: 載入成功時回調函數。
23 jQuery.ajax(...)
24     部分參數:
25         url:請求地址
26         type:請求方式,GET、POST(1.9.0以後用method)
27         headers:請求頭
28         data:要發送的數據
29         contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8")
30         async:是否異步
31         timeout:設置請求超時時間(毫秒)
32         beforeSend:發送請求前執行的函數(全局)
33         complete:完成以後執行的回調函數(全局)
34         success:成功以後執行的回調函數(全局)
35         error:失敗以後執行的回調函數(全局)
36         accepts:經過請求頭髮送給服務器,告訴服務器當前客戶端課接受的數據類型
37         dataType:將服務器端返回的數據轉換成指定類型
38             "xml": 將服務器端返回的內容轉換成xml格式
39             "text": 將服務器端返回的內容轉換成普通文本格式
40             "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM中時,若是包含JavaScript標籤,則會嘗試去執行。
41             "script": 嘗試將返回值看成JavaScript去執行,而後再將服務器端返回的內容轉換成普通文本格式
42             "json": 將服務器端返回的內容轉換成相應的JavaScript對象
43             "jsonp": JSONP 格式
44             使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 爲正確的函數名,以執行回調函數
45             若是不指定,jQuery 將自動根據HTTP包MIME信息返回相應類型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string
46         converters: 轉換器,將服務器端的內容根據指定的dataType轉換類型,並傳值給success回調函數
jQuery Ajax 方法列表

這些方法所有是調用上面的Ajax方法,不一樣的是隻修改對應的type方法,因此說只用Ajax方法便可

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

返回方式:return HttpResponse(json.dumps(字典))

不要使用render,由於返回的模板文件只作渲染,沒法json轉換,不支持redirect方法。 

示例:

 1 def test_ajax(request):
 2     import json
 3     ret = {'status':True,'error':None,'data':None}
 4     try:
 5         print(request.method,request.POST,sep='\t')
 6         h = request.POST.get('hostname')
 7         i = request.POST.get('ip')
 8         p = request.POST.get('port')
 9         b = request.POST.get('b_id')
10         if h and len(h) > 5:
11             models.Host.objects.create(hostname=h,
12                                        ip=i,
13                                        port=p,
14                                        b_id=b)
15         else:
16             ret['status'] = False
17             ret['error'] = '長度小於5'
18     except Exception as e:
19         ret['status'] = False
20         ret['error'] = '請求錯誤'
21     print(ret)
22     return HttpResponse(json.dumps(ret))
View.py(ajax)
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title></title>
  6     <style>
  7         .hide{
  8             display: none;
  9         }
 10         .shade{
 11             position: fixed;
 12             top: 0;
 13             right: 0;
 14             left: 0;
 15             bottom: 0;
 16             background-color: black;
 17             opacity: 0.6;
 18             z-index: 100;
 19         }
 20         .add-mode, .edit-mode{
 21             position: fixed;
 22             height: 300px;
 23             width: 400px;
 24             top: 100px;
 25             left: 50%;
 26             z-index: 101;
 27             border: 1px solid red;
 28             background-color: white;
 29             margin-left: -200px;
 30         }
 31     </style>
 32 </head>
 33 <body>
 34     <h1>主機列表(對象)</h1>
 35     <div>
 36         <input id="add_host" type="button" value="添加"/>
 37     </div>
 38     <table border="1">
 39         <thead>
 40             <tr>
 41                 <th>序號</th>
 42                 <th>主機名</th>
 43                 <th>IP</th>
 44                 <th>端口</th>
 45                 <th>業務線名稱</th>
 46                 <th>操做</th>
 47             </tr>
 48         </thead>
 49         <tbody>
 50             {% for row in v1 %}
 51                 <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
 52                     <td>{{ forloop.counter }}</td>
 53                     <td>{{ row.hostname }}</td>
 54                     <td>{{ row.ip }}</td>
 55                     <td>{{ row.port }}</td>
 56                     <td>{{ row.b.caption }}</td>
 57                     <td>
 58                         <a class="edit">編輯</a> | <a class="del">刪除</a>
 59                     </td>
 60                 </tr>
 61             {% endfor %}
 62         </tbody>
 63     </table>
 64 
 65     <h1>主機列表(字典)</h1>
 66     <table border="1">
 67         <thead>
 68             <tr>
 69                 <th>主機名</th>
 70                 <th>業務線名稱</th>
 71             </tr>
 72         </thead>
 73         <tbody>
 74             {% for row in v2 %}
 75                 <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
 76                     <td>{{ row.hostname }}</td>
 77                     <td>{{ row.b__caption }}</td>
 78                 </tr>
 79             {% endfor %}
 80         </tbody>
 81     </table>
 82 
 83     <h1>主機列表(元組)</h1>
 84     <table border="1">
 85         <thead>
 86             <tr>
 87                 <th>主機名</th>
 88                 <th>業務線名稱</th>
 89             </tr>
 90         </thead>
 91         <tbody>
 92             {% for row in v3 %}
 93                 <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
 94                     <td>{{ row.1 }}</td>
 95                     <td>{{ row.3 }}</td>
 96                 </tr>
 97             {% endfor %}
 98         </tbody>
 99     </table>
100 
101     <div class="shade hide"></div>
102 
103     <div class="add-mode hide">
104         <form method="POST" action="/host">
105             <div class="group">
106                 <input id="host" type="text" placeholder="主機名" name="hostname"/>
107             </div>
108             <div class="group">
109                 <input id="ip" type="text" placeholder="IP" name="ip"/>
110             </div>
111             <div class="group">
112                 <input id="port" type="text" placeholder="端口" name="port"/>
113             </div>
114             <div class="group">
115                 <select id="sel" name="b_id">
116                     {% for op in b_list  %}
117                         <option value="{{ op.id }}">{{ op.caption }}</option>
118                     {% endfor %}
119 
120                 </select>
121             </div>
122             <input type="submit" value="提交"/>
123             <a id="ajax_submit" style="display: inline-block;padding: 5px;background-color: blue;color: white">悄悄提交</a>
124             <input id="cancle" type="button" value="取消"/>
125             <span id="error_msg" style="color: red"></span>
126         </form>
127 
128     </div>
129 
130     <script src="/static/jquery-1.12.4.js"></script>
131     <script>
132         $(function(){
133             $('#add_host').click(function(){
134                 $('.shade,.add-mode').removeClass('hide')
135             });
136             $('#cancle').click(function(){
137                 $('.shade,.add-mode').addClass('hide')
138             });
139             $('#ajax_submit').click(function(){
140                 $.ajax({
141                     url:'/test_ajax',
142                     type:'POST',
143                     data:{'hostname':$('#host').val(),'ip':$('#ip').val(),'port':$('#port').val(),'b_id':$('#sel').val(),},
144                     success:function(data){
145                         var obj = JSON.parse(data);
146                         if(obj.status){
147                             location.reload()
148                         }else{
149                             $('#error_msg').text(obj.error);
150                         }
151                     }
152                 })
153             });
154         })
155     </script>
156 
157 </body>
158 </html>
host.html(ajax)

 四、「僞」AJAX

因爲HTML標籤的iframe標籤具備局部加載內容的特性,因此可使用其來僞造Ajax請求 

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <!--
 9     <input type="text" id="url" />
10     <input type="button" value="發送Iframe請求" onclick="iframeRequest();" />
11     <iframe id="ifm" src="http://www.baidu.com"></iframe>
12     -->
13     <form action="/ajax_json/" method="POST" target="ifm1"> #target=ifm使form和iframe創建管理
14         <iframe id="ifm1" name="ifm1" ></iframe>   #經過iframe綁定form後進行在頁面不刷新的狀況下提交
15         <input type="text" name="username" />
16         <input type="text" name="email" />
17         <input type="submit" onclick="sumitForm();" value="Form提交"/>
18     </form>
19     <script type="text/javascript" src="/static/jquery-1.12.4.js"></script>
20     <script>
21         /*
22         function iframeRequest(){
23             var url = $('#url').val();
24             $('#ifm').attr('src',url);
25         }
26         */
27         function sumitForm(){
28             $('#ifm1').load(function(){
29                 var text = $('#ifm1').contents().find('body').text();
30                 var obj = JSON.parse(text);
31                 console.log(obj)
32             })
33         }
34     </script>
35 </body>
36 </html>
僞ajax

使用順序:若是發送的是普通數據,使用順序優先級:jquery,XMLHttpRequest,iframe

8、文件上傳

一、文件上傳的三種方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .upload{
            display: inline-block;
            padding: 10px;
            background-color: brown;
            position:absolute;
            top: 0;
            bottom: 0;
            right: 0;
            left:0;
            z-index: 90;
        }
        .file{
            width: 100px;
            height: 50px;
            opacity: 0;
            position:absolute;
            top: 0;
            bottom: 0;
            right: 0;
            left:0;
            z-index: 100;
        }
    </style>
</head>
<body>
    <div style="position:relative;width: 100px;height: 50px">
        <input class="file" type="file" id="fafafa" name="afafaf"/>
        <a class="upload">上傳</a>
    </div>
    <input type="button" value="提交XHR" onclick="xhrSubmit()"/>
    <input type="button" value="提交jQuery" onclick="jqSubmit()"/>
    <hr />
    <form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1">
        <iframe id="ifm1" name="ifm1" style="display: none" ></iframe>
        <input type="file" name="fafafa" onchange="changeUpload()"/>
        <input type="submit" onclick="iframeForm();" value="Form提交"/>
    </form>
    <div id="preview"></div>
    <script type="text/javascript" src="/static/jquery-1.12.4.js"></script>
    <script>
        function changeUpload() {
    {#        輸入框改變自動執行,提交操做#}
            $('#form1').submit();
            iframeForm()
        }
        function jqSubmit(){
{#            $('fafafa')[0]#}
            var file_obj = document.getElementById('fafafa').files[0];
            var fd = new FormData();
            fd.append('username','root');
            fd.append('fafafa',file_obj);
            $.ajax({
                url:'/upload_file/',
                type:'POST',
                data:fd,
                processData:false,
                contentType:false,
                success:function(arg,a1,a2) {
                    console.log(arg);
                    console.log(a1);
                    console.log(a2);
                }
            })

        }

        function xhrSubmit(){
{#            $('fafafa')[0]#}
            var file_obj = document.getElementById('fafafa').files[0];
            var fd = new FormData();
            fd.append('username','root');
            fd.append('fafafa',file_obj);
            var xhr = new XMLHttpRequest();
            xhr.open('POST','/upload_file/',true);
            xhr.onreadystatechange = function () {
                if(xhr.readyState == 4){
                    var obj = JSON.parse(xhr.responseText);
                    console.log(obj)
                }
            };
            xhr.send(fd)
        }

        function iframeForm(){
            $('#ifm1').load(function(){
                var text = $('#ifm1').contents().find('body').text();
                var obj = JSON.parse(text);
                {# 預覽圖片#}
                $('#preview').empty();
                var imgTag = document.createElement('img');
                imgTag.src = '/' + obj.data;
                $('#preview').append(imgTag)
            })
        }
    </script>
</body>
</html>
upload.html

二、後端

 1 def upload(request):
 2     return render(request,'upload.html')
 3 def upload_file(request):
 4     username = request.POST.get('username')
 5     fafafa = request.FILES.get('fafafa')
 6     import os
 7     img_path = os.path.join('static/imgs',fafafa.name)
 8     with open(img_path,'wb') as f:
 9         for item in fafafa.chunks():
10             f.write(item)
11     ret = {'code':True,'data':img_path}
12     import json
13     return HttpResponse(json.dumps(ret))
views.py

使用順序:若是發送的是文件,使用順序優先級:iframe,jquery(FormData),XMLHttpRequest(FormData)

9、Model操做

一、建立數據庫表

 1 class UserInfo(models.Model):
 2     nid = models.AutoField(primary_key=True)
 3     username = models.CharField(max_length=32)
 4     class Meta:
 5         # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
 6         db_table = "table_name"
 7         # 聯合索引
 8         index_together = [
 9             ("pub_date", "deadline"),
10         ]
11         # 聯合惟一索引
12         unique_together = (("driver", "restaurant"),)
13         # admin中顯示的表名稱
14         verbose_name
15         # verbose_name加s
16         verbose_name_plural
元信息
 1 # app01_user 生成的表名爲 tb1
 2 class User(models.Model):
 3     name = models.CharField(max_length=32,db_index=True) # 單列建立索引
 4     email = models.CharField(max_length=32)
 5 
 6     class Meta: # 生成的表名:tb1
 7         #數據庫中生成的表名稱,默認app名稱+下劃線+類名
 8         db_table='tb1' #(重要)
 9 
10         index_together={ ('name','email')} # 聯合索引,如用戶名+密碼驗證(重要)
11          # 聯合索引根據最左前綴的模式,name最左
12          # select * from where name = 'xx' 命中索引速度快
13          # select * from where name = 'xx' and email='xx' 命中索引速度快
14          # select * from where email='xx' 沒法命中索引速度慢
15         unique_together=(('name','email'),) # 聯合惟一索引,組合惟一(重要)
16         verbose_name = '上課記錄'
17         verbose_name_plural = '上課記錄' # admin裏生成的表名
單表

 一對多/一對一/多對多,其中一對一和多對多都是基於一對多衍生出來的。

一對多,重要參數:on_delete,related_name,

class UserType(models.Model):
    name = models.CharField(max_length=32)
class User(models.Model):
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    models.ForeignKey(to='UserTyep',to_field='id',on_delete=models.CASCADE) #on_delete有多個選項,這裏這個選項表示刪除一個類型,將會刪除此類型對應的全部用戶

# 在django2.0後,定義外鍵和一對一關係的時候須要加on_delete選項,此參數爲了不兩個表裏的數據不一致問題,否則會報錯:
# TypeError: __init__() missing 1 required positional argument: 'on_delete'
# 舉例說明:
# user=models.OneToOneField(User)
# owner=models.ForeignKey(UserProfile)
# 須要改爲:
# user=models.OneToOneField(User,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值
# owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE) --在老版本這個參數(models.CASCADE)是默認值
# 參數說明:
# on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值
# CASCADE:此值設置,是級聯刪除。
# PROTECT:此值設置,是會報完整性錯誤。
# SET_NULL:此值設置,會把外鍵設置爲null,前提是容許爲null。
# SET_DEFAULT:此值設置,會把設置爲外鍵的默認值。
# SET():此值設置,會調用外面的值,能夠是一個函數。
# 通常狀況下使用CASCADE就能夠了
on_delete

多表關係參數:

  1 ForeignKey(ForeignObject) # ForeignObject(RelatedField)
  2         to = '表名'        # 要進行關聯的表名
  3         to_field=None,     # 要關聯的表中的字段名稱
  4         on_delete=None,    # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
  5         '''
  6             - CASCADE,刪除關聯數據,與之關聯也刪除
  7             - DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError,是數據庫操做後庫級別拋出的
  8             - PROTECT,刪除關聯數據,引起錯誤ProtectedError,是受保護的,由django級別拋出的
  9             - SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)
 10             - SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
 11             - SET,刪除關聯數據,
 12                 a. 與之關聯的值設置爲指定值,設置:models.SET(值)
 13                 b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)
 14                     def func():
 15                         return 10
 16                     class MyModel(models.Model):
 17                         user = models.ForeignKey(
 18                             to="User",
 19                             to_field="id"
 20                             on_delete=models.SET(func),)
 21         '''
 22         related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
 23         related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】    如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
 24         limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
 25             '''
 26             # 如:            
 27                 - limit_choices_to={'nid__gt': 5}
 28                 - limit_choices_to=lambda : {'nid__gt': 5}
 29             from django.db.models import Q
 30                 - limit_choices_to=Q(nid__gt=10)
 31                 - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
 32                 - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
 33             '''
 34         db_constraint=True          # 是否在數據庫中建立外鍵約束
 35         parent_link=False           # 在Admin中是否顯示關聯數據
 36 
 37 
 38 OneToOneField(ForeignKey)
 39     to = '表名'                 # 要進行關聯的表名
 40     to_field=None               # 要關聯的表中的字段名稱
 41     on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
 42     ###### 對於一對一 ######    
 43     # 1. 一對一其實就是 一對多 + 惟一索引
 44     # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段
 45     # 以下會在A表中額外增長一個c_ptr_id列且惟一:
 46     class C(models.Model):
 47         nid = models.AutoField(primary_key=True)
 48         part = models.CharField(max_length=12)
 49     class A(C):
 50         id = models.AutoField(primary_key=True)
 51         code = models.CharField(max_length=1)
 52 
 53 ManyToManyField(RelatedField)
 54     to = '表名'                 # 要進行關聯的表名
 55     related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
 56     related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
 57     limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
 58     # 如:
 59     '''
 60         - limit_choices_to={'nid__gt': 5}
 61         - limit_choices_to=lambda : {'nid__gt': 5}
 62 
 63     from django.db.models import Q
 64         - limit_choices_to=Q(nid__gt=10)
 65         - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
 66         - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
 67     '''
 68     symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段
 69     # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段
 70         models.BB.objects.filter(...)
 71         # 可選字段有:code, id, m1
 72         class BB(models.Model):
 73             code = models.CharField(max_length=12)
 74             m1 = models.ManyToManyField('self',symmetrical=True)
 75         # 可選字段有: bb, code, id, m1
 76         class BB(models.Model):
 77             code = models.CharField(max_length=12)
 78             m1 = models.ManyToManyField('self',symmetrical=False)
 79     through=None,               # 自定義第三張表時,使用字段用於指定關係表
 80     through_fields=None,        # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
 81         from django.db import models
 82         class Person(models.Model):
 83             name = models.CharField(max_length=50)
 84         class Group(models.Model):
 85             name = models.CharField(max_length=128)
 86             members = models.ManyToManyField(
 87                 Person,
 88                 through='Membership',
 89                 through_fields=('group', 'person'),
 90             )
 91         class Membership(models.Model):
 92             group = models.ForeignKey(Group, on_delete=models.CASCADE)
 93             person = models.ForeignKey(Person, on_delete=models.CASCADE)
 94             inviter = models.ForeignKey(
 95                 Person,
 96                 on_delete=models.CASCADE,
 97                 related_name="membership_invites",
 98             )
 99             invite_reason = models.CharField(max_length=64)
100     db_constraint=True,         # 是否在數據庫中建立外鍵約束
101     db_table=None,              # 默認建立第三張表時,數據庫中表的名稱
多對多關係參數

二、示例:經過外鍵實現兩個表的反向操做

1 class UserType(models.Model):
2     name = models.CharField(max_length=32)
3 class User(models.Model):
4     name = models.CharField(max_length=32)
5     pwd = models.CharField(max_length=32)
6     ut = models.ForiegnKey(to='UserTyep', to_field='id')
models.py
 1 def index(request):
 2     # 正向操做
 3     v = models.User.objects.all()
 4     for item in v:
 5         print(v.user)
 6         print(v.pwd)
 7         print(v.ut.name) # 這個實現跨表操做
 8     # 跨表提取指定的字段: ut__name爲UserType的name字段
 9     h = models.User.objects.all().values('user','ut__name')
10     # 反向操做
11     v = models.UserType.objects.all()
12     for item in v:
13         print(item.name)
14         print(item.user_set.all()) # 提取當前類型對應的全部用戶
15     # 跨表提取指定的字段: ut__name爲UserType的name字段
16     h = models.UserType.objects.all().values('name','user__pwd')
17     return HttpResponse('index')
views.py
 1 # 使用參數:related_name='b' ,反向查詢寫法:item.b.all()
 2 # 使用參數:related_query_name='a' 反向查詢寫法:item.a_set.all()
 3 # 一對一,繼承外鍵,而且加入了惟一約束
 4 OneToOneField(ForeignKey)
 5     to = '表名'                 # 要進行關聯的表名
 6     to_field=None               # 要關聯的表中的字段名稱
 7     on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
 8 # 多對多,關注參數:through,through_fields=None(當使用第3種方法時使用)
 9     1:django建立第三張表,增刪改查方法以下:
10         m2m.add/remove/set/clear/filter
11     2:本身建立第三章表(沒有m2m字段),要本身實現第三章表的鏈表查詢
12     實例:
13     class Blog(models.Model):
14         site = models.CharField(max_length=32)
15     class Tag(models.Model):
16         name = models.CharField(max_length=32)
17     class B2T(models.Model):
18         b = models.ForeignKey('Blog')
19         t = models.ForeignKey('Tag')
20     3:自定義第三張表,(有m2m字段)
21         # 經過m2m字段查操做
22         # 經過m2m字段 clear
23     實例:經過through指定第三張表,經過through_field指定第三張表的關聯字段,會建立3張表,第三張表的操做須要本身手工對B2T表操做
24     class Blog(models.Model):
25         site = models.CharField(max_length=32)
26         m = models.ManyToManyField('Tag',through='B2T',through_field=['b','t1'] # 只能實現查詢對Tag表
27     class Tag(models.Model):
28         name = models.CharField(max_length=32)
29     class B2T(models.Model):
30         b = models.ForeignKey('Blog')
31         t1 = models.ForeignKey('Tag')
32         t2 = models.ForeignKey('Tag')
查詢操做

三、QuerySet包含功能

##################################################################
# 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)  #這裏的filter至關於having
    # 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) # distinct去重
    # 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),這個2個涉及到性能

 1 select_related(self, *fields)
 2     select_related()幫組作跨表查詢,若是作了跨表select_related()後面的參數只能加鏈表的字段(foreign key;many to many;one to one)        
 3     性能相關:表之間進行join連表操做,一次性獲取關聯的數據。
 4     當model的此次操做的時候直接會把跨表的數據一次性全拿過來,而後在繼續進行操做時就再也不發起額外的sql查詢了,一次性獲取關聯數據    
 5     model.tb.objects.all().select_related()
 6     model.tb.objects.all().select_related('外鍵字段')
 7     model.tb.objects.all().select_related('外鍵字段__外鍵字段')     
 8     不是全部的地方都適合用其來提升性能,表比較多的話性能反而下降      
 9 prefetch_related(self, *lookups)
10     適用於的屢次查詢,在第一次操做的時候執行不少次查詢select_related()鏈表作了一次查詢;而prefetch_related()鏈一個表會執行兩次操做
11     先去把A的單表全部數據所有拿到,不涉及跨表,在其內部會隱含在執行一次查詢,去B表裏帶着條件去查詢,條件爲B表id in 
12     A與B爲foreign key 關係,把A表中獲取的所有foreign key id去B表中查詢
13     兩次操做完成後全部數據都會放在內存當中,Django會幫助把全部數據聯合,在循環全部數據時,就自動去內存中提取,而不會再作連表查詢
14     性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢  在內存中作關聯,而不會再作連表查詢
15     # 第一次 獲取全部用戶表
16     # 第二次 獲取用戶類型表where id in (用戶表中的查到的全部用戶ID)
17     models.UserInfo.objects.prefetch_related('外鍵字段')
說明
 1 實例:sql效率不高的寫法
 2 def index(request):
 3     # 加入用戶表有10條數據
 4     users = models.User.objects.all()  # 這裏執行一次sql請求
 5     for row in users:
 6         print(row.user,row.pwd,row_ut_id)
 7         print(row.ut.name)  # 這裏外鍵會再次發起一次sql請求
 8         print(row.ut1.name)  # 這裏外鍵會再次發起一次sql請求
 9 實例:相對以上,優化寫法,可是缺點是這裏取到的是字典,不是對象
10 def index(request):
11     # 加入用戶表有10條數據
12     users = models.User.objects.all().values('user','pwd','ut__name')
13     for row in users:
14         pass
15 實例select_related:相對第一個,只須要加1個參數select_related(),便可將關聯的表一次性拿到,能夠在括號內加入關聯的字段,注意只能加關聯的字段,知足優化
16 def index(request):
17     # 加入用戶表有10條數據
18     users = models.User.objects.all().select_related('ut')
19     for row in users:
20         print(row.user,row.pwd,row_ut_id)
21         print(row.ut.name)
22         print(row.ut1.name)
23 實例prefetch_related:會進行2次sql請求,第二次會根據第一次的結果在關聯表進行sql查詢。若是存在多個關聯參數,每一個參數將會進行一次sql請求。
24 def index(request):
25     # 加入用戶表有10條數據
26     users = models.User.objects.all().prefetch_related('ut')
27     # 這裏會進行2次數據庫sql查詢,第二次查詢會根據第一次的結果進行查詢,
28     for row in users:
29         print(row.user,row.pwd,row_ut_id)
30         print(row.ut.name)
31         print(row.ut1.name)
示例

五、數據驗證(通常不用)

- full_clean 進行驗證

    經歷的步驟:

    - 每一個字段的正則

    - clean鉤子

1 # 也能夠在函數內自定義驗證條件
2 def User(models.Mode):
3     name = models.CharField(max_length=32)
4     email = models.EmailField()
5     def clean(self):  # 這裏的clean是models裏的鉤子,用於重寫操做
6         from django.core.exceptions import ValidationError
7         c = User.object.filter(name=self.name).count()
8         if c:
9             raise ValidationError(message='用戶名已經存在',code='i1')
經過clean實現驗證
 1 1.觸發Model中的驗證和錯誤提示有兩種方式:
 2     a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息
 3     b. 使用ModelForm
 4     c. 調用Model對象的 clean_fields 方法,如:
 5         # models.py
 6         class UserInfo(models.Model):
 7             nid = models.AutoField(primary_key=True)
 8             username = models.CharField(max_length=32)
 9             email = models.EmailField(error_messages={'invalid': '格式錯了.'})
10         # views.py
11         def index(request):
12             obj = models.UserInfo(username='11234', email='uu')
13             try:
14                 print(obj.clean_fields())
15             except Exception as e:
16                 print(e)
17             return HttpResponse('ok')
18        # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。
19 2.Admin中修改錯誤提示
20     # admin.py
21     from django.contrib import admin
22     from model_club import models
23     from django import forms
24     class UserInfoForm(forms.ModelForm):
25         age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'})
26 
27         class Meta:
28             model = models.UserInfo
29             # fields = ('username',)
30             fields = "__all__"
31             exclude = ['title']
32             labels = { 'name':'Writer', }
33             help_texts = {'name':'some useful help text.',}
34             error_messages={ 'name':{'max_length':"this writer name is too long"} }
35             widgets={'name':Textarea(attrs={'cols':80,'rows':20})}
36     class UserInfoAdmin(admin.ModelAdmin):
37         form = UserInfoForm
38     admin.site.register(models.UserInfo, UserInfoAdmin)
驗證和錯誤提示

六、其餘

  1 # Django原生SQL獲取cursor字典
  2 import pymysql
  3 from django.db import connection, connections
  4 connection.connect()
  5 conn = connection.connection
  6 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
  7 cursor.execute("""SELECT * from app01_userinfo""")
  8 row = cursor.fetchone()
  9 connection.close()
 10 
 11 # 數字自增、字符串更新
 12 # 數字自增
 13 from django.db.models import F
 14 models.UserInfo.objects.update(num=F('num') + 1)
 15 # 字符串更新
 16 from django.db.models.functions import Concat
 17 from django.db.models import Value
 18 models.UserInfo.objects.update(name=Concat('name', 'pwd'))
 19 models.UserInfo.objects.update(name=Concat('name', Value('666')))
 20 
 21 
 22 # ORM函數相關
 23 # ########### 基礎函數 ###########
 24     # 1. Concat,用於作類型轉換
 25     # v = models.UserInfo.objects.annotate(c=Cast('pwd', FloatField()))
 26 
 27     # 2. Coalesce,從前向後,查詢第一個不爲空的值
 28     # v = models.UserInfo.objects.annotate(c=Coalesce('name', 'pwd'))
 29     # v = models.UserInfo.objects.annotate(c=Coalesce(Value('666'),'name', 'pwd'))
 30 
 31     # 3. Concat,拼接
 32     # models.UserInfo.objects.update(name=Concat('name', 'pwd'))
 33     # models.UserInfo.objects.update(name=Concat('name', Value('666')))
 34     # models.UserInfo.objects.update(name=Concat('name', Value('666'),Value('999')))
 35 
 36     # 4.ConcatPair,拼接(僅兩個參數)
 37     # v = models.UserInfo.objects.annotate(c=ConcatPair('name', 'pwd'))
 38     # v = models.UserInfo.objects.annotate(c=ConcatPair('name', Value('666')))
 39 
 40     # 5.Greatest,獲取比較大的值;least 獲取比較小的值;
 41     # v = models.UserInfo.objects.annotate(c=Greatest('id', 'pwd',output_field=FloatField()))
 42 
 43     # 6.Length,獲取長度
 44     # v = models.UserInfo.objects.annotate(c=Length('name'))
 45 
 46     # 7. Lower,Upper,變大小寫
 47     # v = models.UserInfo.objects.annotate(c=Lower('name'))
 48     # v = models.UserInfo.objects.annotate(c=Upper('name'))
 49 
 50     # 8. Now,獲取當前時間
 51     # v = models.UserInfo.objects.annotate(c=Now())
 52 
 53     # 9. substr,子序列
 54     # v = models.UserInfo.objects.annotate(c=Substr('name',1,2))
 55 
 56     # ########### 時間類函數 ###########
 57     # 1. 時間截取,不保留其餘:Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,ExtractSecond, ExtractWeekDay, ExtractYear,
 58     # v = models.UserInfo.objects.annotate(c=functions.ExtractYear('ctime'))
 59     # v = models.UserInfo.objects.annotate(c=functions.ExtractMonth('ctime'))
 60     # v = models.UserInfo.objects.annotate(c=functions.ExtractDay('ctime'))
 61     #
 62     # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year'))
 63     # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'month'))
 64     # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year_month'))
 65     """
 66     MICROSECOND
 67     SECOND
 68     MINUTE
 69     HOUR
 70     DAY
 71     WEEK
 72     MONTH
 73     QUARTER
 74     YEAR
 75     SECOND_MICROSECOND
 76     MINUTE_MICROSECOND
 77     MINUTE_SECOND
 78     HOUR_MICROSECOND
 79     HOUR_SECOND
 80     HOUR_MINUTE
 81     DAY_MICROSECOND
 82     DAY_SECOND
 83     DAY_MINUTE
 84     DAY_HOUR
 85     YEAR_MONTH
 86     """
 87     # 2. 時間截圖,保留其餘:Trunc, TruncDate, TruncDay,TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear
 88     # v = models.UserInfo.objects.annotate(c=functions.TruncHour('ctime'))
 89     # v = models.UserInfo.objects.annotate(c=functions.TruncDate('ctime'))
 90     # v = models.UserInfo.objects.annotate(c=functions.Trunc('ctime','year'))
 91 
 92 # ORM自定義函數
 93 from django.db.models.functions.base import Func
 94 class CustomeFunc(Func):
 95     function = 'DATE_FORMAT'
 96     template = '%(function)s(%(expressions)s,%(format)s)'
 97     def __init__(self, expression, **extra):
 98         expressions = [expression]
 99         super(CustomeFunc, self).__init__(*expressions, **extra)
100 v = models.UserInfo.objects.annotate(c=CustomeFunc('ctime',format="'%%Y-%%m'"))
其餘

10、Form組件驗證

一、功能

FORM中的字段只對post上來的數據進行form驗證,主要涉及:字段 和 插件

字段:對用戶請求數據的驗證。

插件:用於自動生成html。

    - 自定義:

        - 建立類

        - 定義字段(驗證)

        - 插件(生成html)

    - 初始化操做

二、示例 

 1 from django import forms
 2 from django.forms import fields
 3 # widgets 插件能夠定義html的標籤和樣式,fields表示字段
 4 from django.forms import widgets
 5 class FM(forms.Form):
 6     # 這裏的各個字段,自己本身只作驗證
 7     user = fields.CharField(
 8         error_messages={'required':'用戶名不能爲空'}, # 錯誤提醒
 9         widget = widgets.Textarea(attrs={'class':'c1','style':'background:#e2e3e4'}), # html標籤和樣式
10         label = '用戶名', # 標籤
11         #initial='admin',  # 定義初始值
12         )
13     pwd = fields.CharField(
14         max_length=12,
15         min_length=6,
16         error_messages={'required':'密碼不能爲空','min_length':'密碼最小長度6位','max_length':'密碼最大長度爲12位'},
17         widget = widgets.PasswordInput(attrs={'style':'background:#e3e4e5'}),
18         label = '密碼',
19     )
20     email = fields.EmailField(
21         error_messages={'required':'郵箱不能夠爲空','invalid':'郵箱格式不正確'},
22         label = '郵箱',
23     )
24     f = fields.FileField(
25         label='上傳文件'
26     )
27     # 能夠顯示指定目錄下全部的文件
28     p = fields.FilePathField(
29         path='d:/'
30     )
31     # 下拉框
32     cite = fields.ChoiceField(
33         choices=[(0,'bj'),(1,'sh'),(2,'sz')]
34     )
35     cite2 = fields.CharField(
36     initial=2,
37     widget=widgets.RadioSelect(choices=((0,'man'),(1,'girl')))
38     )
39     # 多選下拉框
40     mcite = fields.MultipleChoiceField(
41         choices=[(0,'bj'),(1,'sh'),(2,'sz')]
42     )
43 
44 def fm(request):
45     # GET將返回表單輸入框
46     if request.method == 'GET':
47         # 從數據庫提取數據,爲字段生成默認值,注意必須爲字典格式,健必須爲FM的字段名
48         dic = {
49             'user':'r1',
50             'pwd':'abc',
51             'email':'test@test',
52             'cite':1,
53             'mcite':[1,2],
54         }
55         obj = FM(initial=dic) # 這裏將dic做爲參數傳入,便可生成默認值
56         return render(request,'fm.html',{'obj':obj})
57     if request.method == 'POST':
58         # POST獲取全部提交的數據並進行校驗(is_valid),cleaned_data以字典格式返回全部校驗成功的數據,errors返回全部校驗失敗的數據,
59         # 直接將obj返回給前端,前端進行錯誤打印,as_json以json格式打印全部錯誤
60         obj = FM(request.POST)
61         ck = obj.is_valid()
62         if ck:
63             print(obj.cleaned_data)
64             # 將表單數據進行數據庫添加
65             models.UserName.objects.create(**obj.cleaned_data)
66             return redirect('/fm')
67         else:
68             print(obj.errors)
69             print(obj.errors.as_json())
70             return render(request,'fm.html',{'obj':obj})
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     {#功能:實現表單進行數據驗證,並在驗證未經過狀況下,頁面不進行刷新,只提示錯誤#}
 9     <form action="/fm" method="post">
10         {% csrf_token %}
11     {#    如下第一個user.label爲FM表單user字段的label值,第二個obj.user爲FM表單的user字段,最後的一個是FM表單的error_messages錯誤提醒#}
12         {% csrf_token %}
13         <p>{{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }}</p>
14         <p>{{ obj.pwd.label }}{{ obj.pwd }}{{obj.errors.pwd.0 }}</p>
15         <p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>
16         <p>{{ obj.f.label }}{{ obj.f }}{{ obj.errors.f.0 }}</p>
17         <p>{#這個提交的是選中的文件的路徑#}
18             {{ obj.p }}
19         </p>
20         <p>{#choice下拉框選項#}
21             {{ obj.cite }}
22         </p>
23         <p>{#單選#}
24             {{ obj.cite2 }}
25         </p>
26         <p>{{ obj.mcite }}</p>
27     其餘標籤有
28     {#        {{ obj.as_p }}#}
29     {#        {{ obj.as_ul }}#}
30     {#        <table>{{ obj.as_table }}</table>#}
31         <input type="submit" value="提交" />
32     </form>
33 </body>
34 </html>
fm.html

三、form類

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

Django內置字段:

  1 Field
  2     required=True,               是否容許爲空
  3     widget=None,                 HTML插件
  4     label=None,                  用於生成Label標籤或顯示內容
  5     initial=None,                初始值
  6     help_text='',                幫助信息(在標籤旁邊顯示)
  7     error_messages=None,         錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'}
  8     show_hidden_initial=False,   是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直)
  9     validators=[],               自定義驗證規則
 10     localize=False,              是否支持本地化
 11     disabled=False,              是否能夠編輯
 12     label_suffix=None            Label內容後綴
 13 
 14 CharField(Field)
 15     max_length=None,             最大長度
 16     min_length=None,             最小長度
 17     strip=True                   是否移除用戶輸入空白
 18 IntegerField(Field)
 19     max_value=None,              最大值
 20     min_value=None,              最小值
 21 
 22 FloatField(IntegerField)
 23     ...
 24  
 25 DecimalField(IntegerField)
 26     max_value=None,              最大值
 27     min_value=None,              最小值
 28     max_digits=None,             總長度
 29     decimal_places=None,         小數位長度
 30  
 31 BaseTemporalField(Field)
 32     input_formats=None          時間格式化   
 33  
 34 DateField(BaseTemporalField)    格式:2015-09-01
 35 TimeField(BaseTemporalField)    格式:11:12
 36 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 37  
 38 DurationField(Field)            時間間隔:%d %H:%M:%S.%f
 39     ...
 40  
 41 RegexField(CharField)
 42     regex,                      自定製正則表達式
 43     max_length=None,            最大長度
 44     min_length=None,            最小長度
 45     error_message=None,         忽略,錯誤信息使用 error_messages={'invalid': '...'}
 46  
 47 EmailField(CharField)      
 48     ...
 49  
 50 FileField(Field)
 51     allow_empty_file=False     是否容許空文件
 52  
 53 ImageField(FileField)      
 54     ...
 55     注:須要PIL模塊,pip3 install Pillow
 56     以上兩個字典使用時,須要注意兩點:
 57         - form表單中 enctype="multipart/form-data"
 58         - view函數中 obj = MyForm(request.POST, request.FILES)
 59  
 60 URLField(Field)
 61     ...
 62 
 63 BooleanField(Field)  
 64     ...
 65  
 66 NullBooleanField(BooleanField)
 67     ...
 68  
 69 ChoiceField(Field)
 70     ...
 71     choices=(),                選項,如:choices = ((0,'上海'),(1,'北京'),)
 72     required=True,             是否必填
 73     widget=None,               插件,默認select插件
 74     label=None,                Label內容
 75     initial=None,              初始值
 76     help_text='',              幫助提示
 77 
 78 ModelChoiceField(ChoiceField)
 79     ...                        django.forms.models.ModelChoiceField
 80     queryset,                  # 查詢數據庫中的數據
 81     empty_label="---------",   # 默認空顯示內容
 82     to_field_name=None,        # HTML中value的值對應的字段
 83     limit_choices_to=None      # ModelForm中對queryset二次篩選
 84      
 85 ModelMultipleChoiceField(ModelChoiceField)
 86     ...                        django.forms.models.ModelMultipleChoiceField
 87      
 88 TypedChoiceField(ChoiceField)
 89     coerce = lambda val: val   對選中的值進行一次轉換
 90     empty_value= ''            空值的默認值
 91  
 92 MultipleChoiceField(ChoiceField)
 93     ...
 94  
 95 TypedMultipleChoiceField(MultipleChoiceField)
 96     coerce = lambda val: val   對選中的每個值進行一次轉換
 97     empty_value= ''            空值的默認值
 98  
 99 ComboField(Field)
100     fields=()                  使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式
101                                fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
102 MultiValueField(Field)
103     PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用
104  
105 SplitDateTimeField(MultiValueField)
106     input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
107     input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
108  
109 FilePathField(ChoiceField)     文件選項,目錄下文件顯示在頁面中
110     path,                      文件夾路徑
111     match=None,                正則匹配
112     recursive=False,           遞歸下面的文件夾
113     allow_files=True,          容許文件
114     allow_folders=False,       容許文件夾
115     required=True,
116     widget=None,
117     label=None,
118     initial=None,
119     help_text=''
120  
121 GenericIPAddressField
122     protocol='both',           both,ipv4,ipv6支持的IP格式
123     unpack_ipv4=False          解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用
124  
125 SlugField(CharField)           數字,字母,下劃線,減號(連字符)
126     ...
127  
128 UUIDField(CharField)           uuid類型
129     ...
130 '''
131 import uuid
132 # make a UUID based on the host ID and current time
133 uuid.uuid1()    # doctest: +SKIP
134 UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
135 
136 # make a UUID using an MD5 hash of a namespace UUID and a name
137 uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
138 UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
139 
140 # make a UUID from a string of hex digits (braces and hyphens ignored)
141 x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
142 
143 # convert a UUID to a string of hex digits in standard form
144 str(x)
145 '00010203-0405-0607-0809-0a0b0c0d0e0f'
146 
147 # get the raw 16 bytes of the UUID
148 x.bytes
149 b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
150 
151 # make a UUID from a 16-byte string
152 uuid.UUID(bytes=x.bytes)
153 UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
154 '''
內置form

Django內置插件:

 1 TextInput(Input)
 2 NumberInput(TextInput)
 3 EmailInput(TextInput)
 4 URLInput(TextInput)
 5 PasswordInput(TextInput)
 6 HiddenInput(TextInput)
 7 Textarea(Widget)
 8 DateInput(DateTimeBaseInput)
 9 DateTimeInput(DateTimeBaseInput)
10 TimeInput(DateTimeBaseInput)
11 CheckboxInput
12 Select
13 NullBooleanSelect
14 SelectMultiple
15 RadioSelect
16 CheckboxSelectMultiple
17 FileInput
18 ClearableFileInput
19 MultipleHiddenInput
20 SplitDateTimeWidget
21 SplitHiddenDateTimeWidget
22 SelectDateWidget
23 
24 # 單radio,值爲字符串
25 user = fields.CharField(
26     initial=2,
27     widget=widgets.RadioSelect(choices=((1,'aa'),(2,'bb'),))
28 )
29 # 單radio,值爲字符串
30 user = fields.ChoiceField(
31     choices=((1, 'aa'), (2, 'bb'),),
32     initial=2,
33     widget=widgets.RadioSelect
34 ) 
35 # 單select,值爲字符串
36 user = fields.CharField(
37     initial=2,
38     widget=widgets.Select(choices=((1,'aa'),(2,'bb'),))
39 )
40 # 單select,值爲字符串
41 user = fields.ChoiceField(
42     choices=((1, 'aa'), (2, 'bb'),),
43     initial=2,
44     widget=widgets.Select
45 )
46 # 多選select,值爲列表
47 user = fields.MultipleChoiceField(
48     choices=((1,'aa'),(2,'bb'),),
49     initial=[1,],
50     widget=widgets.SelectMultiple
51 )
52 # 單checkbox
53 user = fields.CharField(
54     widget=widgets.CheckboxInput()
55 ) 
56 # 多選checkbox,值爲列表
57 user = fields.MultipleChoiceField(
58     initial=[2, ],
59     choices=((1, 'aa'), (2, 'bb'),),
60     widget=widgets.CheckboxSelectMultiple
61 )
內置插件
 1 # 在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
 2 from django.forms import Form
 3 from django.forms import widgets
 4 from django.forms import fields
 5 from django.core.validators import RegexValidator
 6 
 7 class MyForm(Form):
 8     user = fields.ChoiceField(
 9         # choices=((1, 'aa'), (2, 'bb'),),
10         initial=2,
11         widget=widgets.Select
12     )
13     def __init__(self, *args, **kwargs):
14         super(MyForm,self).__init__(*args, **kwargs)
15         # self.fields['user'].widget.choices = ((1, 'aa'), (2, 'bb'),)
16         #
17         self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
18 # 使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
19 from django import forms
20 from django.forms import fields
21 from django.forms import widgets
22 from django.forms import models as form_model
23 from django.core.exceptions import ValidationError
24 from django.core.validators import RegexValidator
25 class FInfo(forms.Form):
26     authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
27     # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
使用

每一個內置插件均可以經過attr自定製屬性

示例:經過表單實現單選

 1 from django.forms import widgets,fields
 2 from django import forms
 3 from app01 import models
 4 from django.forms.models import ModelChoiceField,ModelMultipleChoiceField
 5 # ModelChoiceField 單選
 6 # ModelMultipleChoiceField 多選
 7 class UserInfoForm(forms.Form):
 8     user = fields.CharField(
 9         required=False,
10         widget = widgets.Textarea(attrs={'class':'c1'})
11     )
12     pwd = fields.CharField(
13         max_length=12,
14         widget = widgets.PasswordInput(attrs={'class':'c1'})
15     )
16     user_type = fields.ChoiceField(
17         # choices=[(0,'普通用戶'),(1,'超級用戶')],
18         choices=[],
19         widget=widgets.Select
20     )
21     user_type2 = fields.CharField(
22         widget=widgets.Select(choices=[])
23     )
24     user_type3 = ModelChoiceField(
25         empty_label='請選擇用戶類型',
26         # 使用此方法雖然不用使用構造方法,可是表須要定製__str__方法
27         queryset=models.UserType.objects.all(),
28         to_field_name='id'  # 生成select標籤內option的value值
29     )
30     def __init__(self,*args,**kwargs):
31         super(UserInfoForm,self).__init__(*args,**kwargs)
32         self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
33         self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')
forms.py
1 def index2(request):
2     from app01.forms import UserInfoForm
3     obj = UserInfoForm()
4     return render(request,'indexform.html',{'obj':obj})
views.py
1 <body>
2     <p>{{ obj.user }}</p>
3     <p>{{ obj.pwd }}</p>
4     <p>{{ obj.user_type }}</p>
5     <p>{{ obj.user_type2 }}</p>
6     <p>{{ obj.user_type3 }}</p>
7 </body>
indexform.html

四、數據驗證

經歷三個階段:

    - 每個字段(正則,字段鉤子)

    - clean

    - _post_clean

對於錯誤信息:總體的錯誤信息放於__all__內。

示例:使用鉤子進行數據驗證

 1 # 鉤子舉例,註冊,登陸
 2 from django.core.exceptions import ValidationError
 3 from django import forms
 4 from app01 import models
 5 from django.forms import widgets
 6 from django.forms import fields
 7 
 8 class RegisterForm(forms.Form):
 9     '''字段增長驗證方式,首先進行user字段的正則表達式驗證,若是經過了。而後進行源碼裏預留的鉤子clean_user驗證'''
10     user = fields.CharField()
11     email = fields.EmailField()
12 
13     def clean_user(self):
14         '''源碼裏經過鉤子clean+_field,增長正則表達式驗證'''
15         c = models.User.objects.filter(name=self.cleaned_data['user']).count()
16         if not c:
17             return self.cleaned_data['user']
18         else:
19             raise ValidationError('用戶名已經存在',code='xxx')
20     def clean_email(self):
21         pass
22 class LoginForm(forms.Form):
23     user = fields.CharField()
24     pwd = fields.CharField(validators=[])  # 這個參數能夠自定義正則表達式驗證
25 
26     def clean_user(self):
27         '''第一類鉤子字段驗證,源碼裏經過鉤子clean+_field,增長正則表達式驗證'''
28         c = models.User.objects.filter(name=self.cleaned_data['user']).count()
29         if not c:
30             return self.cleaned_data['user']
31         else:
32             raise ValidationError('用戶名已經存在',code='xxx')
33     def clean_pwd(self):
34         pass
35     def clean(self):
36         '''第二類鉤子 總體進行驗證'''
37         self.cleaned_data['user']
38         self.cleaned_data['pwd']
39         c = models.User.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
40         if c:
41             return self.cleaned_data
42         else:
43             raise ValidationError('用戶名或密碼錯誤')
44     def _post_clean(self):
45         '''第三類鉤子'''
46         pass
forms.py
1 def register(request):
2     from app01.forms import RegisterForm
3     obj = RegisterForm(request.POST)
4     if obj.is_valid():
5         obj.cleaned_data
6     else:
7         obj.errors
views.py

五、初始化數據

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

 1 1、form
 2 from django.forms import Form
 3 from django.forms import widgets
 4 from django.forms import fields
 5 from django.core.validators import RegexValidator
 6 class MyForm(Form):
 7     user = fields.CharField()
 8     city = fields.ChoiceField(
 9         choices=((1, '上海'), (2, '北京'),),
10         widget=widgets.Select
11     )
12 2、views
13 from django.shortcuts import render, redirect
14 from .forms import MyForm
15 def index(request):
16     if request.method == "GET":
17         values = {'user': 'root', 'city': 2}
18         obj = MyForm(values)
19         return render(request, 'index.html', {'form': obj})
20     elif request.method == "POST":
21         return redirect('http://www.google.com')
22     else:
23         return redirect('http://www.google.com')
24 3、HTML
25 <form method="POST" enctype="multipart/form-data">
26     {% csrf_token %}
27     <p>{{ form.user }} {{ form.user.errors }}</p>
28     <p>{{ form.city }} {{ form.city.errors }}</p>
29     <input type="submit"/>
30 </form>
初始化

11、ModelForm操做

在使用Model和Form時,都須要對字段進行定義並指定類型,經過ModelForm則能夠省去From中字段的定義

一、ModelForm(耦合很強)

    能夠實現

    1:數據庫操做

    2:數據驗證

    使用地方:1:小型項目,2:自定製jdango admin

二、功能:

    1:能夠生成html標籤:class Meta...

    2:mf = xxxModelForm(instance=ModelObj)

    3:額外的標籤:is_rmb=Ffields.CharField(widget=Fwidgets.CheckboxInput())

    4:各類驗證,is_valid() ->各類鉤子

    5:mf.save()

        或

        instance = mf.save(False)

        instance.save()

        mf.save_m2m()

三、字段

from django.shortcuts import render
from django import forms
from django.forms import fields as Ffields
from app01 import models
from django.forms import widgets as Fwidgets

# ModelForm中的字段
class UserInfoModelForm(forms.ModelForm):
    # 自定製一些額外的字段
    is_rmb = Ffields.CharField(
        widget= Fwidgets.CheckboxInput()
    )
    class Meta:
        model = models.UserInfo    # 對應的model
        fields = '__all__'        # 所有字段
        # fields = ['..','..']    # 指定字段名
        # fields = ['username','email']
        # exclude = ['username']  #除某個字段以外(排除的字段名)
        labels = {              # 提示信息
            'username':'用戶名',
            'email':'郵箱'
        }
        help_texts = {          # 標籤後的提示信息
            'username':'提示信息'
        }
        widgets = {
            'username':Fwidgets.Textarea(attrs={'class':'c1'})
        }
        error_messages = {      # 字段錯誤提醒
            # '__all__':{'總體的錯誤信息'},
            'email':{ 'required':'郵箱不能爲空','invalid':'郵箱格式不對'}
        }
        # field_classes = {       # 自定義字段類,這裏是將input標籤的email的字段修改成url屬性
        #     'email':Ffields.URLField
        # }
        # localized_fields = ('ctime',)    # 指定哪些字段使用東八區時間,也就是本地化
        '''
            如:
                數據庫中
                    2016-12-27 04:10:57
                setting中的配置
                    TIME_ZONE = 'Asia/Shanghai'
                    USE_TZ = True
                則顯示:
                    2016-12-27 12:10:57
        '''
    # 鉤子
    def clean_username(self):
        old = self.cleaned_data['username']
        return old
ModelForm字段

四、其餘功能

 1    
 2 1. 驗證執行過程
 3     is_valid -> full_clean -> 鉤子 -> 總體錯誤
 4 2. 字典字段驗證
 5     def clean_字段名(self):
 6         # 能夠拋出異常
 7         # from django.core.exceptions import ValidationError
 8         return "新值"
 9 3. 用於驗證
10     model_form_obj = XXOOModelForm()
11     model_form_obj.is_valid()
12     model_form_obj.errors.as_json()
13     model_form_obj.clean()
14     model_form_obj.cleaned_data
15 4. 用於建立
16     model_form_obj = XXOOModelForm(request.POST)
17     #### 頁面顯示,並提交 #####
18     # 默認保存多對多
19         obj = form.save(commit=True)
20     # 不作任何操做,內部定義 save_m2m(用於保存多對多)
21         obj = form.save(commit=False)
22         obj.save()      # 保存單表信息
23         obj.save_m2m()  # 保存關聯多對多信息
24 5. 用於更新和初始化
25     obj = model.tb.objects.get(id=1)
26     model_form_obj = XXOOModelForm(request.POST,instance=obj)
27     ...
28     PS: 單純初始化
29         model_form_obj = XXOOModelForm(initial={...})
ModelForm執行過程及驗證初始化

五、示例:用戶管理

  1 from django.shortcuts import render
  2 from django import forms
  3 from django.forms import fields as Ffields
  4 from app01 import models
  5 from django.forms import widgets as Fwidgets
  6 
  7 # ModelForm中的字段
  8 class UserInfoModelForm(forms.ModelForm):
  9     # 自定製一些額外的字段
 10     is_rmb = Ffields.CharField(
 11         widget= Fwidgets.CheckboxInput()
 12     )
 13     class Meta:
 14         model = models.UserInfo    # 對應的model
 15         fields = '__all__'        # 所有字段
 16         # fields = ['..','..']    # 指定字段名
 17         # fields = ['username','email']
 18         # exclude = ['username']  #除某個字段以外(排除的字段名)
 19         labels = {              # 提示信息
 20             'username':'用戶名',
 21             'email':'郵箱'
 22         }
 23         help_texts = {          # 標籤後的提示信息
 24             'username':'提示信息'
 25         }
 26         widgets = {
 27             'username':Fwidgets.Textarea(attrs={'class':'c1'})
 28         }
 29         error_messages = {      # 字段錯誤提醒
 30             # '__all__':{'總體的錯誤信息'},
 31             'email':{ 'required':'郵箱不能爲空','invalid':'郵箱格式不對'}
 32         }
 33         # field_classes = {       # 自定義字段類,這裏是將input標籤的email的字段修改成url屬性
 34         #     'email':Ffields.URLField
 35         # }
 36         # localized_fields = ('ctime',)    # 指定哪些字段使用東八區時間,也就是本地化
 37         '''
 38             如:
 39                 數據庫中
 40                     2016-12-27 04:10:57
 41                 setting中的配置
 42                     TIME_ZONE = 'Asia/Shanghai'
 43                     USE_TZ = True
 44                 則顯示:
 45                     2016-12-27 12:10:57
 46         '''
 47     # 鉤子
 48     def clean_username(self):
 49         old = self.cleaned_data['username']
 50         return old
 51 
 52 class UserInfoForm(forms.Form):
 53     username = Ffields.CharField(max_length=32)
 54     email = Ffields.EmailField()
 55     user_type = Ffields.ChoiceField(
 56         choices=models.UserType.objects.values_list('id','caption')
 57     )
 58     def __init__(self,*args,**kwargs):
 59         super(UserInfoForm,self).__init__(*args,**kwargs)
 60         self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')
 61 
 62 def index(request):
 63     if request.method == 'GET':
 64         obj = UserInfoModelForm()
 65         return render(request,'index.html',{'obj':obj})
 66     elif request.method == 'POST':
 67         obj = UserInfoModelForm(request.POST)
 68         if obj.is_valid():
 69             obj.save()
 70             '''
 71            下面三句和上面的一句是等價的關係
 72            instance = obj.save(False)
 73            instance.save()  #只會保存當前類信息不會保存manytomany
 74            obj.save_m2m()
 75            '''
 76         # print(obj.is_valid())
 77         # print(obj.cleaned_data)
 78         # print(obj.errors.as_json())
 79         # models.UserInfo.objects.create(**obj.cleaned_data)
 80         return render(request,'index.html',{'obj':obj})
 81 
 82 
 83 def user_list(request):
 84     li = models.UserInfo.objects.all().select_related('user_type')
 85     return render(request,'user_list.html',{'li':li})
 86 
 87 def user_edit(request,nid):
 88     # 獲取當前id對應的用戶信息
 89     # 顯示用戶已經存在的數據
 90     if request.method == "GET":
 91         user_obj = models.UserInfo.objects.filter(id=nid).first()
 92         mf = UserInfoModelForm(instance=user_obj)
 93         return render(request,'user_edit.html',{'mf':mf,'nid':nid})
 94     elif request.method == "POST":
 95         user_obj = models.UserInfo.objects.filter(id=nid).first()
 96         mf = UserInfoModelForm(request.POST,instance=user_obj)
 97         if mf.is_valid():
 98             mf.save()
 99         else:
100             print(mf.errors.as_json())
101         return render(request,'user_edit.html',{'mf':mf,'nid':nid})
102 
103 
104 
105  
views.py
 1 from django.contrib import admin
 2 from django.urls import path
 3 from django.conf.urls import url
 4 from app01 import views
 5 
 6 urlpatterns = [
 7     path('admin/', admin.site.urls),
 8     url(r'^index/',views.index),
 9     url(r'^user_list/',views.user_list),
10     url(r'^edit-(\d+)/',views.user_edit),
11 ]
urls.py
 1 from django.db import models
 2 
 3 # Create your models here.
 4 
 5 class UserType(models.Model):
 6     caption = models.CharField(max_length=32)
 7 
 8 class UserGroup(models.Model):
 9     name = models.CharField(max_length=32)
10 
11 class UserInfo(models.Model):
12     username = models.CharField(max_length=32)
13     email = models.EmailField()
14     user_type = models.ForeignKey(to='UserType',to_field='id',on_delete=models.CASCADE)
15     u2g = models.ManyToManyField('UserGroup')
models.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <ul>
 9         {% for row in li %}
10             <li>{{ row.username }} - {{ row.user_type.caption }}- <a href="/edit-{{ row.id }}/">編輯</a></li>
11         {% endfor %}
12     </ul>
13 </body>
14 </html>
user_list.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form method="POST" action="/edit-{{ nid }}/">
 9         {% csrf_token %}
10         {{ mf.as_p }}
11         <input type="submit" value="提交"/>
12     </form>
13 
14 </body>
15 </html>
user_edit.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/index/" method="POST">
 9         {% csrf_token %}
10         {{ obj.as_p}}
11         <input type="submit" value="提交"/>
12     </form>
13 </body>
14 </html>
index.html

12、cookie

一、獲取Cookie

 1 def cookie(request):
 2     request.COOKIES
 3     request.COOKIES['key']  #獲取cookie
 4     request.COOKIES.get('key') #獲取cookie
 5     '''
 6     request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
 7         參數:
 8             default: 默認值
 9                salt: 加密鹽
10             max_age: 後臺控制過時時間
11     '''
views.py

二、設置Cookie

(帶簽名的cookie:rep.set_signed_cookie)

    response = HttpResponse(...)
    response = render(request, 'index.html')
    response = redirect('/index/')
    
    response.set_cookie(key,value,...)
    response.set_signed_cookie(key,value,salt='加密鹽',...)
    '''
        參數:
            key,              鍵
            value='',         值
            max_age=None,     超時時間
            expires=None,     超時時間(IE requires expires, so set it if hasn't been already.)
            path='/',         Cookie生效的路徑,/ 表示根路徑,特殊的:跟路徑的cookie能夠被任何url的頁面訪問
            domain=None,      Cookie生效的域名
            secure=False,     https傳輸
            httponly=False    只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)
    '''
設置cookie

三、JavaScript和jquery也能夠操做cookie

<script src='/static/js/jquery.cookie.js'></script>

$.cookie( "list_pager_num" 30 ,{ path:  '/'  });

基於cookie實現定製顯示數據條數 

from django.shortcuts import render,HttpResponse,redirect
from django.urls import reverse
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 all_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.all_count < self.pager_num:
            start_index = 1
            end_index = self.all_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.all_count:
                    end_index = self.all_count + 1
                    start_index = self.all_count - self.pager_num + 1
        if self.current_page == 1:
            prev = '<a class="page" href="#">上一頁</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.all_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 = ''.join(page_list)
        page_str = mark_safe(page_str)
        return page_str


LIST = []
for i in range(1009):
    LIST.append(i)
def user_list(request):
    current_page = request.GET.get('p',1)
    current_page = int(current_page)
    val = request.COOKIES.get('per_page_count')
    print(val)
    val = int(val)
    page_obj = 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})
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pagination .page{
            display: inline-block;
            padding: 5px;
            margin: 5px;
        }
        .pagination .page.active{
            color: white;
            background-color: black;
        }
    </style>
</head>
<body>
    <ul>
        {% for item in li %}
            {% include 'li.html' %}
        {% endfor %}
    </ul>
    <div>
        <select id="ps" onchange="changePageSize(this)">
            <option value="10">10</option>
            <option value="30">30</option>
            <option value="50">50</option>
            <option value="100">100</option>
        </select>
    </div>
    <div class="pagination">
        {{ page_str }}
    </div>
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        $(function(){
            var v = $.cookie('per_page_count',v,{'path':'/user_list/'});
            $('#ps').val(v);
        });
        function changePageSize(ths){
            var v = $(ths).val();
            console.log(v);
            $.cookie('per_page_count',v,{'path':'/user_list/'});
            location.reload();
        }
    </script>
</body>
</html>
user_list.html

十3、session

一、session基本概念及基本操做

cookie是保存在用戶瀏覽器端的鍵值對、session是保存在服務器端的鍵值對、session依賴於cookie

簡單描述session:用戶來請求登錄成功以後,服務器生成一個隨機字符串給用戶,而且在服務器端也保存起來,而且保存的字符串對應一個字典,放置當前用戶的全部信息

服務器session操做:

 1 def index(request):
 2     # 獲取、設置、刪除Session中數據
 3     request.session['k1'] #數據不存在會報錯
 4     request.session.get('k1',None)  #不存在返回none,不報錯
 5     request.session['k1'] = 123  #不存在建立,存在則更新
 6     request.session.setdefault('k1',123) # 存在則不設置
 7     del request.session['k1']  #刪除
 8 
 9     # 全部 鍵、值、鍵值對
10     request.session.keys()
11     request.session.values()
12     request.session.items()
13     request.session.iterkeys()
14     request.session.itervalues()
15     request.session.iteritems()
16 
17     # 用戶session的隨機字符串
18     request.session.session_key  #用來獲取用戶端的用戶隨機字符串
19     # 將全部Session失效日期小於當前日期的數據刪除
20     request.session.clear_expired()
21     # 檢查 用戶session的隨機字符串 在數據庫中是否
22     request.session.exists("session_key")
23     # 刪除當前用戶的全部Session數據
24     request.session.delete("session_key")
25     request.session.set_expiry(value)
26         * 若是value是個整數,session會在些秒數後失效。
27         * 若是value是個datatime或timedelta,session就會在這個時間後失效。
28         * 若是value是0,用戶關閉瀏覽器session就會失效。
29         * 若是value是None,session會依賴全局session失效策略。
session操做

在settings.py設置文件中設置默認操做:

1 SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
2 SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
3 SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路徑(默認)
4 SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默認)
5 SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(默認)
6 SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http傳輸(默認)
7 SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默認)
8 SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過時(默認)
9 SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都保存Session,默認修改以後才保存(默認)
settings.py

在settings.py設置文件中設置引擎:

Django中默認支持Session,其內部提供了5種類型的Session供開發者使用

 1 1、數據庫Session
 2     SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
 3 2、緩存Session
 4     SESSION_ENGINE = 'django.contrib.sessions.backends.cache' 
 5     SESSION_CACHE_ALIAS = 'default'    # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
 6 3、文件Session
 7     SESSION_ENGINE = 'django.contrib.sessions.backends.file'    
 8     SESSION_FILE_PATH = None     # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 9 四、緩存+數據庫Session
10 數據庫用於作持久化,緩存用於提升效率
11     SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'   
12 5、加密cookie Session
13     SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'  
14  
settings.py

二、用戶登錄驗證示例

Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。

簡單使用session:配置好session後

執行:- python manage.py makemigrations

   - python manage.py migrate

 1 from django.shortcuts import render,redirect,HttpResponse
 2 # Create your views here.
 3 def login(request):
 4     if request.method == 'GET':
 5         return render(request,'login.html')
 6     elif request.method == 'POST':
 7         user = request.POST.get('user')
 8         pwd = request.POST.get('pwd')
 9         if user == 'root' and pwd == '123':
10             #生成隨機字符串
11             #寫到用戶瀏覽器cookie
12             #保存到session中
13             #在隨機字符串對應的字典中設置相關內容
14 
15             #session中設置值
16             request.session['username'] = user
17             request.session['is_login'] = True
18             if request.POST.get('rmb',None) == '1':
19                 #人爲的獲取設置超時時間
20                 request.session.set_expiry(10)
21             return redirect('/index/')
22         else:
23             return render(request,'login.html')
24 def index(request):
25     #獲取當前用戶的隨機字符串
26     #根據隨機字符串獲取對應的信息
27 
28     #session中獲取值
29     # if request.session['is_login']:
30     if request.session.get('is_login',None):
31         # return HttpResponse(request.session['username'])
32         return render(request,'index.html',{'username':request.session['username']})
33     else:
34         return HttpResponse('醜拒!')
35 def logout(request):
36     request.session.clear()
37     return redirect('/login/')
views.py
 1 """day22 URL Configuration
 2 
 3 The `urlpatterns` list routes URLs to views. For more information please see:
 4     https://docs.djangoproject.com/en/2.1/topics/http/urls/
 5 Examples:
 6 Function views
 7     1. Add an import:  from my_app import views
 8     2. Add a URL to urlpatterns:  path('', views.home, name='home')
 9 Class-based views
10     1. Add an import:  from other_app.views import Home
11     2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
12 Including another URLconf
13     1. Import the include() function: from django.urls import include, path
14     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
15 """
16 from django.contrib import admin
17 from django.urls import path
18 from django.conf.urls import url
19 from app01 import views
20 urlpatterns = [
21     path('admin/', admin.site.urls),
22     url(r'^login/', views.login),
23     url(r'^index/', views.index),
24     url(r'^logout/', views.logout),
25 ]
urls.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <h1>歡迎登錄,{{ username }},{{ request.session.username }}</h1>
 9     <a href="/logout/">註銷</a>
10 </body>
11 </html>
index.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/login/" method="POST">
 9         <input type="text" name="user"/>
10         <input type="text" name="pwd"/>
11         <input type="checkbox" name="rmb" value="1"/> 10秒免登錄
12         <input type="submit" value="提交"/>
13     </form>
14 </body>
15 </html>
login.html

十4、跨站請求僞造

django爲用戶實現防止跨站請求僞造的功能,經過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。

而對於django中設置防跨站請求僞造功能有分爲全局和局部。

一、全局:

settings.py中的:MIDDLEWARE

中間件 django.middleware.csrf.CsrfViewMiddleware

二、局部:

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

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

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

三、普通表單應用:

1 veiw中設置返回值:
2   return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
3      或者
4      return render(request, 'xxx.html', data)
5 html中設置Token:
6   {% csrf_token %}
普通表單

四、ajax應用:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form action="/login/" method="POST">
 9     {# 對於傳統的form,能夠經過表單的方式將token再次發送到服務端#}
10         {% csrf_token %}   {# html中設置Token:#}
11         <input type="text" name="user"/>
12         <input type="text" name="pwd"/>
13         <input type="checkbox" name="rmb" value="1"/> 10秒免登錄
14         <input type="submit" value="提交"/>
15         <input id="btn" type="button" value="按鈕"/>
16     </form>
17     <script src="/static/jquery-1.12.4.js"></script>
18     <script src="/static/jquery.cookie.js"></script>
19     <script>
20     {# ajax設置token#}
21     //全局設置
22         $(function(){
23             $.ajaxSetup({
24                 beforeSend:function(xhr,setting){
25                     xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
26                 }
27             });
28             var csrftoken = $.cookie('csrftoken');
29             $('#btn').click(function(){
30                 $.ajax({
31                     url:'/login/',
32                     type:'POST',
33                     {# headers:{'X-CSRFtoken':$.cookie('csrftoken')},#}  //單獨設置
34                     data:{'user':'root','pwd':'123'},
35                     success:function(arg){
36                     }
37                 })
38             })
39         })
40     </script>
41 </body>
42 </html>
login.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     {% csrf_token %}
 9     <input type="button" onclick="Do();"  value="Do it"/>
10     <script src="/static/jquery-1.12.4.js"></script>
11     <script src="/static/jquery.cookie.js"></script>
12     <script type="text/javascript">
13         var csrftoken = $.cookie('csrftoken');
14         function csrfSafeMethod(method) {
15             // these HTTP methods do not require CSRF protection
16             return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
17         }
18         $.ajaxSetup({
19             beforeSend: function(xhr, settings) {
20                 if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
21                     xhr.setRequestHeader("X-CSRFToken", csrftoken);
22                 }
23             }
24         });
25         function Do(){
26             $.ajax({
27                 url:"/app01/test/",
28                 data:{id:1},
29                 type:'POST',
30                 success:function(data){
31                     console.log(data);
32                 }
33             });
34         }
35     </script>
36 </body>
37 </html>
ajax示例

十5、中間件

在django中,中間件其實就是一個類,在請求到來和結束後,django會根據本身的規則在合適的時機執行中間件中相應的方法。

在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每個元素就是一箇中間件。

一、中間件中能夠定義的方法:

process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs) #process_request執行完成後執行
process_response(self, request, response)
process_exception(self, request, exception)  #當views函數出錯時執行
process_template_response(self,request,response)  #若是views中的函數返回的對象中具備render方法時執行(用不到)
以上方法的返回值能夠是None和HttpResonse對象,若是是None,則繼續按照django定義的規則向下執行,若是是HttpResonse對象,則直接將該對象返回給用戶。
可定義的方法

二、自定義中間件

與mange.py在同一目錄下的文件夾 Middle下的m1.py文件中:

 1 from django.utils.deprecation import MiddlewareMixin
 2 
 3 class Row1(MiddlewareMixin):
 4     def process_request(self,request):
 5         print('第一層進')
 6     def process_response(self,request,response):
 7         print('第一層出')
 8         return response
 9 # from django.shortcuts import HttpResponse
10 class Row2(MiddlewareMixin):
11     def process_request(self,request):
12         print('第二層進')
13         # return HttpResponse('拒絕!!!')
14     def process_response(self,request,response):
15         print('第二層出')
16         return response
17 
18 class Row3(MiddlewareMixin):
19     def process_request(self,request):
20         print('第三層進')
21     def process_response(self,request,response):
22         print('第三層出')
23         return response
m1.py

三、註冊中間件

 1 MIDDLEWARE = [
 2     'django.middleware.security.SecurityMiddleware',
 3     'django.contrib.sessions.middleware.SessionMiddleware',
 4     'django.middleware.common.CommonMiddleware',
 5     'django.middleware.csrf.CsrfViewMiddleware',
 6     'django.contrib.auth.middleware.AuthenticationMiddleware',
 7     'django.contrib.messages.middleware.MessageMiddleware',
 8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 9     'Middle.m1.Row1',
10     'Middle.m1.Row2',
11     'Middle.m1.Row3',
12 ]
settings.py

十6、緩存

因爲Django是動態網站,全部每次請求均會去數據進行相應的操做,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存

緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則再也不去執行view中的操做,而是直接從內存或者Redis中以前緩存的內容拿到,並返回。

Django中提供了5種緩存方式:開發調試、內存、文件、數據庫、Memcache緩存(python-memcached模塊、pylibmc模塊) 

一、配置:

  1 1、開發調試方式
  2 # 此爲開始調試用,實際內部不作任何操做
  3 # 配置:
  4     CACHES = {
  5         'default': {
  6             'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
  7             'TIMEOUT': 300,                                               # 緩存超時時間(默認300,None表示永不過時,0表示當即過時)
  8             'OPTIONS':{
  9                 'MAX_ENTRIES': 300,                                       # 最大緩存個數(默認300)
 10                 'CULL_FREQUENCY': 3,                                      # 緩存到達最大個數以後,剔除緩存個數的比例,即:1/CULL_FREQUENCY(默認3)
 11             },
 12             'KEY_PREFIX': '',                                             # 緩存key的前綴(默認空)
 13             'VERSION': 1,                                                 # 緩存key的版本(默認1)
 14             'KEY_FUNCTION' 函數名                                          # 生成key的函數(默認函數會生成爲:【前綴:版本:key】)
 15         }
 16     }
 17 # 自定義key
 18 def default_key_func(key, key_prefix, version):
 19     """
 20     Default function to generate keys.
 21     Constructs the key used by all other methods. By default it prepends
 22     the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
 23     function with custom key making behavior.
 24     """
 25     return '%s:%s:%s' % (key_prefix, version, key)
 26 def get_key_func(key_func):
 27     """
 28     Function to decide which key function to use.
 29     Defaults to ``default_key_func``.
 30     """
 31     if key_func is not None:
 32         if callable(key_func):
 33             return key_func
 34         else:
 35             return import_string(key_func)
 36     return default_key_func
 37 2、內存方式
 38 # 此緩存將內容保存至內存的變量中
 39 # 配置:
 40     CACHES = {
 41         'default': {
 42             'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
 43             'LOCATION': 'unique-snowflake',
 44         }
 45     }
 46 3、文件方式
 47 # 此緩存將內容保存至文件
 48 # 配置:
 49 
 50     CACHES = {
 51         'default': {
 52             'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
 53             'LOCATION': '/var/tmp/django_cache',
 54         }
 55     }
 56 4、數據庫方式
 57 # 此緩存將內容保存至數據庫
 58 # 配置:
 59     CACHES = {
 60         'default': {
 61             'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
 62             'LOCATION': 'my_cache_table', # 數據庫表
 63         }
 64     }
 65 # 注:執行建立表命令 python manage.py createcachetable
 66 5、Memcache緩存方式
 67 # 此緩存使用python-memcached模塊鏈接memcache
 68     CACHES = {
 69         'default': {
 70             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
 71             'LOCATION': '127.0.0.1:11211',
 72         }
 73     }
 74     CACHES = {
 75         'default': {
 76             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
 77             'LOCATION': 'unix:/tmp/memcached.sock',
 78         }
 79     }
 80     CACHES = {
 81         'default': {
 82             'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
 83             'LOCATION': [
 84                 '172.19.26.240:11211',
 85                 '172.19.26.242:11211',
 86             ]
 87         }
 88     }
 89 # 此緩存使用pylibmc模塊鏈接memcache
 90     CACHES = {
 91         'default': {
 92             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
 93             'LOCATION': '127.0.0.1:11211',
 94         }
 95     }
 96     CACHES = {
 97         'default': {
 98             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
 99             'LOCATION': '/tmp/memcached.sock',
100         }
101     }
102     CACHES = {
103         'default': {
104             'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
105             'LOCATION': [
106                 '172.19.26.240:11211',
107                 '172.19.26.242:11211',
108             ]
109         }
110     }
111 6、Redis緩存方式
112     CACHES = {
113         "default": {
114             "BACKEND": "django_redis.cache.RedisCache",
115             "LOCATION": "redis://127.0.0.1:6379",
116             "OPTIONS": {
117                 "CLIENT_CLASS": "django_redis.client.DefaultClient",
118                 "CONNECTION_POOL_KWARGS": {"max_connections": 100}
119                 # "PASSWORD": "密碼",
120             }
121         }
122     }
123 #視圖中連接並操做
124 from django_redis import get_redis_connection
125 conn = get_redis_connection("default")
配置緩存

二、應用:

 1 1、全站使用
 2 使用中間件,通過一系列的認證等操做,若是內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶以前,判斷緩存中是否已經存在,若是不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存
 3     MIDDLEWARE = [
 4         'django.middleware.cache.UpdateCacheMiddleware',
 5         # 其餘中間件...
 6         'django.middleware.cache.FetchFromCacheMiddleware',
 7     ]
 8 
 9     CACHE_MIDDLEWARE_ALIAS = ""
10     CACHE_MIDDLEWARE_SECONDS = ""
11     CACHE_MIDDLEWARE_KEY_PREFIX = ""
12 2、單獨視圖緩存
13 方式一:
14     from django.views.decorators.cache import cache_page
15 
16     @cache_page(60 * 15)
17     def my_view(request):
18         ...
19 方式二:
20     from django.views.decorators.cache import cache_page
21     urlpatterns = [
22         url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
23     ]
24 3、局部視圖使用
25 a. 引入TemplateTag
26     {% load cache %}
27 b. 使用緩存
28     {% cache 5000 緩存key %}
29         緩存內容
30     {% endcache %}
緩存應用

十7、信號

jango中提供了「信號調度」,用於在框架執行操做時解耦。

通俗來說,就是一些動做發生的時候,信號容許特定的發送者去提醒一些接受者

一、所有內置信號:

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

二、信號的使用:

 1 from django.core.signals import request_finished
 2 from django.core.signals import request_started
 3 from django.core.signals import got_request_exception
 4 
 5 from django.db.models.signals import class_prepared
 6 from django.db.models.signals import pre_init, post_init
 7 from django.db.models.signals import pre_save, post_save
 8 from django.db.models.signals import pre_delete, post_delete
 9 from django.db.models.signals import m2m_changed
10 from django.db.models.signals import pre_migrate, post_migrate
11 
12 from django.test.signals import setting_changed
13 from django.test.signals import template_rendered
14 
15 from django.db.backends.signals import connection_created
16 
17 def callback(sender, **kwargs):
18     print("f1_callback")
19     print(sender,kwargs)
20 f1.connect(callback)
21 # f1指上述導入的內容
22 
23 from django.core.signals import request_finished
24 from django.dispatch import receiver
25 @receiver(request_finished)
26 def my_callback(sender, **kwargs):
27     print("Request finished!")
信號使用

十8、動態驗證碼

Python生成隨機驗證碼,須要使用PIL模塊

安裝:pip3 install pillow

一、基本使用:

 1 1. 建立圖片
 2 from PIL import Image
 3 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
 4 # 在圖片查看器中打開
 5 # img.show()
 6 # 保存在本地
 7 with open('code.png','wb') as f:
 8     img.save(f,format='png')
 9 2. 建立畫筆,用於在圖片上畫任意內容
10 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
11 draw = ImageDraw.Draw(img, mode='RGB')
12 3. 畫點
13 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
14 draw = ImageDraw.Draw(img, mode='RGB')
15 # 第一個參數:表示座標
16 # 第二個參數:表示顏色
17 draw.point([100, 100], fill="red")
18 draw.point([300, 300], fill=(255, 255, 255))
19 4. 畫線
20 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
21 draw = ImageDraw.Draw(img, mode='RGB')
22 # 第一個參數:表示起始座標和結束座標
23 # 第二個參數:表示顏色
24 draw.line((100,100,100,300), fill='red')
25 draw.line((100,100,300,100), fill=(255, 255, 255))
26 5. 畫圓
27 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
28 draw = ImageDraw.Draw(img, mode='RGB')
29 # 第一個參數:表示起始座標和結束座標(圓要畫在其中間)
30 # 第二個參數:表示開始角度
31 # 第三個參數:表示結束角度
32 # 第四個參數:表示顏色
33 draw.arc((100,100,300,300),0,90,fill="red")
34 6. 寫文本
35 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
36 draw = ImageDraw.Draw(img, mode='RGB')
37 # 第一個參數:表示起始座標
38 # 第二個參數:表示寫入內容
39 # 第三個參數:表示顏色
40 draw.text([0,0],'python',"red")
41 7. 特殊字體文字
42 img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
43 draw = ImageDraw.Draw(img, mode='RGB')
44 # 第一個參數:表示字體文件路徑
45 # 第二個參數:表示字體大小
46 font = ImageFont.truetype("kumo.ttf", 28)
47 # 第一個參數:表示起始座標
48 # 第二個參數:表示寫入內容
49 # 第三個參數:表示顏色
50 # 第四個參數:表示顏色
51 draw.text([0, 0], 'python', "red", font=font)
pillow基本使用
 1 import random
 2 def check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
 3     code = []
 4     img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
 5     draw = ImageDraw.Draw(img, mode='RGB')
 6     def rndChar():
 7         """
 8         生成隨機字母
 9         :return:
10         """
11         return chr(random.randint(65, 90))
12     def rndColor():
13         """
14         生成隨機顏色
15         :return:
16         """
17         return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
18     # 寫文字
19     font = ImageFont.truetype(font_file, font_size)
20     for i in range(char_length):
21         char = rndChar()
22         code.append(char)
23         h = random.randint(0, 4)
24         draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
25     # 寫干擾點
26     for i in range(40):
27         draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
28     # 寫干擾圓圈
29     for i in range(40):
30         draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
31         x = random.randint(0, width)
32         y = random.randint(0, height)
33         draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
34     # 畫干擾線
35     for i in range(5):
36         x1 = random.randint(0, width)
37         y1 = random.randint(0, height)
38         x2 = random.randint(0, width)
39         y2 = random.randint(0, height)
40         draw.line((x1, y1, x2, y2), fill=rndColor())
41     img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
42     return img,''.join(code)
43 if __name__ == '__main__':
44     # 1. 直接打開
45     # img,code = check_code()
46     # img.show()
47     # 2. 寫入文件
48     # img,code = check_code()
49     # with open('code.png','wb') as f:
50     #     img.save(f,format='png')
51     # 3. 寫入內存(Python3)
52     # from io import BytesIO
53     # stream = BytesIO()
54     # img.save(stream, 'png')
55     # stream.getvalue()
56     # 4. 寫入內存(Python2)
57     # import StringIO
58     # stream = StringIO.StringIO()
59     # img.save(stream, 'png')
60     # stream.getvalue()
61     pass
圖片驗證碼

二、圖片驗證碼應用:

 1 方式一:
 2  # 方式一:這樣的方式吧路徑寫死了,只能是那一張圖片
 3     import os
 4     path = os.path.join(settings.BASE_DIR,"static","image","3.jpg")  #路徑拼接
 5     with open(path,"rb") as f:
 6         data = f.read()
 7     return HttpResponse(data)
 8 方式二:
 9 # 方式二:每次都顯示不一樣的圖片,利用pillow模塊,安裝一個pillow模塊
10     from PIL import Image
11     img = Image.new(mode="RGB",size=(120,40),color="green") #首先本身建立一個圖片,參數size=(120,40) 表明長和高
12     f = open("validcode.png","wb")#而後把圖片放在一個指定的位置
13     img.save(f,"png")  #保存圖片
14     f.close()
15     with open("validcode.png","rb") as f:
16         data = f.read()
17     return HttpResponse(data)
18 方式三:
19  # 方式三:
20     # 方式二也不怎麼好,由於每次都要建立一個保存圖片的文件,咱們能夠不讓吧圖片保存到硬盤上,
21     # 在內存中保存,完了自動清除,那麼就引入了方式三:利用BytesIO模塊
22     from io import BytesIO
23     from PIL import Image
24     img = Image.new(mode="RGB",size=(120,40),color="blue")
25     f = BytesIO()  #內存文件句柄
26     img.save(f,"png")  #保存文件
27     data = f.getvalue()#打開文件(至關於python中的f.read())
28     return HttpResponse(data)
29 方式四:
30  # 方式四:一、添加畫筆,也就是在圖片上寫上一些文字
31     #         二、而且字體隨機,背景顏色隨機
32     from io import BytesIO
33     from PIL import Image,ImageDraw,ImageFont
34     import random
35     #隨機建立圖片
36     img = Image.new(mode="RGB",size=(120,40),color=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
37     draw = ImageDraw.Draw(img,"RGB")
38     # 畫干擾線
39     for i in range(5):
40         x1 = random.randint(0, 120)
41         y1 = random.randint(0, 40)
42         x2 = random.randint(0, 120)
43         y2 = random.randint(0, 40)
44         draw.line((x1, y1, x2, y2), fill=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
45     font = ImageFont.truetype("static/font/kumo.ttf",20)  #20表示20像素
46     str_list = []  #吧每次生成的驗證碼保存起來
47     # 隨機生成五個字符
48     for i in range(5):
49         random_num = str(random.randint(0, 9))  # 隨機數字
50         random_lower = chr(random.randint(65, 90))  # 隨機小寫字母
51         random_upper = chr(random.randint(97, 122))  # 隨機大寫字母
52         random_char = random.choice([random_num, random_lower, random_upper])
53         print(random_char,"random_char")
54         str_list.append(random_char)
55         # (5 + i * 24, 10)表示座標,字體的位置
56         draw.text((5+i*24,10),random_char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
57     print(str_list,"str_list")
58     f = BytesIO()#內存文件句柄
59     img.save(f,"png")   #img是一個對象
60     data = f.getvalue()  #讀取數據並返回至HTML
61     valid_str = "".join(str_list)
62     print(valid_str,"valid_str")
63     request.session["keep_valid_code"] = valid_str   #吧保存到列表的東西存放至session中
64     return HttpResponse(data)
四種方式

三、示例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>login</title>
 6     <link rel="stylesheet" href="/static/commons.css" />
 7 </head>
 8 <body>
 9 <div>
10     <div>用戶登陸</div>
11     <form>
12         <div>
13             <label>用戶名</label>
14             <input type="text" placeholder="請輸入用戶名" />
15         </div>
16         <div>
17             <label>密碼</label>
18             <input type="text" placeholder="請輸入密碼" />
19         </div>
20         <div>
21             <label>驗證碼</label>
22             <div>
23                 <input type="text" placeholder="輸入驗證碼" name="check_code">
24             </div>
25             <div>
26                 <img src="/app04/check_code.html" onclick="changeCheckCode(this);">
27             </div>
28         </div>
29     </form>
30 </div>
31 <script>
32     function changeCheckCode(ths) {
33 {#        能夠簡單實現驗證碼刷新#}
34         ths.src = ths.src + '?'
35     }
36 </script>
37 </body>
38 </html>
check_code.html
 1 def check_code(request):
 2     '''
 3     驗證碼
 4     :param request:
 5     :return:
 6     '''
 7     from io import BytesIO
 8     # 在內存建立文件
 9     stream = BytesIO()
10     # 調用自定義的check_code方法生成一個圖片和一個驗證碼字串,check_code寫法請參考驗證碼實例
11     img,code = create_validate_code()
12     # 將圖片寫入到內存中以圖片形式
13     img.save(stream,'PNG')
14     # 爲當前請求設置session
15     request.session['CheckCode'] = code
16     # stream.getvalue()是從內存中獲取圖片
17     return HttpResponse(stream.getvalue())
18 def login(request):
19     if request.method == 'POST':
20         if request.POST.get('check_code').upper() == request.session['CheckCode'].upper():
21             print('驗證碼正確')
22         else:
23             print('驗證碼錯誤')
24     return render(request,'app04/login.html')
views.py

四、滑動驗證碼

藉助插件來作

一、打開插件,找到本身須要的驗證碼

二、篩選有用的路徑

三、把對應的視圖函數也拿過來,注意還須要一個geetest.py的文件

 1 #滑動驗證碼
 2     url(r'^pc-geetest/register', pcgetcaptcha, name='pcgetcaptcha'),
 3     url(r'^pc-geetest/ajax_validate', pcajax_validate, name='pcajax_validate'),
 4 
 5 # ================
 6 from app01.geetest import GeetestLib
 7 pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
 8 pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"
 9 mobile_geetest_id = "7c25da6fe21944cfe507d2f9876775a9"
10 mobile_geetest_key = "f5883f4ee3bd4fa8caec67941de1b903"
11 # 滑動驗證碼
12 def pcgetcaptcha(request):
13     user_id = 'test'
14     gt = GeetestLib(pc_geetest_id, pc_geetest_key)
15     status = gt.pre_process(user_id)
16     request.session[gt.GT_STATUS_SESSION_KEY] = status
17     request.session["user_id"] = user_id
18     response_str = gt.get_response_str()
19     return HttpResponse(response_str)
20 # 滑動驗證碼
21 def pcajax_validate(request):
22 
23     if request.method == "POST":
24         # 驗證的驗證碼
25         ret = {"flag": False, "error_msg": None}
26         gt = GeetestLib(pc_geetest_id, pc_geetest_key)
27         challenge = request.POST.get(gt.FN_CHALLENGE, '')
28         validate = request.POST.get(gt.FN_VALIDATE, '')
29         seccode = request.POST.get(gt.FN_SECCODE, '')
30         status = request.session[gt.GT_STATUS_SESSION_KEY]
31         user_id = request.session["user_id"]
32         print("status",status)
33         if status:
34             result = gt.success_validate(challenge, validate, seccode, user_id)
35         else:
36             result = gt.failback_validate(challenge, validate, seccode)
37         if result:  #若是驗證驗證碼正確,就驗證用戶名是否正確
38             username = request.POST.get("username")
39             password = request.POST.get("password")
40 
41            # 驗證用戶名和密碼
42             user = auth.authenticate(username=username, password=password)
43             if user:
44                 # 若是驗證成功就讓登陸
45                 ret["flag"] = True
46                 auth.login(request, user)
47             else:
48                 ret["error_msg"] = "用戶名和密碼錯誤"
49         else:
50             ret["error_msg"] = "驗證碼錯誤"
51         return HttpResponse(json.dumps(ret))
52     else:
53         return render(request, "login.html")
views.py
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6     <meta name="viewport" content="width=device-width">
  7     <title>Title</title>
  8     <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
  9     <link rel="stylesheet" href="/static/css/login.css">
 10     <script src="/static/jquery-3.2.1.min.js"></script>
 11    滑動驗證碼的時候導入
 12     <script src="http://static.geetest.com/static/tools/gt.js"></script>
 13     <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
 14     <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
 15 
 16 </head>
 17 <body>
 18 <div class="container">
 19     <div class="row">
 20         <div class="col-md-1=10">
 21             <form class="form-horizontal" id="form_data" action="/login/" method="post">
 22                 {% csrf_token %}
 23                 <div class="form-group">
 24                     <label for="username" class="col-sm-2 control-label">用戶名</label>
 25                     <div class="col-sm-5">
 26                         <input type="text" class="form-control" id="username" placeholder="username" name="username">
 27                     </div>
 28                 </div>
 29                 <div class="form-group">
 30                     <label for="password" class="col-sm-2 control-label">密碼</label>
 31                     <div class="col-sm-5">
 32                         <input type="password" class="form-control" id="password" placeholder="password" name="password">
 33                     </div>
 34                 </div>
 35                 <div class="form-group">
 36                     <div class="row">
 37                         <div class="col-md-6 col-md-offset-1">
 38 {#                            文字部分#}
 39                             <label for="vialdCode" class="col-sm-2 control-label">驗證碼</label>
 40                              <div class="col-sm-5">
 41                                 <input type="text" class="form-control vialdCode_text" id="vialdCode" placeholder="驗證碼" name="vialdCode">
 42                             </div>
 43 {#                            圖片部分#}
 44                              <div class="col-md-5">
 45                             <img class="vialdCode_img" src="/get_vaildCode_img/" alt="" width="200px" height="100px">
 46 {#                                 <a href=""></a>     #}
 47                         </div>
 48                         </div>
 49 
 50                     </div>
 51                 </div>
 52                 <div class="form-group">
 53                     <div class="col-sm-offset-2 col-sm-10">
 54                         <div class="checkbox">
 55                             <label>
 56                                 <input type="checkbox"> 下次自動登陸
 57                             </label>
 58                         </div>
 59                     </div>
 60                 </div>
 61                 <div class="form-group">
 62                     <div class="col-sm-offset-2 col-sm-10">
 63                         <p>
 64                             <button type="button" class="btn btn-success login" id="submit">登陸</button>
 65                             <span class="error has-error"></span></p>
 66                         <p>
 67                             <button type="button" class="btn btn-primary register">註冊</button>
 68                         </p>
 69                     </div>
 70                     <div id="popup-captcha"></div>
 71                 </div>
 72             </form>
 73         </div>
 74     </div>
 75 </div>
 76 {#滑動驗證碼#}
 77 <script>
 78     var handlerPopup = function (captchaObj) {
 79         $("#submit").click(function () {
 80             captchaObj.show();
 81         });
 82         //定時函數
 83          $(".login").click(function () {
 84              function foo() {
 85                  $(".error").html("")
 86              }
 87 
 88              // 成功的回調
 89              captchaObj.onSuccess(function () {
 90                  var validate = captchaObj.getValidate();
 91                  $.ajax({
 92                      url: "/pc-geetest/ajax_validate", // 進行二次驗證
 93                      type: "post",
 94                      dataType: "json",
 95                      headers: {"X-CSRFToken": $.cookie('csrftoken')},
 96                      data: {
 97                          username: $('#username').val(),
 98                          password: $('#password').val(),
 99                          geetest_challenge: validate.geetest_challenge,
100                          geetest_validate: validate.geetest_validate,
101                          geetest_seccode: validate.geetest_seccode
102                      },
103                      success: function (data) {
104                          console.log(data);
105                          if (data["flag"]) {
106 {#                             alert(location.search);#}
107 {#                             alert(location.search.slice(6));#}
108 {#                             方式一#}
109 {#                             if (location.search.slice(6)) {#}
110                                  {#                            若是用戶沒有登陸點讚的時候,當用戶後來又登陸了,就直接讓跳轉到當前點讚的那個路徑#}
111 {#                                 location.href = location.search.slice(6)#}
112 {#                             }#}
113 {#                             else {#}
114 {#                                 window.location.href = '/index/'#}
115 {#                             }#}
116 {#                             方式二:#}
117                              alert($.cookie("next_path"));
118                              if ($.cookie("next_path")){
119                                  location.href = $.cookie("next_path")
120                              }
121                              else{
122                                  location.href = "/index/"
123                              }
124                          }
125                          else {
126                              $(".error").html(data["error_msg"]);
127                              setTimeout(foo, 3000)
128                          }
129                      }
130                  });
131              });
132 
133          });
134              // 將驗證碼加到id爲captcha的元素裏
135              captchaObj.appendTo("#popup-captcha");
136              // 更多接口參考:http://www.geetest.com/install/sections/idx-client-sdk.html
137          };
138     // 驗證開始須要向網站主後臺獲取id,challenge,success(是否啓用failback)
139     $.ajax({
140         url: "/pc-geetest/register?t=" + (new Date()).getTime(), // 加隨機數防止緩存
141         type: "get",
142         dataType: "json",
143         success: function (data) {
144             // 使用initGeetest接口
145             // 參數1:配置參數
146             // 參數2:回調,回調的第一個參數驗證碼對象,以後可使用它作appendTo之類的事件
147             initGeetest({
148                 gt: data.gt,
149                 challenge: data.challenge,
150                 product: "popup", // 產品形式,包括:float,embed,popup。注意只對PC版驗證碼有效
151                 offline: !data.success // 表示用戶後臺檢測極驗服務器是否宕機,通常不須要關注
152                 // 更多配置參數請參見:http://www.geetest.com/install/sections/idx-client-sdk.html#config
153             }, handlerPopup);
154         }
155     });
156 </script>
login.html

十9、KindEditor

一、官網:http://kindeditor.net/demo.php

二、下載:http://kindeditor.net/down.php

三、文件夾說明

asp:asp示例
asp.net:asp.net示例
attached:空文件夾,放置關聯文件attached
examples:HTML示例
jsp:java示例
kindeditor-all-min.js:所有JS(壓縮)
kindeditor-all.js:所有JS(未壓縮)
kindeditor-min.js:僅KindEditor JS(壓縮)
kindeditor.js:僅KindEditor JS(未壓縮)
lang:支持語言
license.txt:License
php:PHP示例
plugins:KindEditor內部使用的插件
themes:KindEditor主題

四、基本使用

 1 <textarea name="content" id="content"></textarea>
 2  
 3 <script src="/static/jquery-1.12.4.js"></script>
 4 <script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
 5 <script>
 6     $(function () {
 7         initKindEditor();
 8     });
 9  
10     function initKindEditor() {
11         var kind = KindEditor.create('#content', {
12             width: '100%',       // 文本框寬度(能夠百分比或像素)
13             height: '300px',     // 文本框高度(只能像素)
14             minWidth: 200,       // 最小寬度(數字)
15             minHeight: 400      // 最小高度(數字)
16         });
17     }
18 </script>
基本使用

詳細參數:http://kindeditor.net/docs/option.html

五、文件操做

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<div>
    <h1>文章內容</h1>
    {{ request.POST.content|safe }}
</div>


<form method="POST">
    <h1>請輸入內容:</h1>
    {% csrf_token %}
    <div style="width: 500px; margin: 0 auto;">
        <textarea name="content" id="content"></textarea>
    </div>
    <input type="submit" value="提交"/>
</form>

<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/plugins/kind-editor/kindeditor-all.js"></script>
<script>
    $(function () {
        initKindEditor();
    });

    function initKindEditor() {
        var a = 'kind';
        var kind = KindEditor.create('#content', {
            width: '100%',       // 文本框寬度(能夠百分比或像素)
            height: '300px',     // 文本框高度(只能像素)
            minWidth: 200,       // 最小寬度(數字)
            minHeight: 400,      // 最小高度(數字)
            uploadJson: '/kind/upload_img/',
            extraFileUploadParams: {
                'csrfmiddlewaretoken': '{{ csrf_token }}'
            },
            fileManagerJson: '/kind/file_manager/',
            allowPreviewEmoticons: true,
            allowImageUpload: true
        });
    }
</script>
</body>
</html>

HTML
HTML
 1 import os
 2 import json
 3 import time
 4 
 5 from django.shortcuts import render
 6 from django.shortcuts import HttpResponse
 7 
 8 
 9 def index(request):
10     """
11     首頁
12     :param request:
13     :return:
14     """
15     return render(request, 'index.html')
16 
17 
18 def upload_img(request):
19     """
20     文件上傳
21     :param request:
22     :return:
23     """
24     dic = {
25         'error': 0,
26         'url': '/static/imgs/20130809170025.png',
27         'message': '錯誤了...'
28     }
29 
30     return HttpResponse(json.dumps(dic))
31 
32 
33 def file_manager(request):
34     """
35     文件管理
36     :param request:
37     :return:
38     """
39     dic = {}
40     root_path = '/Users/wupeiqi/PycharmProjects/editors/static/'
41     static_root_path = '/static/'
42     request_path = request.GET.get('path')
43     if request_path:
44         abs_current_dir_path = os.path.join(root_path, request_path)
45         move_up_dir_path = os.path.dirname(request_path.rstrip('/'))
46         dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path
47 
48     else:
49         abs_current_dir_path = root_path
50         dic['moveup_dir_path'] = ''
51 
52     dic['current_dir_path'] = request_path
53     dic['current_url'] = os.path.join(static_root_path, request_path)
54 
55     file_list = []
56     for item in os.listdir(abs_current_dir_path):
57         abs_item_path = os.path.join(abs_current_dir_path, item)
58         a, exts = os.path.splitext(item)
59         is_dir = os.path.isdir(abs_item_path)
60         if is_dir:
61             temp = {
62                 'is_dir': True,
63                 'has_file': True,
64                 'filesize': 0,
65                 'dir_path': '',
66                 'is_photo': False,
67                 'filetype': '',
68                 'filename': item,
69                 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
70             }
71         else:
72             temp = {
73                 'is_dir': False,
74                 'has_file': False,
75                 'filesize': os.stat(abs_item_path).st_size,
76                 'dir_path': '',
77                 'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False,
78                 'filetype': exts.lower().strip('.'),
79                 'filename': item,
80                 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
81             }
82 
83         file_list.append(temp)
84     dic['file_list'] = file_list
85     return HttpResponse(json.dumps(dic))
86 
87 View
views.py

六、XSS過濾特殊標籤

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from bs4 import BeautifulSoup
 4 
 5 
 6 class XSSFilter(object):
 7     __instance = None
 8 
 9     def __init__(self):
10         # XSS白名單
11         self.valid_tags = {
12             "font": ['color', 'size', 'face', 'style'],
13             'b': [],
14             'div': [],
15             "span": [],
16             "table": [
17                 'border', 'cellspacing', 'cellpadding'
18             ],
19             'th': [
20                 'colspan', 'rowspan'
21             ],
22             'td': [
23                 'colspan', 'rowspan'
24             ],
25             "a": ['href', 'target', 'name'],
26             "img": ['src', 'alt', 'title'],
27             'p': [
28                 'align'
29             ],
30             "pre": ['class'],
31             "hr": ['class'],
32             'strong': []
33         }
34 
35     @classmethod
36     def instance(cls):
37         if not cls.__instance:
38             obj = cls()
39             cls.__instance = obj
40         return cls.__instance
41 
42     def process(self, content):
43         soup = BeautifulSoup(content, 'lxml')
44         # 遍歷全部HTML標籤
45         for tag in soup.find_all(recursive=True):
46             # 判斷標籤名是否在白名單中
47             if tag.name not in self.valid_tags:
48                 tag.hidden = True
49                 if tag.name not in ['html', 'body']:
50                     tag.hidden = True
51                     tag.clear()
52                 continue
53             # 當前標籤的全部屬性白名單
54             attr_rules = self.valid_tags[tag.name]
55             keys = list(tag.attrs.keys())
56             for key in keys:
57                 if key not in attr_rules:
58                     del tag[key]
59 
60         return soup.renderContents()
61 
62 
63 if __name__ == '__main__':
64     html = """<p class="title">
65                         <b>The Dormouse's story</b>
66                     </p>
67                     <p class="story">
68                         <div name='root'>
69                             Once upon a time there were three little sisters; and their names were
70                             <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
71                             <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
72                             <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
73                             and they lived at the bottom of a well.
74                             <script>alert(123)</script>
75                         </div>
76                     </p>
77                     <p class="story">...</p>"""
78 
79     v = XSSFilter.instance().process(html)
80     print(v)
xss示例
 1 #基於__new__實現單例模式示例
 2 from bs4 import BeautifulSoup
 3 
 4 
 5 class XSSFilter(object):
 6     __instance = None
 7 
 8     def __init__(self):
 9         # XSS白名單
10         self.valid_tags = {
11             "font": ['color', 'size', 'face', 'style'],
12             'b': [],
13             'div': [],
14             "span": [],
15             "table": [
16                 'border', 'cellspacing', 'cellpadding'
17             ],
18             'th': [
19                 'colspan', 'rowspan'
20             ],
21             'td': [
22                 'colspan', 'rowspan'
23             ],
24             "a": ['href', 'target', 'name'],
25             "
相關文章
相關標籤/搜索