Django、Torando、Flask、Bottlejavascript
model(模型、數據庫)、views(html模版)、controllers(業務邏輯處理) --> MVCcss
model(模型、數據庫)、templates(html模版)、view(業務邏輯處理) --> MTVhtml
- User表的增,刪,改,查
- 登陸 - 首頁 …
- web端 - 客戶端
/Projname __init__.py settings.py # 用戶級的配置文件 urls.py # 路由配置,爲用戶輸入的url匹配對應的視圖函數 /app01 # app文件 /migration/ # 數據遷移記錄 __init__.py admin.py # Django自帶的後臺管理功能 apps.py # app註冊配置文件 models.py # 模型 test.py # 單元測試 view.py # 業務處理,循環函數 # 可將view變換成目錄,並分塊 /templates # 模板目錄(html) /static # 靜態文件目錄(自定) manage.py # 程序啓動文件 # 如下可選 /repository # 可將主程序的Models提取到此處 /api # 專門的api處理 /backend # 用於用戶的後臺管理
sudo pip3 install django # 或 pip3 install django==2.0.1 # 指定版本
django-admin startproject projectname
cd projectname
python manage.py runserver 127.0.0.1:8080
——在settings.py
文件下操做前端
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] # 此處爲設置模版搜索路徑 # 'templates'名稱要與模版文件所在的目錄一致 , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
STATIC_URL = '/static/' # 路徑前綴,程序將在根目錄的此路徑下搜索靜態文件 STATICFILES_DIRS =( # 新增此變量配置 os.path.join(BASE_DIR, 'static'), # 必定要加逗號,'static'與 STATIC_URL保持一致 )
模板文件便可使用該目錄下的靜態文件java
<link rel="stylesheet" href="/static/css-filename.css">
cd到項目目錄下python
python3 manage.py startapp app01 # 可有多個,用於主站、後臺管理、運維平臺等等
在建立Project的時候輸入app名mysql
——適用於非瀏覽器的的客戶端jquery
django.conf import global_settings # 默認配置文件 django.conf import settings # 用戶配置文件
在客戶端的start.py文件下git
import os os.environ['USER_SETTINGS'] = "config.settings" # 執行時自動將用戶配置文件設爲環境變量 # config.py文件下 import os from . import global_settings class Settings(object): def __init__(self): # 找到默認配置,先導入,若有重複以用戶爲準 for name in dir(global_settings): if name.isupper(): value = getattr(global_settings, name) setattr(self, name, value) # 找到用戶自定義配置 settings_module = os.environ['USER_SETTINGS'] if not settings_module: return m = importlib.import_module(settings_module) for name in dir(m): if name.isupper(): value = getattr(m, name) setattr(self, name, value)
小技巧:web
#測試模式配置 DEBUG=True # 函數中 DEBUG = settings.DEBUG if DEBUG: # 啓動測試模式專用程序
# except顯示錯誤堆棧信息 try: ... except Exception: print(traceback.format_exc())
在啓動文件中輸入如下代碼,達到相似manage.py啓動的效果
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "項目名.settings") # 設置環境變量 import django django.setup() # 手動註冊django全部的app
urls.py
新建url模式指向視圖函數。view.py
建立建立視圖函數返回模板。指的是使用函數來做爲業務邏輯處理的方式,CBV是指url對應類;FBV指url對應函數,FBV更爲靈活。
urlpatterns = [ url(r'^index/', index), # FBV:url對應函數 ]
urls.py
urlpatterns = [ url(r'^login/', view.Login.as_view()), # CBV:url對應類,自動處理GET和POST等請求 ]
view.py
from django.shortcuts import View # 經過反射做用實現 class Login(View): # 繼承View類 def get(self, request): # 定義get請求時的函數 return render(request, 'login.html') def post(self, request): return render(request, 'login.html')
URL定位資源,用HTTP動詞(GET,POST,DELETE,DETC)描述操做。
GET查找、POST建立、PUT更新、DELETE刪除
其他PATCH、HEAD、OPTIONS、TRACE
面向資源編程:把網絡上的任何東西看成資源
1.method:方法 # GET # POST # PUT # DELETE 2.狀態碼 # 200 # 404 # 500 # 403 3.url必須是名詞
參考資料: http://www.ruanyifeng.com/blog/2014/05/restful_api.html
class Login(View): def get(self, request): # 定義get請求時的函數 return render(request, 'login.html') def post(self, request): return render(request, 'login.html') def dispatch(self, request, *args, **kwargs): obj = super(Login, self).dispatch(request, *args, **kwargs) # 調用View中的dispatch 方法再進行改寫 ''' 可在此加入改寫代碼 ''' return obj
- 保存在瀏覽器上的鍵值對
- 服務端能夠向用戶瀏覽器端寫cookie
- 客戶端每次發請求時會攜帶cookie去
應用於投票、登陸等
def login(request) obj = HttpResponse('OK') # 設置cookie超時 # 方式1 設置時間(推薦) obj.set_cookie( 'key', # 第一個參數爲key value='value', # 第二個參數爲value max_age=100 # 超時時間爲100秒 ) # 方式2 設置日期 import datetime from datetime import timedelta ct = datetime.datetime.utcnow() v = timedelta(seconds=10) # 計算10秒之後的日期 value = ct + v obj.set_cookie( 'key', value='value', expires=value # 設置最長超時日期 ) return obj # 其餘設置:url、域名等 obj.set_cookie( 'key', value='value', path='/url/' # 設置可用的url domain=None, # 設置可用域名,默認爲當前域名 secure=False, # 證書:爲https提供的功能,使用https須要改爲True httponly=False # 只能經過http請求中進行傳輸,js代碼沒法獲取 )
HttpResponse、render、redirect都可使用
request.COOKIES request.get_signed_cookie('k1', salt='jjjj')
tk = obj.set_signed_cookie('ticket','123123sda',salt='jjjj')
from django.core.signing import TimestampSigner class Mysigner(TimestampSigner): def sign(self, value): # 此處可自行加密 return value + '12345678' def unsign(self, value, max_age=None): print(value) return value[0:-8]
settings.py
文件中將配置改爲SIGNING_BACKEND = "c1.MySigner"
用戶登陸狀態的cookie應用——使用裝飾器對函數進行修改
cookie是保存在客戶端瀏覽器上的鍵值對
Session即保存在服務器端的數據(本質是鍵值對)
應用:依賴cookie
做用:保持會話(web網站)
def login(request): if request.method == 'GET': return render(request, 'login.html') else: u = request.POST.get('user') p = request.POST.get('pwd') obj = models.UserAdmin.objects.filter(username=u, password=p).first() if obj: # 1.生成隨機字符串 # 2.經過cookie發送給客戶端 # 3.服務端保存(django_session表裏面) # { # 隨機字符串1:{'username': 'alex', 'email': '11',...} # } request.session['username'] = obj.username return redirect('/index/') else: return render(request, 'login.html', {'msg': "用戶名或密碼錯誤"}) def index(request): # 1.獲取客戶端cookie中的隨機字符串 # 2.去session中查找有沒有隨機字符串 # 3.去session對應的key的value中查看是否有username v = request.session.get('username') if v: return HttpResponse("登陸成功") else: return redirect('/login/')
def index(request): # 獲取、設置、刪除Session中數據 request.session['k1'] request.session.get('k1',None) # 沒有k1,則建立默認給None request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在則不設置 del request.session['k1'] # 刪除值,不刪除對 # 全部 鍵、值、鍵值對 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() # 以迭代器的方式,一個一個取 request.session.itervalues() request.session.iteritems() # 用戶session的隨機字符串 request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查 用戶session的隨機字符串 在數據庫中是否 request.session.exists("session_key") # 刪除當前用戶的全部Session數據 request.session.delete("session_key") request.session.set_expiry(value) #* 若是value是個整數,session會在些秒數後失效。 #* 若是value是個datatime或timedelta,session就會在這個時間後失效。 #* 若是value是0,用戶關閉瀏覽器session就會失效。 #* 若是value是None,session會依賴全局session失效策略。
Django本來已有一套默認配置,如需自定義,須在settings.py
下增長如下變量
# 數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) # 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 使用文件保存 SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 緩存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 將session數據放到另一臺機子的服務器內存上。 SESSION_CASHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 # 需配合Django緩存配置 # 緩存+數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 數據庫用於作持久化,緩存用於提升效率 # 存於cookie中 SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認)
——編輯url並定義處理函數
主目錄urls.py
文件下
urlpatterns = [ # url(r'^admin/', admin.site.urls), # 在此列表新增url,把admin替換成url後綴 url(r'^login/', view.login), # 例:替換成r'^login/'和login函數 # 終止符 url(r'^index/', view.index), # r'^index/'爲正則表達式,以^開頭,$或/表示結束 url(r'^index/(\d+)/', view.index), # 使用正則表達式來匹配url,匹配出的組做爲參數傳到views # FBV接收 --> def index(request,a1) # 位置參數式 url( r'^index/(\w+)/(\w+)', # 兩個及以上正則表達式 # FBV接收 --> def index(request,a1,a2) 按順序接收 view.index ), # 指定參數式 url( r'^index/(?P<a1>\w+)/(?P<a2>\w+)', # 兩個及以上正則表達式 # FBV接收 --> def index(request,a1,a2) 指定參數名稱爲a1,a2,並接收 view.index ), # 混合式 沒有混合式,必須統一,要麼位置參數。 ]
正則補充:
\w
匹配字母或數字或下劃線或漢字 等價於'\[^A-Za-z0-9_]\'
。
靜態的好處是速度快(搜索引擎更偏心)
動態由於要到數據庫查找數據因此慢
僞靜態是爲了作SEO,讓搜索引擎以爲你是個靜態網站
url(r'^index/(\w+).html$',index), # 加上.html結尾,假裝爲靜態網站
127.0.0.1/app01/index.html
url(r'^app01/',include('app01.urls')), # 將url分發到app01執行
url(r'^index.html',view.index), # 在app01下匹配index函數
url(r'^',view.index), # 將錯誤的url給到首頁
# 位置參數版 url(r'^index.html/(\d+)/',view.index, name='n1'), # 爲url命名 # 命名參數版 url(r'^index.html/(?P<a1>\d+)/',view.index, name='n2'), # 爲url命名
import reverse # 位置參數版 v = reverse('n1', args=(1,)) # args爲返回url:'/index/a' 中的a # 命名參數版 v = reverse('n2', kwargs={'a1: 111'}) # a1爲命名參數指定名稱的參數
<form method='POST' action='{% url "n1" %}' /> // 模版特殊標記經過名稱反生成url 數據替換結果爲 <form method='POST' action='/index/1/' /> // 模版特殊標記經過名稱反生成url 可在標記中加入參數 <ul> {% for i in user_list %} <li> {{ i }} | <a herf="/edit/{{ i }}/">編輯</a></li> // 下面語句與上面效果同樣 <li> {{ i }} | <a herf="{% url 'n1' i %}">編輯</a></li> {% endfor %} </ul>
權限管理中,保存別名,而後反生成菜單的url做爲action的值
注:別的框架不支持別名
views.py
部分
import HttpResponse,render def login(request): # 定義處理url的函數 return HttpResponse('<input type="text" />') # 利用HttpResponse返回字符串 def index(request): return render(request,"index.html") #直接讀取html文件,讀取內容並返回字符串 # 注:請提早作好模版文件路徑配置
render(request, 模版路徑, dict)
HttpResponse(request, str(or dict))
redirect("網址(or 新url)")
urls.py
部分
urlpatterns = [ # url(r'^admin/', admin.site.urls), # 在此列表新增url,把admin替換成url後綴 url(r'^login/', views.login), # 例:替換成r'^login/'和login函數 url(r'^index/', views.index), ]
用get()、getlist()(用於多選下拉框)方法能夠拿到用戶請求的相關信息
GET —— 只有request.GET有值
POST——二者都有值
method——請求的方法
FILES——請求中附帶的文件
更多方法:https://www.cnblogs.com/scolia/archive/2016/07/01/5633351.html
模版html文件下
<form method="post" action="/login/"> {# method做爲提交的方法,value做爲提交的值 #} <input type="text" name="username"> {# name做爲提交的鍵,value做爲提交的值 #} <input type="password" name="password"> <input type="submit" value="登陸"> {{ msg }} {# 特殊字符 放提示語的地方 #} </form>
views.py
下
def login(request): if request.method == 'get': return render(request, 'login.html') # 判斷客戶端使用的方法及對其進行處理 else: # request.GET或request.POST 儲存用戶發過來的值 u = request.POST.get('user') # 用戶POST提交的username u = request.POST.get('pwd') # 用戶POST提交的password if u == 'root' and p == '123': return redirect('http://www.xxx.com') else: # 用戶名密碼錯誤時,動態顯示 提示信息 return render(request, 'login.html', {'msg':'用戶名或密碼錯誤'})
特殊標記返回值不必定是字符串,能夠爲列表或字典
return render( request, 'index.html', { 'name': "alex", 'users': ['李志', '李傑'], 'user_dict':{'k1': 'v1', 'k2': 'v2'}, 'user_list_dict':[ {'id':1, 'name':'alex', 'email': 'alex3714@163.com'}, {'id':2, 'name':'alex2', 'email': 'alex23714@163.com'}, {'id':3, 'name':'alex3', 'email': 'alex33714@163.com'}, ] } )
<p>{{ name }}</p> <p>{{ users.0 }}</p> # 獲取列表中第一個元素 <p>{{ users.1 }}</p> <p>{{ user_dict.k1 }}</p> # 獲取字典中key爲k1的value值 <p>{{ user_dict.k2 }}</p>
<ul> {% for item in users %} # 循環開始 <li>{{ item }}</li> {% end for %} # 循環結束 </ul> <table> {% for row in users %} # 循環開始 <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> <td>{{ row.email }}</td> <td> <a>編輯</a><a herf="/del"={{ row.id }}></a> </td> </tr> {% end for %} </table> {# 字典循環 #} {% for k, v in userinfo.items %} <h6>{{ k }}-{{ v }}</h6> {% endfor %}
母版:存放全部頁面公用部分
子版:繼承母版公用部分及定製私有部分
{% extends 'layout.html' %} {# 表示繼承母版 #} {% block html %} {# 母版中應有此block html標記 #} <div>...</div> {# 在母版中有此block標記的地方插入如下代碼 #} {% endblock %} {# block的其餘用途 #} {% block css %} <style></style> {# 導入本身專用的css #} {% endblock %} {% block js %} <script></script> {# 導入本身專用的js #} {% endblock %}
建立小組件如pub.html
{# 注意:刪除其餘標籤,只剩下組件部分 #} <div> <h3>特別漂亮的小組件</h3> <div class="title">標題:{{ name }}</div> <div class="content">內容:{{ name }}</div> </div>
程序會先導入全部組件、母版後再開始渲染,所以組件內的特殊標記也會被渲染成功
在須要用到小組件的地方導入
{% include "pub.html"%}
simple_tag是指下方的upper
這種有函數做用的標籤
{{ name|upper }}
建立simple_tag有如下步驟:
a、在app中建立templatetags模塊
b、建立任意 .py 文件,如:xx.py
from django import template from django.utils.safestring import mark_safe register = template.Library() @register.filter def my_upper(value, args) # fillter 最多隻能傳2個參數,可傳入列表後逐個提取 return value.upper() + args @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
c、在使用自定義simple_tag的html文件中導入以前建立的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% name|my_upper:"1,2,3" %} {# @register.filter可做爲條件語句進行判斷使用。注意冒號後不可有空格 #} {% if name|my_bool %} <h3>真</h3> {% else %} <h3>假</h3> {% endif %} {% my_simple_time 1 2 3 %} {# @register.simple_tag不可用於條件語句 #} {% my_input 'id_username' 'hide' %}
e、在settings中配置當前app,否則django沒法找到自定義的simple_tag
Ajax是前端與後臺數據交互的技術,即偷偷地向後臺發請求,可用於模態對話框(自制的彈框)。
另一種相似的方式是'新url',就是跳轉到新的url,返回新的頁面 ,用於處理較大量的數據。
使用form表單提交,頁面會刷新,Ajax提交不刷新
$.ajax({ url: '要提交的地址', type: 'post', // GET或POST,提交方式 data: {'k1': 'v1', 'k2': 'v2'}, // 提交的數據的值,支持列表,不支持字典,只能經過序列化 traditional: true, // 若是提交的數據的值有列表則須要添加此屬性 dataType: 'JSON' // 返回的數據反序列化 success: function (data) { // 當前服務端處理完畢後,自動執行的回調函數 // data爲返回的數據 location.herf = 'www.baidu.com' } })
function add2(){ var xhr = new XMLHttpRequest(); var onreadystatechange = function(){ if (xhr.readyState == 4) // 判斷準備狀態是否在已經得到相應 alert(xhr.responseText); // 響應的結果數據 }; // GET請求 xhr.open('GET', '/add2/?i1=12&i2=19') // 註明請求方法及須要打開的url xhr.send(); // 發送請求 // POST請求 xhr.open('POST', '/add2/'); // 使用POST方法,將數據值藏在請求體內 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); # 設置請求頭告知處理請求體 xhr.send('i1=12&i2=19'); }
def add2(): if request.method == "GET": i1 = int(request.GET.get('i1')) i2 = int(request.GET.get('i2')) return HttpResponse(i1 + i2)
a. void open(String method,String url,Boolen async) 用於建立請求 參數: method: 請求方式(字符串類型),如:POST、GET、DELETE... url: 要請求的地址(字符串類型) async: 是否異步(布爾類型) b. void send(String body) 用於發送請求 參數: body: 要發送的數據(字符串類型) c. void setRequestHeader(String header,String value) 用於設置請求頭 參數: header: 請求頭的key(字符串類型) vlaue: 請求頭的value(字符串類型) d. String getAllResponseHeaders() 獲取全部響應頭 返回值: 響應頭數據(字符串類型) e. String getResponseHeader(String header) 獲取響應頭中指定header的值 參數: header: 響應頭的key(字符串類型) 返回值: 響應頭中指定的header對應的值 f. void abort() 終止請求
a. Number readyState 狀態值(整數) 詳細: 0-未初始化,還沒有調用open()方法; 1-啓動,調用了open()方法,未調用send()方法; 2-發送,已經調用了send()方法,未接收到響應; 3-接收,已經接收到部分響應數據; 4-完成,已經接收到所有響應數據; b. Function onreadystatechange 當readyState的值改變時自動觸發執行其對應的函數(回調函數) c. String responseText 服務器返回的數據(字符串類型) d. XmlDocument responseXML 服務器返回的數據(Xml對象) e. Number states 狀態碼(整數),如:200、404... f. String statesText 狀態文本(字符串),如:OK、NotFound...
$.ajax({ ... })
<form method="POST" action="/fake_ajax/" target="ifr"> <iframe name="ifr" id='ifr' style='display: none'></iframe> <input type="text" name="user" /> <a onclick="submitForm();">提交</a> # 綁定提交表格的函數 </form> <script> function submitForm(){ document.getElementById('ifr').onload = loadIframe; # 提交表格時執行loadIframe函數 document.getElementById('f1').submit(); } function loadIframe(){ var content = document.getElementById('f1').contentWindow.document.body.innerText; alert(content); } </script>
def fake_ajax(request): if request.method == 'GET': return render(request, 'fake_ajax.html') else: print(request.POST) return HttpResponse("返回值")
<h1>原生Ajax上傳文件</h1> <input type='file' id='i1'/> <a onclick="upload1()" id='i1'>上傳</a> <div id='container1'></div> {# 預覽功能 #} <h1>jQuery.Ajax上傳文件</h1> <input type='file' id='i2'/> <a onclick="upload2()" id='i2'>上傳</a> <div id='container2'></div> <h1>僞Ajax上傳文件</h1> <form method="POST" action="/upload/" target="ifr" enctype="mutipart/form-data"> <iframe name="ifr" id='ifr' style='display: none'></iframe> <input type="file" name="fafafa" /> <a onclick="upload3();">上傳</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1(){ // 原生Ajax上傳文件 var formData = new FormData(); # 重要,添加文件的重要載體 formData.append('fafafa', document.getElementById('i1'.files[0])); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ var file_path = xhr.responseText; var tag = document.createElement('img'); tag.src = '/' + file_path; document.getElementById('container1').appendChild(tag); // 將上傳的圖片即時展示 } } xhr.open('POST', '/upload/'); xhr.send(formdata); # 非字符串,無需再發送請求頭 function upload2(){ // jQuery.Ajax上傳文件 var formData = new FormData(); formData.append('fafafa', $('i2')[0].files[0])); // jQuery 轉換 $.ajax({ url: '/upload/', tyoe: 'POST', data: formData, contentType:false, // 告知jQuery不用處理數據(設置請求頭) processData:false, // 告知jQuery不用處理數據(設置請求頭) success: function(arg){ var tag = document.createElement('img'); tag.src = '/' + arg; $('container2').append(tag); // 將上傳的圖片即時展示 } }) } function upload3(){ // 僞Ajax上傳文件 document.getElementById('ifr').onload = loadIframe; # 提交表格時執行loadIframe函數 document.getElementById('f1').submit(); } function loadIframe(){ var content = document.getElementById('f1').contentWindow.document.body.innerText; var tag = document.createElement('img'); tag.src = '/' + content; document.getElementById('container3').appendChild(tag); // 將上傳的圖片即時展示 } </script>
$('#i2') --> $('#i2')[0] // jQuery轉DOM document.getElementById('i1') --> $(document.getElementById('i1')) // DOM轉jQuery
def upload(request): if request.method == 'GET': return render(request, 'upload.html') else: print(request.POST, request.FILES) file_obj = request.FILES.get("fafafa") file_path = os.path.join("static", file_obj.name) with open(file_path, 'wb') as f: for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse(file_path)
跨域Ajax:JASONP技術是一種解決跨域問題的方式
問題描述:瀏覽器的同源策略不支持跨域發送Ajax請求(Ajax發送跨域請求時,再回來時瀏覽器拒絕接受)
突破口1:script標籤沒有被禁止跨域。
侷限性:只能用GET請求,服務端和前端必須約定好
<a onclick="getUsers();">發送</a> <ul id='usernames'></ul> <script> function getUsers(){ var tag = document.createElement('script'); // tag.src = "http://www.jxntv.cn/data/jmd-jxtv2/html?callback=list&_1454376870403" tag.src = "http://www.s4.com:8001/users/?callback=bbb" document.head.appendChild(tag); } function bbb(arg){ for (var i=0, i<arg.length, i++){ var tag_li = document.createElement('li'); tag_li.innerText = arg[i]; document.getElementByID("usernames").appendChild(tag_li) } } </script> // jQuery版 <script> function getUsers(){ $.ajax( url: 'http://www.s4.com:8001/user/', // url將拼接爲'http://www.s4.com:8001/user/?callback=bbb' type: 'GET', dataType: 'JSONP', jsonp: 'callback', jsonpCallback: 'bbb' ) } function bbb(arg){ for (var i=0, i<arg.length, i++){ var tag_li = document.createElement('li'); tag_li.innerText = arg[i]; document.getElementByID("usernames").appendChild(tag_li) } } </script>
視圖函數部分
def users(request): v = request.GET.get('callback') user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) temp = "%s(%s)" % (v, user_list_str,) return HttpResponse(temp)
127.0.0.1 www.s4.com
到settings.py
加入如下配置便可使用新加入的域名
ALLOWED_HOSTS = ['http://www.s4.com',]
突破口2:CORS跨站資源共享。修改視圖函數配置,修改響應頭。
侷限性:但須要服務器方開放共享資源。
def new_users(request): user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) obj = HttpResponse(user_list_str) obj['Access-Control-Allow-Origin'] = 'http://www.s5.com:8000' # 加入容許訪問的域名 obj['Access-Control-Allow-Origin'] = '*' # 即全部人都可訪問 return obj
簡單請求(僅發送一次請求):HEAD
、GET
、POST
複雜請求(發送兩次請求,一次爲預檢請求):OPTIONS
def new_users(request): if request.method == "OPTIONS": print('預檢...') obj = HttpResponse() obj['Access-Control-Allow-Origin'] = "*" obj['Access-Control-Request-Methods'] = 'DELETE' return obj user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) obj = HttpResponse(user_list_str) obj['Access-Control-Allow-Origin'] = '*' # 即全部人都可訪問 return obj
其餘突破口:經過服務端發送請求再返回給瀏覽器
參考資料:
http://www.cnblogs.com/wupeiqi/articles/5703697.html
ajax用POST方法傳字典時收不到數據
在ajax中加入參數: contentType:"application/x-www-form-urlencoded",
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/6216618.html
Django默認使用sqlite,所以要修改爲mysql
settings.py
修改DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改成mysql 'NAME': 'DjangoTEST', # 修改數據庫名 'USER': 'root', 'PASSWORD':'123', 'HOST': '127.0.0.1', 'PORT': 3306 } }
__init__.py
文件下加入import pymysql pymysql.install_as_MySQLdb()
settings.py
下注冊appINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', # here ]
python3 manage.py migrate # 將上述APP的數據導入到數據庫
settings.py
下default爲默認connection,可加入多個數據庫
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改成mysql 'NAME': 'djangodb', # 修改數據庫名 'USER': 'root', 'PASSWORD':'123', 'HOST': '127.0.0.1', 'PORT': 3306 } 'db2': { 'ENGINE': 'django.db.backends.sqlite3', # 增長一個sqlite 'NAME': 'djangodb2', # 修改數據庫名 } }
from django.db import connection, connections cursor = connection.cursor() # connection=default數據 cursor = connections['db2'].cursor() cursor.execute("select * ……") cursor與pymysql用法一致
import pymysql class SqlHelper: def __init__(self): self.connect() def connect(self, sql, args) self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='mysite',charset='utf-8') self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def modify(self, sql, args): self.cursor.execute(sql, args) self.conn.commit() def multiple_modify(self, sql) self.cursor.executemany(sql, args) self.conn.commit() def getlist(self, sql, args): self.cursor.execute(sql, args) result = self.cursor.fetchall() self.conn.commit() return result def getone(self, sql, args): self.cursor.execute(sql, args) result = self.cursor.fetchone() self.conn.commit() return result def create(self, sql, args): self.cursor.execute(sql, args) self.conn.commit() return self.cursor.lastrowid def close(self): self.cursor.close() self.conn.close()
到model.py
文件下建立表
class UserInfo(models.Model): nid = models.BigAutoField(primary_key=True) # 自增字段 能夠不寫,Django會自動生成id = models.AutoField() username = models.CharField(max_length=32) password = models.CharField(max_length=64)
建立數據表命令:
python3 manage.py makemigrations # 根據model裏面的規則建立表 python3 manage.py migrate
在model.py
中修改
class UserInfo(models.Model): id = models.BigAutoField(primary_key=True) # 自增ID # id = models.AutoField() username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() # 增長此字段
再次執行命令便可(改字段名同理):
python3 manage.py makemigrations # 根據model裏面的規則建立表 python3 manage.py migrate
每一次修改會在migrations中記錄每次修改進行比對,因此別刪裏面的文件
出現如下問題是由於默認新增字段不能爲空
You are trying to add a non-nullable field 'age' to userinfo without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now Type 'exit' to exit this prompt >>>做如下修改便可
age = models.IntegerField(null=True) # 修改成能夠爲空 # 或 age = models.IntegerField(default=1) # 修改默認值爲1
如發現表沒有建立成功請再次執行(必須兩條均執行)
python3 manage.py makemigrations python3 manage.py migrate
class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() ug = models.ForeignKey('UserGroup', null=True) # 新增外鍵,沒有數據時要設爲能夠爲空 # 生成的字段名默認生成爲ug_id ur = models.ForeignKey('self', null=True, blank=True) # ForeignKey的自關聯: 引用本身的ID
AutoField(Field) - int自增列,必須填入參數 primary_key=True BigAutoField(AutoField) - bigint自增列,必須填入參數 primary_key=True 注:當model中若是沒有自增列,則自動會建立一個列名爲id的列 from django.db import models class UserInfo(models.Model): # 自動建立一個列名爲id的且爲自增的整數列 username = models.CharField(max_length=32) class Group(models.Model): # 自定義自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整數 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整數 0 ~ 32767 IntegerField(Field) - 整數列(有符號的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整數 0 ~ 2147483647 BigIntegerField(IntegerField): - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807 自定義無符號整數字段 class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' PS: 返回值爲字段在數據庫中的屬性,Django字段默認的值爲: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)', BooleanField(Field) - 布爾值類型 NullBooleanField(Field): - 能夠爲空的布爾值 CharField(Field) - 字符類型 - 必須提供max_length參數, max_length表示字符長度 TextField(Field) - 文本類型 EmailField(CharField): - 字符串類型,Django Admin以及ModelForm中提供驗證機制 IPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制 GenericIPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6 - 參數: protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both" URLField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證 URL SlugField(CharField) - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號) CommaSeparatedIntegerField(CharField) - 字符串類型,格式必須爲逗號分割的數字 UUIDField(Field) - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能 - 參數: path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 容許文件 allow_folders=False, 容許文件夾 FileField(Field) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage width_field=None, 上傳圖片的高度保存的數據庫字段名(字符串) height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串) DateTimeField(DateField) - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 時間格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型 FloatField(Field) - 浮點型 DecimalField(Field) - 10進制小數 - 參數: max_digits,小數總長度 decimal_places,小數位長度 BinaryField(Field) - 二進制類型
# 單個字段 null=True default='111' db_index=True unique=True # 多個組合 class Meta: unique_together( (u,g), ) index_together( (u,g), ) # ADMIN參數 blank=True # 能夠爲空 verbose_name='用戶名' # 修改字段名 editable=False # 不可編輯,將被隱藏 help_text='這是提示信息' # 輸入提示信息 choice=[(0, 阿斯頓),(1, 地方)], # 一般跟個default註明默認值 error_messages # 自定義錯誤信息,如 {'null': 不能爲空, 'invaild':'格式錯誤',……} 字典鍵:null, blank, invaild, invaild_choice, unique, unique for date validators # 使用正則表達式自定義錯誤驗證(列表類型),從而定製想要的驗證規則
from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '優先錯信息1', 'c2': '優先錯信息2', 'c3': '優先錯信息3', }, validators=[ RegexValidator(regex='root_\d+', message='錯誤了', code='c1'), RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'), EmailValidator(message='又錯誤了', code='c3'), ] )
color_list = ( (1, "黑色"), (2, "白色"), (3, "藍色"), ) color = models.InterField(choice=color_list) # 使用choice參數
若是變量固定不變,使用此方法。選項動態時使用ForeignKey
刪除類後執行命令直接刪除
def index(request): from app01 import models # 增長 models.UserGroup.objects.create(title='銷售部') # 輸入一個數據 models.UserInfo.objects.create(user='root', password='123', age='18', ug_id=1) # 查找 group_list = models.UserGroup.objects.all() # 得到對象(row)列表 group_list = models.UserGroup.objects.first() # 得到第一個 group_list = models.UserGroup.objects.filter(id=1, title='銷售部') # AND關係 # 神奇的雙下劃線 group_list = models.UserGroup.objects.filter(id__gt=1) # id_gt 大於 # id_lt 小於 # 刪除 group_list = models.UserGroup.objects. filter(id__gt=1).delete() # # 更新 group_list = models.UserGroup.objects.filter(id__gt=1).update(title='公關部') # 字段爲空 group_list = models.UserGroup.objects.filter(age__isnull=True).update(title='公關部') return render(request, 'newindex.html', {"group_list": group_list})
################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 獲取全部的數據對象 def filter(self, *args, **kwargs) # 條件查詢 —— 過濾 # 條件能夠是:參數,字典,Q def exclude(self, *args, **kwargs) # 條件查詢 —— 排除 # 條件能夠是:參數,字典,Q def select_related(self, *fields) # 第一次查詢的時候就作了連表,減小查詢次數 性能相關:表之間進行join連表操做,一次性獲取關聯的數據。 model.tb.objects.all().select_related() model.tb.objects.all().select_related('表名') model.tb.objects.all().select_related('表名_外鍵字段(或表名)','表名_外鍵字段(或表名)') def prefetch_related(self, *lookups) # 不作連表,作屢次查詢 性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。 # 獲取全部用戶表 # 獲取用戶類型表where id in (用戶表中的查到的全部用戶ID) models.UserInfo.objects.prefetch_related('外鍵字段') from django.db.models import Count, Case, When, IntegerField Article.objects.annotate( numviews=Count(Case( When(readership__what_time__lt=treshold, then=1), output_field=CharField(), )) ) students=Student.objects.all().annotate(num_excused_absences=models.Sum( models.Case( models.When(absence__type='Excused', then=1), default=0, output_field=models.IntegerField() ))) def annotate(self, *args, **kwargs) # 用於實現聚合group by查詢 from django.db.models import Count, Avg, Max, Min, Sum v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 def distinct(self, *field_names) # 用於distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct進行去重 def order_by(self, *field_names) # 用於排序 models.UserInfo.objects.all().order_by('-id','age') def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # 構造額外的查詢條件或者映射,如:子查詢 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:若是存在order_by,reverse則是倒序,若是多個排序則一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列數據 def only(self, *fields): #僅取某個表中的數據(對象) models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') 替代方法: models.UserInfo.objects.values('username','id') # 區別爲字典or對象 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): # 建立對象 # 建議使用**dic的方式去傳參數 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) # 可以使用for循環批量生成對象,再經過bulk_create一次過導入數據庫。 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): # 是否有結果 其餘操做
經過外鍵關聯找到類型id對應的名稱
objs = models.UserInfo.objects.all() for obj in objs: print( obj.name, obj.age, obj.ut_id, obj.ut.title, # 單錶鏈接:直接使用外鍵鏈接的表中的字段 obj.ut.fo.caption, # 多表鏈接:使用本表外鍵中的源表裏面的外鍵中的字段 )
obj = models.UserType.objects.all().first() for row in obj.userinfo_set.all(): # obj.userinfo_set爲屬於obj這個類型的在userinfo表裏的全部行對象的集合 print(row.name, row.age)
objs = models.UserInfo.objects.all() # 返回結果是多個對象[obj,obj,...] objs = models.UserInfo.objects.all().first() # 返回結果是單個對象 obj objs = models.UserInfo.objects.all().values('id','name') # 返回結果是字典 [{id:v1,name:v1},{id:v2,name:v2},...] objs = models.UserInfo.objects.all().values_list('id','name') # 返回結果是元組 [(v1,v1),(v2,v2),...] # 跨表操做 objs = models.UserInfo.objects.all().values('id','name', 'ut__title') # 雙下劃線取跨表關聯值。ut爲外鍵,title爲源表中的值
# 注意必須是字典,不然會報錯 from django.http import JsonResponse # 若是想傳列表,須要加參數safe=False return JsonResponse([1,2,3], safe=False)
方法1: django自帶序列化queryset, 到達前端直接DataType
from django.core import serializers v = models.Server.objects.all() data = serializers.serialize("json", v)
方法2: 使用values()
v = models.Server.objects.values("id", "hostname", 'create_at')
因爲json沒法序列化時間,因此須要對其擴展
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): # 繼承JSON原生編碼類 def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self, field) data = json.dumps(list(v), cls=JsonCustomEncoder) # 每序列化一個字段以前都要先調用此類
在表中加入__str__()
方法,方便用print()查看排序結果
class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() ug = models.ForeignKey('UserGroup', null=True) def __str__(self): return "%s-%s"(self.id, self.name) # 快速查看結果
user_list = models.UserInfo.objects.all().order_by('id') user_list = models.UserInfo.objects.all().order_by('-id') # 倒序 user_list = models.UserInfo.objects.all().order_by('-id', 'name') #加入第二個排序條件 print(user_list)
from django.db.models import Count,Sum,Max,Min # 可引入多個聚合函數 v = models.UserInfo.objects.values('ug_id').annotate(xxx=Count('id')) print(v.query) # 可查看生成的SQL語句
SELECT 'app01_usergroup'.'ug_id', COUNT('app01_userinfo'.'id') AS 'xxx' FROM 'app01_userinfo'.'ug_id';
from django.db.models import Count,Sum,Max,Min v = models.UserInfo.objects.filter(id__gt=2).values('ug_id').annotate(xxx=Count('id')).filter(xxx__gt=2) print(v.query) # 可查看生成的SQL語句
SELECT 'app01_usergroup'.'ug_id', COUNT('app01_userinfo'.'id') AS 'xxx' FROM 'app01_userinfo' WHERE 'app01_userinfo'.'id' > 2 GROUP BY 'app01_userinfo'.'ug_id' HAVING COUNT('app01_userinfo'.'id') > 2; // filter 在前面是 WHERE 在後面是 HAVING
filter(id__gt) filter(id__lt) filter(id__lte) filter(id__gte) filter(id__in[1,2,3]) filter(id__range[1, 2]) # between filter(name__startswith='xxx') filter(name__contains='xxx') exclude(id=1) # 排除,即id!=1
ManyToManyField()
class Boy(): name = CharField(32) m = models.ManyToManyField("Girl") # 自動建立第三張表 class Girl(): nick = CharField(32) boyobj = models.Boy.objects.filter(name='boyname') boyobj.m.all() # 正向查詢得到Girl對象 boyobj.m.add(1,2) # 增長 boyobj.m.remove(*[1,2]) # 刪除 boyobj.m.set([1]) # 重置:清空而後加入此條關係 boyobj.m.clear() # 清空 girlobj = models.Boy.objects.filter(name='girlname') girlobj.boy_set() # 反向查詢得到Boy對象
class Love(models.Model): b = models.ForeignKey('Boy') g = models.ForeignKey('Girl') class Meta: unique_together = [ # 聯合惟一 (b, g), ]
class Boy(): name = CharField(32) m = models.ManyToManyField("Girl", through='Love', through_fields=('b','g')) # 使用自定義的表做爲關係表 class Girl(): nick = CharField(32) class Love(models.Model): b = models.ForeignKey('Boy') g = models.ForeignKey('Girl') class Meta: unique_together = [ # 聯合惟一 (b, g), ] # 此方法僅可以使用如下兩種方法 boyobj.m.all() boyobj.m.clear()
ManyToManyField
其餘參數介紹ManyToManyField( RelatedField # 要進行關聯的字段名 to, # related_name=None, # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做時,使用的鏈接前綴,用於替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中顯示關聯數據時,提供的條件: # 如: # - limit_choices_to={'nid__gt': 5} # - limit_choices_to=lambda : {'nid__gt': 5} # from django.db.models import Q # - limit_choices_to=Q(nid__gt=10) # - limit_choices_to=Q(nid=8) | Q(nid__gt=10) # - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段 # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段 # models.BB.objects.filter(...) # 可選字段有:code, id, m1 # class BB(models.Model): # code = models.CharField(max_length=12) # m1 = models.ManyToManyField('self',symmetrical=True) # 可選字段有: bb, code, id, m1 # class BB(models.Model): # code = models.CharField(max_length=12) # m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定義第三張表時,使用字段用於指定關係表 through_fields=None, # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表 # from django.db import models # class Person(models.Model): # name = models.CharField(max_length=50) # class Group(models.Model): # name = models.CharField(max_length=128) # members = models.ManyToManyField( # Person, # through='Membership', # through_fields=('group', 'person'), # ) # class Membership(models.Model): # group = models.ForeignKey(Group, on_delete=models.CASCADE) # person = models.ForeignKey(Person, on_delete=models.CASCADE) # inviter = models.ForeignKey( # Person, # on_delete=models.CASCADE, # related_name="membership_invites", # ) # invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在數據庫中建立外鍵約束 db_table=None, # 默認建立第三張表時,數據庫中表的名稱 )
from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger # 此步模擬數據庫中獲取的結果,請忽略 L = [] for i in range(999): L.append(i) def index(request): current_page = request.GET.get('p') paginator = Paginator(L, 10) # 實例化分頁對象 # Paginator的參數解釋: # per_page: 每頁顯示條目數量 # count: 數據總個數 # num_pages:總頁數 # page_range:總頁數的索引範圍,如: (1,10),(1,200) # page: page對象 try: posts = paginator.page(current_page) # has_next 是否有下一頁 # next_page_number 下一頁頁碼 # has_previous 是否有上一頁 # previous_page_number 上一頁頁碼 # object_list 分頁以後的數據列表 # number 當前頁 # paginator paginator對象 except PageNotAnInteger: # 如非整型數字錯誤則把當前頁設爲1 posts = paginator.page(1) except EmptyPage: # 如頁面爲空則把當前頁設爲最後一頁 posts = paginator.page(paginator.num_pages) return render(request, 'index.html', {'posts': posts})
<ul> {% for item in posts %} {# 打印當前頁內容 #} <li>{{ item }}</li> {% endfor %} </ul> <div class="pagination"> <span class="step-links"> {# 若是有上一頁則顯示Previous按鈕 #} {% if posts.has_previous %} <a href="?p={{ posts.previous_page_number }}">Previous</a> {% endif %} <span class="current"> {# 顯示效果爲 '當前頁碼' of '總頁碼' #} Page {{ posts.number }} of {{ posts.paginator.num_pages }}. </span> {% if posts.has_next %} {# 若是有下一頁則顯示Next按鈕 #} <a href="?p={{ posts.next_page_number }}">Next</a> {% endif %} </span> </div>
分頁時須要作三件事:
#!/usr/bin/env python # _*_coding:utf-8_*_ from django.utils.safestring import mark_safe class PageInfo(object): def __init__(self, current, totalItem,peritems=5): self.__current=current self.__peritems=peritems self.__totalItem=totalItem def From(self): return (self.__current-1)*self.__peritems def To(self): return self.__current*self.__peritems def TotalPage(self): #總頁數 result=divmod(self.__totalItem,self.__peritems) if result[1]==0: return result[0] else: return result[0]+1 def Custompager(baseurl,currentPage,totalpage): #基礎頁,當前頁,總頁數 perPager=11 #總頁數<11 #0 -- totalpage #總頁數>11 #當前頁大於5 currentPage-5 -- currentPage+5 #currentPage+5是否超過總頁數,超過總頁數,end就是總頁數 #當前頁小於5 0 -- 11 begin=0 end=0 if totalpage <= 11: begin=0 end=totalpage else: if currentPage>5: begin=currentPage-5 end=currentPage+5 if end > totalpage: end=totalpage else: begin=0 end=11 pager_list=[] if currentPage<=1: first="<a href=''>首頁</a>" else: first="<a href='%s%d'>首頁</a>" % (baseurl,1) pager_list.append(first) if currentPage<=1: prev="<a href=''>上一頁</a>" else: prev="<a href='%s%d'>上一頁</a>" % (baseurl,currentPage-1) pager_list.append(prev) for i in range(begin+1,end+1): if i == currentPage: temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i) else: temp="<a href='%s%d'>%d</a>" % (baseurl,i,i) pager_list.append(temp) if currentPage>=totalpage: next="<a href='#'>下一頁</a>" else: next="<a href='%s%d'>下一頁</a>" % (baseurl,currentPage+1) pager_list.append(next) if currentPage>=totalpage: last="<a href=''>末頁</a>" else: last="<a href='%s%d'>末頁</a>" % (baseurl,totalpage) pager_list.append(last) result=''.join(pager_list) return mark_safe(result) #把字符串轉成html語言
from django.db.models import F model.UserInfo.object.all().update(age=F("age" + 1))
condition = { 'id':1, 'name':'root' } model.UserInfo.object.all().filter(**condition)
from django.db.models import Q model.UserInfo.object.all().filter(Q(id=8) | Q(id=2)) # Q的or用法 # model.UserInfo.object.all().filter(Q(id=8) & Q(id=2)) q1 = Q() q1.connector = 'OR' q1.children.append(('c1', 1)) q1.children.append(('c1', 10)) q1.children.append(('c1', 9)) q2 = Q() q2.connector = 'OR' q2.children.append(('c1', 2)) q2.children.append(('c1', 5)) q2.children.append(('c1', 6)) q3 = Q() q3.connector = 'AND' q3.children.append(('id', 1)) q3.children.append(('id', 2)) q2.add(q3, 'OR') con = Q() con.add(q1, 'AND') con.add(q2, 'AND')
# 使用for將字段轉化爲Q # 假如這是一個前端的條件選擇器 condition_dict = { 'k1': [1, 2, 3, 4], 'k2': [1,], 'k3': [11,] } # 服務端無需修改 con = Q() for k,v in condition_dict.items(): q = Q() q.connect = 'OR' for i in v: q.children.append(('id',i)) con.add(q, 'AND') model.UserInfo.object.all().filter(con)
select參數
v = model.UserInfo.object.all().extra(select={ 'n': "SELECT COUNT(1) FROM app01_usertype" }) """ SELECT id, name, (SELECT COUNT(1) FROM app01_usertype) as n FROM app01_userinfo; """ v = model.UserInfo.object.all().extra(select={ 'n': "SELECT COUNT(1) FROM app01_usertype WHERE id > %s OR id=%s" , 'm': "SELECT COUNT(1) FROM app01_usertype WHERE id > %s OR id=%s" , }, select_params=[1, 2, 3, 4])
where參數
v = model.UserInfo.object.all().extra( where=['id=1 or id=2',"name='alex"] # 列表之間以AND鏈接,元素能夠爲SQL原生語句如or,and等.. ,params=[]) # 同理可以使用佔位符
還有其餘參數...
# 笛卡爾積 v = model.UserInfo.object.all().extra( tables=['app01_usertype'] # 列表之間以AND鏈接,元素能夠爲SQL原生語句如or,and等.. ,params=[])
v = model.UserInfo.object.all().extra( select={'newid':'"SELECT COUNT(1) FROM app01_usertype WHERE id > %s', select_params=[1,], where=['age > %s'], params=[18,], order_by=['-age'], tables=['app01_usertype']
生成的SQL語句爲
SELECT app01_userinfo.id, (SELECT COUNT(1) FROM app01_usertype WHERE id) AS newid FROM app01_userinfo, app01_usertype WHERE app01_userinfo.age > 18 ORDER BY app01_userinfo.age DESC
required=True, 是否容許爲空 widget=None, HTML插件 label=None, 用於生成Label標籤或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標籤旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否能夠編輯 label_suffix=None Label內容後綴
CharField(Field)
max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除用戶輸入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 總長度
decimal_places=None, 小數位長度
BaseTemporalField(Field)
input_formats=None 時間格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 時間間隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定製正則表達式
max_length=None, 最大長度
min_length=None, 最小長度
error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否容許空文件
ImageField(FileField)
...
注:須要PIL模塊,pip3 install Pillow
以上兩個字典使用時,須要注意兩點:
- form表單中 enctype="multipart/form-data"
- view函數中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默認select插件
label=None, Label內容
initial=None, 初始值
help_text='', 幫助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查詢數據庫中的數據
empty_label="---------", # 默認空顯示內容
to_field_name=None, # HTML中value的值對應的字段
limit_choices_to=None # ModelForm中對queryset二次篩選
ModelMultipleChoiceField(ModelChoiceField) # 多選
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 對選中的值進行一次轉換
empty_value= '' 空值的默認值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 對選中的每個值進行一次轉換
empty_value= '' 空值的默認值
ComboField(Field)
fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中
path, 文件夾路徑
match=None, 正則匹配
recursive=False, 遞歸下面的文件夾
allow_files=True, 容許文件
allow_folders=False, 容許文件夾
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用
SlugField(CharField) 數字,字母,下劃線,減號(連字符)
...
UUIDField(CharField) uuid類型
...
from django.forms import Form from django.forms import fields class LoginForm(Form): username = fields.CharField( # 與表單<input>中的name一致 max_length=18, # 最長長度 min_length=6, # 最短長度 required=True, # 不能爲空 error_messages={ # 錯誤信息重寫 'required': "用戶名不能爲空", 'min_length': "過短了", 'max_length': "太長了", } ) password = fields.CharField(max_length=18,required=True) def login(request): if request.method == "GET": return render(request, 'index.html') else: obj = LoginForm(request.POST) # 拿到POST信息 if obj.is_valid: # 是否經過驗證 obj.cleand_data # 拿到用戶輸入正確的信息(字典) else: obj.errors # 這是一個對象,加了__str__() obj.errors['username'] # 獲取錯誤信息列表 obj.errors['password'] return render(request, 'login.html', {'obj': obj} )
在模版中加入
{{ obj.errors.username.0 }} {{ obj.errors.password.0 }}
class LoginForm(Form): # 繼承Field類,有required,help_text,error_messages等經常使用參數 t1 = fields.CharField() # 默認required等於Ture t2 = fields.IntegerField( error_messages={ 'required': 't2不能爲空', 'invaild': '格式錯誤,必須爲數字', 'max_value': '必須小於1000', 'min_value': '必須大於10' }) ### 繼承CharField類的全部參數,另有min_length,max_length,strip等參數 ### t3 = fields.EmailField( error_messages={ 'required': 't3不能爲空', 'invaild': '格式錯誤,必須爲郵箱格式' }) t4 = fields.URLField() t5 = fields.SlugField() # 除特殊字符外的字符 t6 = fields.GenericIPAddressField() t7 = fields.DateField() t8 = fields.DateTimeField() t9 = fields.RegexField( # 自定義正則的規則 '139\d+', # 正則表達式 error_massage={ 'invaild': '輸入有效的號碼' } ) ########################################################
from django.forms import fields from django.forms import widgets class TestForm(Form): t1 = fields.CharField( #############組合使用自動生成HTML標籤############### widget=widgets.Textarea # 控制生成的input類型:默認是text label='用戶名', # 標籤 initial='user1', # 提供默認值 help_text='請輸入你的用戶名' # 幫助信息 localize=False, # 時間本地化 disable=False, # 禁用 label_suffix=':' # 標籤後的符號 #############組合使用自動生成HTML標籤############### validators=[], ) # widget多種用法 cls_id = fields.IntegerField( # widget.Select() widget=widgets.Select(choices=[(1, '上海'),(2, '北京')]) # 增長固定值 widget=widgets.Select( choices=models.Classes.objects.values_list('id', 'title')) # 使用數據庫內的值做爲選項 # widget.TextInput() widget=widgets.TextInput(attrs={'class': 'form-contrl'}) # 爲插件增長屬性,每一個插件都有這個參數 ) 注意!這裏有BUG!:choice的值沒法自動更新,由於class只在啓動時將變量啓動一次,後續示例化不會再從新取值,choice值亦不會變化。加入如下代碼解決問題: # 方法一 def __init__(self, *args, **kwargs): super(TeacherForm, self).__init__(*args, **kwargs) self.fields['cls_id'].choices = models.Classes.objects.values_list('id','title') # 方法二 : 耦合性高,建議小的應用程序使用 from django.forms import models as form_model cls_id = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) # 須要在Classes中加入__str__配合使用 def __str__(): return self.title
<p> {{ obj.as_p }} {# 順序爲: label|label_suffix|input輸入框[默認值](disable)|help_text #} </p> <ul> {{ obj.as_ul }} {# 生成ul #} </ul> <table> {{ obj.as_table }} {# 生成table #} </table>
後附所有字段參數的解釋
好處:不刷新,上次內容自動保留
<form id='f1' action='/login' method='POST'> {% csrf_token %} <input type='text' name="username"> <input type='password' name="password"> <input type='submit' values="提交"> </form> <a onclick="submitForm()">Ajax提交</a> <script> function summitForm(){ $('.c1').remove; $.ajax({ url: '/ajax_login', type: 'POST', data: $('#f1').serialize() // 將數據變成user=alex&pwd=456&csrftoken=defefaasd dataType: 'JASON' success: function(arg){ if (arg.status){ // 空 } else { $.each(arg.msg, function(index, value)) { var tag = document.createElement('span'); tag.innerHTML = value[0] $('#f1').find('input[name="' + index + '"]').after(tag); } } } }) } </script>
import json def ajax_login(request): ret = {'status': True, 'msg': None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: ret['status'] = False ret['msg'] = obj.errors v = json.dumps(obj.username) return HttpResponse(v)
login.py
<form id='f1' action='/login/' method='POST' novalidate> {# novalidate禁止瀏覽器自己驗證功能 #} {% csrf_token %} <p> {{ obj.username }}{{ obj.errors.username.0 }} {# 自動生成input標籤class=username #} </p> <p> {{ obj.password }}{{ obj.errors.password.0 }} </p> <input type='submit' values="提交"> </form> <a onclick="submitForm()">Ajax提交</a>
class LoginForm(Form): username = field.CharField(min_length=8) password = field.CharField() def login(request): if request.method == "GET": obj = LoginForm() # 第一次GET進來value不帶值 return render(request, "login.html", {'obj': obj}) else: obj = LoginForm(request.POST) # 第二次POST進來value帶着用戶輸入的值 if obj.is_vaild(): print(obj.cleaned_data) else: return render(request, 'login.html', {'obj': obj})
小tips——快速取出以元組爲元素的序列
id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []
class TestForm(Form): t1 = fields.CharField( widget=widgets.Textarea(attrs={}) # widget=widgets.TextInput(attrs={}) # widget=widgets.PasswordInput(attrs={}) ) t2 = fields.CharField( widget=widgets.CheckboxInput() # 單項選擇框 ) t3 = fields.MultipleChoiceField( widget=widgets.CheckboxSelectMultiple # 多選 ) t4 = fields.ChoiceField( widdget=widgets.RadioSelect # 單選 ) t5 = fields.FileField( widdget=widgets.FileInput # 文件上傳 ) def test(request): obj = TestForm(initial={'t3': [2, 3]}) # 設置默認值 return render(request, 'test.html', {'obj': obj})
關注返回值,寫錯就會有問題,建議看源碼
from django.core.exceptions import ValidationError from django.core.validators import RegexValidator class TestForm(Form): user = fields.CharField( validators=[RegexVaildator(r'^[0-9]+¥', '請輸入數字')] # 此處可再額外增長正則表達式 ) # 第一個鉤子 def clean_user(self): # 單獨對字段進行擴展,函數名格式爲"clean_變量名" v = self.cleaned_data['user'] # 必須已經取得值 if models.Student.objects.filter(name=v).count(): # 能夠到數據庫中查看是否有此值 raise ValidationError('用戶名已經存在') # raise ValidationError('用戶名已經存在', code='invaild') # code對應error_msg中的鍵 return v # 爲cleaned_data中的 # 第二個鉤子 def clean(self): # 對總體的值作驗證 user = self.cleaned_data.get('user') email = self.cleaned_data.get('email') if models.Student.objects.filter(user=user, email=email).count(): self.add_error('user', ValidationError('用戶名已經存在')) # 可將此錯誤歸爲user錯誤 raise ValidationError('用戶名已經存在') # 或直接拋錯誤,歸到__all__鍵 return self.cleaned_data # 若爲None會返回未經處理的原值 # 第三個鉤子 def _post_clean(self): # 通常不會用到(用clean基本足夠) pass 注:先執行正則,再執行此函數,如不經過正則,則不會執行此函數。 看源碼:is_valid --> self.errors --> self.full_clean() --> 最下面三個函數
Field required=True, 是否容許爲空 widget=None, HTML插件 label=None, 用於生成Label標籤或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標籤旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否能夠編輯 label_suffix=None Label內容後綴 CharField(Field) max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除用戶輸入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 總長度 decimal_places=None, 小數位長度 BaseTemporalField(Field) input_formats=None 時間格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定製正則表達式 max_length=None, 最大長度 min_length=None, 最小長度 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否容許空文件 ImageField(FileField) ... 注:須要PIL模塊,pip3 install Pillow 以上兩個字典使用時,須要注意兩點: - form表單中 enctype="multipart/form-data" - view函數中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默認select插件 label=None, Label內容 initial=None, 初始值 help_text='', 幫助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查詢數據庫中的數據 empty_label="---------", # 默認空顯示內容 to_field_name=None, # HTML中value的值對應的字段 limit_choices_to=None # ModelForm中對queryset二次篩選 ModelMultipleChoiceField(ModelChoiceField) # 多選 ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換 empty_value= '' 空值的默認值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 對選中的每個值進行一次轉換 empty_value= '' 空值的默認值 ComboField(Field) fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 容許文件 allow_folders=False, 容許文件夾 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 SlugField(CharField) 數字,字母,下劃線,減號(連字符) ... UUIDField(CharField) uuid類型 ...
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', )
正常順序:process_request【一、二、3】--> process_view【一、二、3】--> process_response【一、二、3】
class MyRequestExeute(object): def process_request(self,request): # 處理請求 pass # 不要返回request,不然直接跳過其餘中間件,1.10版本之後有所不一樣 def process_view(self, request, callback, callback_args, callback_kwargs): # 路由匹配,執行視圖函數 i =1 pass def process_exception(self, request, exception): # 發生錯誤時執行 pass def process_response(self, request, response): # 處理響應信息 return response # 須要返回response def process_template_reponse(self, request, response): return response
MIDDLEWARE_CLASSES = ( '模塊.middleware.auth.MyRequestExeute', # 加入本身的模塊路徑 )
默認:wsgiref + django 生產環境:uwsgi + django
XSS攻擊是指那些利用輸入框寫入代碼來控制用戶客戶端的行爲
注:Django自己內置防XSS攻擊機制,除非註明數據爲safe
msg = [] def comment(request): # 用戶使用評論輸入功能 if request.method == 'GET': return render(request, 'comment.html') else: v = request.POST.get('content') msg.append(v) return render(request, 'comment.html') def index(request): # 將評論在index頁面展現 return render(request, 'index.html', {'msg': msg})
<form method='POST' action='/comment/'> <input type='text' name='content' /> <input type='submit' name='提交' /> </form>
解除XXS防護的標記,前端代碼加safe
<h1>評論</h1> {% for item in msg %} <div>{{ item }}</div> {# {# <div>{{ item | safe }}</div> 若是要非用safe必須將特殊字符排除#} {% endfor %}
mark_safe()
newtemp = mark_safe(temp) # 作此標記後,數據會被前端認爲是安全數據
防止黑客利用修改URL上的參數進行盜取用戶信息或控制瀏覽器的行爲,主要採用token驗證身份的方法。
{% csrf_token %}
<form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name='user' /> <input type="submit" value="提交" /> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ var csrf = $("input[name='csrfmiddlewaretoken']").val() // 獲取csrf_token裏面的值 var user = $("#user").val() // 獲取用戶名 $.ajax({ url: '/csrf.html', type: 'POST', data: {"user": user, "csrfmiddlewaretoken": csrf}, success:function(arg){ console.log(arg); } }) } </script>
cookie = document.cookie // 原生的js獲取cookie的方法 使用jquery.cookie插件 <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"> </script> <script> function submitForm(){ var token = $.cookie('csrftoken'); // 獲取cookie裏面的token var user = $("#user").val(); // 獲取用戶名 $.ajax({ url: '/csrf.html', type: 'POST', headers: {"X-CSRFToken": token} // 添加請求頭傳token data: {"user": user}, success:function(arg){ console.log(arg); } }) } </script>
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 將此項註釋掉 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt # 此函數不可用 def csrf1(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('OK') @csrf_protect # 此函數可用 def csrf2(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('OK')
from django.views import View from django.utils.decorators import method_decorator @method_decorator(csrf_exempt) # CBV需使用此裝飾器 @method_decorator(csrf_exempt, name='get') # 可用name參數註明給哪一個方法加,給'dispatch'加即所有加 class Foo(View): def dispatch(self, request, *args, **kwargs): pass def get(self, request): pass @method_decorator(csrf_exempt) # 可在指定方法加裝飾器 def post(self, request): pass
將Model和Form結合,以達到快速建立表單和數據驗證並提交的效果。
參考資料:http://www.cnblogs.com/wupeiqi/articles/6229414.html
from django.forms.models import ModelForm class TestModelForm(ModelForm): # 想自定義仍可自定義 class Meta: model = models.UserInfo # 無需從新定義表單屬性,直接根據models生成 field = '__all__' error_message = { 'user': {'required': '用戶名不能爲空'}, 'email': {'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤'} } def test(request): if request.method == 'GET': form = TestModelForm() context = { 'form': form } return render(request, 'test.html', context) else: form = TestModelForm(request.POST) if form.is_vaild(): form.save() return redirect('http//:www.google.com') context = { 'form': form } return render(request, 'test.html', context) def edit(request, nid): obj = models.UserInfo.object.filter(id=nid).first() if request.method == "GET": form = TestModelForm(instance=obj) context = { 'form': form } return render(request, 'edit.html', context) else: form = TestModelForm(instance=obj, data=request.POST, file=request.FILES) if form.is_vaild(): form.save() # 保存數據到數據庫 return redirect('http://www.google.com') context = { 'form': form } return render(request, 'test.html', context)
ModelForm a. class Meta: model, # 對應Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 幫助提示信息 widgets=None, # 自定義插件 error_messages=None, # 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定義字段類 (也能夠自定義字段) localized_fields=('birth_date',) # 本地化,如:根據不一樣時區顯示數據 如: 數據庫中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 則顯示: 2016-12-27 12:10:57 b. 驗證執行過程 is_valid -> full_clean -> 鉤子 -> 總體錯誤 c. 字典字段驗證 def clean_字段名(self): # 能夠拋出異常 # from django.core.exceptions import ValidationError return "新值" d. 用於驗證 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用於建立 model_form_obj = XXOOModelForm(request.POST) #### 頁面顯示,並提交 ##### # 默認保存多對多 obj = form.save(commit=True) # 不作任何操做,內部定義 save_m2m(用於保存多對多) obj = form.save(commit=False) obj.save() # 保存單表信息 obj.save_m2m() # 保存關聯多對多信息 f. 用於更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 單純初始化 model_form_obj = XXOOModelForm(initial={...})
前提:使用django自帶的user表
from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required @login_required() def acc_login(request): error = '' if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username, password=password) if user: login(request, user) return redirect('/') else: error = 'wrong password or username' return render(request, 'login/', 'error': error) @login_required(login_url='/login/') def acc_logout(request): logout(request) return redirect(request.GET.get('next', '/')) @login_required(login_url='/login/') # 能夠在此處單獨註明,也能夠在settings裏面加入LOGIN_URL,便可全局控制 def host_list(request):
{{ request.user }} // 前端模板調用user {{ request.path }} // 獲取當前url {{ request.user.account.host_group.all }} // 使用request中的user進行查找,像使用object同樣 function() { $("#miannav-menu a[herf='{{ request.path }}']").parent().addClass('active-link') // 模板中的按鍵的上一級與url對應的目錄變成激活狀態 } // $.get("{% url 'get_host_list' %}",{'gid': gid}, function(callback){ console.log(callback); })
使用jquery 的get、POST方法傳ajax到服務器
function getHostlist(self,bind){ $.get("{% url 'get_host_list' %}",{'gid': gid, 'csrfmiddlewaretoken': '{{ csrf_token }}'}, function(callback){ console.log(callback); }) } // 注意self是click事件綁定時將this傳入 function getToken(self, bind_host_id){ $.post("{% url 'get_token' %}",{'bind_host_id': bind_host_id,'csrfmiddlewaretoken': '{{ csrf_token }}'}, function(callback){ console.log(callback); }) }
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/7444717.html