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跨域請求
一、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()
上述經過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()
二、自定義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()
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()
在上一步驟中,對於全部的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')]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>INDEX @uuu</h1> </body> </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()
三、web框架
MVC
Model View Controller
數據庫 模板文件 業務處理
MTV
Model Template View
數據庫 模板文件 業務處理
一、建立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>')
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 ]
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')
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>
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})
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>
子板
{#繼承那個模板#} {% 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 %}
三、模板導入
模版
<form> <input type="text"/> <input type="submit"/> </form>
導入模板
{#繼承那個模板#} {% 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 %}
四、自定義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
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', ]
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>
五、自定義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
使用filter:
{{ '參數1'|函數名:'參數2' }}
filter主要用在if...else判斷裏,用於if條件
一、獲取用戶請求數據
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>
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')
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 ]
四、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 ]
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')
====》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 ]
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')
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>
====》建議:二者都用
五、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})
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})
一、單一路由對應
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 ]
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 ]
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 ]
五、添加額外參數
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')), ]
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/', views.index, name='index') ]
from django.conf.urls import url from app02 import views urlpatterns = [ url(r'^index/', views.index, name='index') ]
from django.shortcuts import render,HttpResponse from django.urls import reverse def index(request): print('app01') return HttpResponse(reverse('index'))
from django.shortcuts import render,HttpResponse from django.urls import reverse def index(request): print('app02') return HttpResponse(reverse('index'))
顯示結果:
#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')), ]
from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^index/', views.index, name='index') ]
from django.conf.urls import url from app02 import views app_name = 'app02' urlpatterns = [ url(r'^index/', views.index, name='index') ]
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'))
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'))
頁面顯示結果:
http://127.0.0.1:8000/a/index/:/a/index/
http://127.0.0.1:8000/b/index/:/b/index/
一、自定義分頁
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})
<!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>
二、生成公共模塊:
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})
一、基本操做
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)
註冊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 ]
執行命令:
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()
二、其餘操做
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')
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 ]
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/')
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>
用戶登陸成功跳轉用戶管理界面,基於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 ]
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})
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>
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>
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>
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>
三、建立數據庫表
# 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就能夠了
跨表操做
外鍵:
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})
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>
五、獲取表單的三種方式
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})
<!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>
六、多對多
建立
方式一:自定義關係表
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 #
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))
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>
一、概述
對於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對象的主要屬性:
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...
示例:
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>
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))
1 url(r'^ajax/$',views.ajax), 2 url(r'^ajax_json/$',views.ajax_json),
跨瀏覽器支持:
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回調函數
這些方法所有是調用上面的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))
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>
四、「僞」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>
使用順序:若是發送的是普通數據,使用順序優先級:jquery,XMLHttpRequest,iframe
一、文件上傳的三種方式
<!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>
二、後端
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))
使用順序:若是發送的是文件,使用順序優先級:iframe,jquery(FormData),XMLHttpRequest(FormData)
一、建立數據庫表
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就能夠了
多表關係參數:
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')
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')
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類型(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')
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'"))
一、功能
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})
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>
三、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 '''
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')
1 def index2(request): 2 from app01.forms import UserInfoForm 3 obj = UserInfoForm() 4 return render(request,'indexform.html',{'obj':obj})
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>
四、數據驗證
經歷三個階段:
- 每個字段(正則,字段鉤子)
- 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
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
五、初始化數據
在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>
在使用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
四、其餘功能
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={...})
五、示例:用戶管理
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
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 ]
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')
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>
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>
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>
一、獲取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 '''
二、設置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獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋) '''
三、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})
<!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>
一、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失效策略。
在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設置文件中設置引擎:
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
二、用戶登錄驗證示例
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/')
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 ]
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>
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>
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>
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>
在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
三、註冊中間件
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 ]
因爲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 %}
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 # 建立數據庫鏈接時,自動觸發
二、信號的使用:
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!")
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)
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>
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')
四、滑動驗證碼
藉助插件來作
一、打開插件,找到本身須要的驗證碼
二、篩選有用的路徑
三、把對應的視圖函數也拿過來,注意還須要一個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")
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>
一、官網: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
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
六、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)
1 #基於__new__實現單例模式示例 2 from bs4 import BeautifulSoup 3 4 5 class XSSFilter(object): 6 __instance = None 7 8 def __init__(self): 9 # XSS白名單 10 self.valid_tags = { 11 "font": ['color', 'size', 'face', 'style'], 12 'b': [], 13 'div': [], 14 "span": [], 15 "table": [ 16 'border', 'cellspacing', 'cellpadding' 17 ], 18 'th': [ 19 'colspan', 'rowspan' 20 ], 21 'td': [ 22 'colspan', 'rowspan' 23 ], 24 "a": ['href', 'target', 'name'], 25 "