Python 14:Django

2019年11月11日 阅读数:151
这篇文章主要向大家介绍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