路由系統
簡而言之,django的路由系統作用就是使views里面處理數據的函數與請求的url建立映射關系。使請求到來之后,根據urls.py里的關系條目,去查找到與請求對應的處理方法,從而返回給客戶端http頁面數據

django 項目中的url規則定義放在project 的urls.py目錄下,
默認如下:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'admin/', admin.site.urls), ]
url()函數可以傳遞4個參數,其中2個是必須的:regex和view,以及2個可選的參數:kwargs和name。下面是具體的解釋:
- regex: regex是正則表達式的通用縮寫,它是一種匹配字符串或url地址的語法。Django拿着用戶請求的url地址,在urls.py文件中對urlpatterns列表中的每一項條目從頭開始進行逐一對比,一旦遇到匹配項,立即執行該條目映射的視圖函數或二級路由,其后的條目將不再繼續匹配。因此,url路由的編寫順序至關重要!
需要注意的是,regex不會去匹配GET或POST參數或域名,例如對於https://www.example.com/myapp/,regex只嘗試匹配myapp/。對於https://www.example.com/myapp/?page=3,regex也只嘗試匹配myapp/。
如果你想深入研究正則表達式,可以讀一些相關的書籍或專論,但是在Django的實踐中,你不需要多高深的正則表達式知識。
性能注釋:正則表達式會進行預先編譯當URLconf模塊加載的時候,因此它的匹配搜索速度非常快,你通常感覺不到。
- view:
當正則表達式匹配到某個條目時,自動將封裝的HttpRequest對象作為第一個參數,正則表達式“捕獲”到的值作為第二個參數,傳遞給該條目指定的視圖。如果是簡單捕獲,那么捕獲值將作為一個位置參數進行傳遞,如果是命名捕獲,那么將作為關鍵字參數進行傳遞。 - kwargs:
任意數量的關鍵字參數可以作為一個字典傳遞給目標視圖。 - name:
對你的URL進行命名,可以讓你能夠在Django的任意處,尤其是模板內顯式地引用它。相當於給URL取了個全局變量名,你只需要修改這個全局變量的值,在整個Django中引用它的地方也將同樣獲得改變。這是極為古老、朴素和有用的設計思想,而且這種思想無處不在。
1.最基礎映射
用戶訪問http://127.0.0.1:8000/index 然后后端使用index()函數處理
urls.py
from django.conf.urls import include, url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/$', views.index), ]
1、先從創建的app下的views.py面定義處理數據的函數
2、在urls.py里導入views
3、在urlpatterns里寫入一條url與處理函數的l映射關系
4、url映射一般是一條正則表達式,“” 字符串的開始,“$“ 字符串的結束
5、當寫成^$不輸入任何url時不會在返回黃頁,而是返回后面函數里對應的頁面。一般這一條會寫在url的最后。如
2.按照順序放置的動態路由
可以使用正則來匹配URL,將一組url使用一條映射搞定
urlpatterns = [
url(r'^host/(\d+)$', views.host),
url(r'^host_list/(\d+)/(\d+)$', views.host_list),
]
^host/(\d+)$
相對應的url是: ”http://127.0.0.1/host/2“ (\d+)是匹配任意的數字,在分頁時靈活運用。
在views.host中需要指定一個形式參數來接受(\d+)$ 的值
def user_list(request,id): return HttpResponse(id)
^host_list/(\d+)/(\d+)$
相對應的url是: ”http://127.0.0.1/host/8/9“,匹配到的數字會以參數的形式按照順序傳遞給views里面相對應的函數
在views.host_list中需要指定兩個形式參數,注意:此參數的順序嚴格按照url中匹配的順序
def user_list(request,hid,hid2): return HttpResponse(hid+hid2)
3.傳參形勢的路由
利用正則表達式的分組方法,將url以參數的形式傳遞到函數,可以不按順序排列
urlpatterns = [ url(r'^user_list/(?P<v1>\d+)/(?P<v2>\d+)$',views.user_list), ]
(?P<v1>\d+)
正則表達式的分組,相當於一個字典, key=v1, value=\d+。 {"v1":"\d+"}
然后將此參數傳遞到views里對應的函數,可以不按照順序
def user_list(request,v2,v1): return HttpResponse(v1+v2) 參數v1 = (?P<v1>\d+) 參數v2 = (?P<v2>\d+)
4.根據不同的app來分發不同的url
如果一個項目下有很多的app,那么在urls.py里面就要寫巨多的urls映射關系。這樣看起來很不靈活,而且雜亂無章。
我們可以根據不同的app來分類不同的url請求。
首先,在urls.py里寫入urls映射條目。注意要導入include方法
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ]
這條關系的意思是將url為”app01/“的請求都交給app01下的urls去處理
其次,在app01下創建一個urls.py文件,用來處理請求的url,使之與views建立映射
from django.conf.urls import include, url from app01 import views urlpatterns = [ url(r'index/$', views.index), ]
想對於url請求為: "http://127.0.0.1/app01/index/"
5.通過反射機制,為django開發一套動態的路由系統
在urls.py里定義分類正則表達式
from django.conf.urls import patterns, include, url from django.contrib import admin from DynamicRouter.activator import process urlpatterns = patterns('', # Examples: # url(r'^$', 'DynamicRouter.views.home', name='home'), # url(r'^blog/', include('blog.urls')), url(r'^admin/', include(admin.site.urls)), ('^(?P<app>(\w+))/(?P<function>(\w+))/(?P<page>(\d+))/(?P<id>(\d+))/$',process), ('^(?P<app>(\w+))/(?P<function>(\w+))/(?P<id>(\d+))/$',process), ('^(?P<app>(\w+))/(?P<function>(\w+))/$',process), ('^(?P<app>(\w+))/$',process,{'function':'index'}), )
在同目錄下創建activater.py
#!/usr/bin/env python #coding:utf-8 from django.shortcuts import render_to_response,HttpResponse,redirect def process(request,**kwargs): '''接收所有匹配url的請求,根據請求url中的參數,通過反射動態指定view中的方法''' app = kwargs.get('app',None) function = kwargs.get('function',None) try: appObj = __import__("%s.views" %app) viewObj = getattr(appObj, 'views') funcObj = getattr(viewObj, function) #執行view.py中的函數,並獲取其返回值 result = funcObj(request,kwargs) except (ImportError,AttributeError),e: #導入失敗時,自定義404錯誤 return HttpResponse('404 Not Found') except Exception,e: #代碼執行異常時,自動跳轉到指定頁面 return redirect('/app01/index/') return result
模版語言
模版的創建過程,對於模版,其實就是讀取模版(其中嵌套着模版標簽),然后將 Model 中獲取的數據插入到模版中,最后將信息返回給用戶
模板中也有自己的語言,該語言可以實現數據展示
* 創建模版
>>> from django.template import Template >>> t = Template("My name is {{my_name}}.") >>> print t
- 渲染模版 一旦你擁有一個Template對象,你可以通過給一個context來給它傳遞數據 ontext是一個變量及賦予的值的集合,模板使用它來得到變量的值,或者對於塊標簽求值 這個context由django.template模塊的Context類表示 它的初始化函數有一個可選的參數:一個映射變量名和變量值的字典 通過context調用Template對象的render()方法來填充模板
>>> from django.template import Context, Template >>> t = Template("My name is {{name}}.") >>> c = Context({"name": "Stephane"}) >>> t.render(c) 'My name is Stephane.'
變量名必須以字母(A-Z或a-z)開始,可以包含數字,下划線和小數點,變量名大小寫敏感
其他:
{{ item }} {% for item in item_list %} <a>{{ item }}</a> {% endfor %} forloop.counter forloop.first forloop.last {% if ordered_warranty %} {% else %} {% endif %} 母板:{% block title %}{% endblock %} 子板:{% extends "base.html" %} {% block title %}{% endblock %} 幫助方法: {{ item.event_start|date:"Y-m-d H:i:s"}} {{ bio|truncatewords:"30" }} {{ my_list|first|upper }} {{ name|lower }}
- 自定義simple_tag 1.在app中創建templatetags模塊 2.創建任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() @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,) return mark_safe(result) @register.filter def f1(arg1,arg2): ret = arg1 + arg2 if ret > 10: return True else: return False @register.simple_tag def f2(arg1,arg2): ret = arg1 + arg2 return ret
3.在使用自定義simple_tag的html文件中導入之前創建的 xx.py 文件名
{% load xx %}
4.使用simple_tag
{% my_simple_time 1 2 3%}
{% my_input 'id_username' 'hide'%}
注意 simple_tag 調用的時候,只能是 simple_tag 參數1 參數2
filter 調用時 只能是 參數1|filre:參數2,而且最多支持2參數
5.在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', )
ajax
對於WEB應用程序:用戶瀏覽器發送請求,服務器接收並處理請求,然后返回結果,往往返回就是字符串(HTML),瀏覽器將字符串(HTML)渲染並顯示瀏覽器上。
傳統的Web應用如表單提交,一個簡單操作需要重新加載全局數據
2、AJAX
AJAX,Asynchronous JavaScript and XML (異步的JavaScript和XML),一種創建交互式網頁應用的網頁開發技術方案。
-
異步的JavaScript:
使用 【JavaScript語言】 以及 相關【瀏覽器提供類庫】 的功能向服務端發送請求,當服務端處理完請求之后,【自動執行某個JavaScript的回調函數】。
PS:以上請求和響應的整個過程是【偷偷】進行的,頁面上無任何感知。 -
XML
XML是一種標記語言,是Ajax在和后台交互時傳輸數據的格式之一
利用AJAX可以做:
1、注冊時,輸入用戶名自動檢測用戶是否已經存在。
2、登陸時,提示用戶名密碼錯誤
3、刪除數據行時,將行ID發送到后台,后台在數據庫中刪除,數據庫刪除成功后,在頁面DOM中將數據行也刪除
jQuery的ajax
jQuery其實就是一個JavaScript的類庫,其將復雜的功能做了上層封裝,使得開發者可以在其基礎上寫更少的代碼實現更多的功能。
- jQuery Ajax 方法列表
jQuery.get(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 dataType: 返回內容格式,xml, json, script, text, html jQuery.post(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數 success: 載入成功時回調函數 dataType: 返回內容格式,xml, json, script, text, html jQuery.getJSON(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 jQuery.getScript(...) 所有參數: url: 待載入頁面的URL地址 data: 待發送 Key/value 參數。 success: 載入成功時回調函數。 jQuery.ajax(...) 部分參數: url:請求地址 type:請求方式,GET、POST(1.9.0之后用method) headers:請求頭 data:要發送的數據 contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8") async:是否異步 timeout:設置請求超時時間(毫秒) beforeSend:發送請求前執行的函數(全局) complete:完成之后執行的回調函數(全局) success:成功之后執行的回調函數(全局) error:失敗之后執行的回調函數(全局) accepts:通過請求頭發送給服務器,告訴服務器當前客戶端課接受的數據類型 dataType:將服務器端返回的數據轉換成指定類型 "xml": 將服務器端返回的內容轉換成xml格式 "text": 將服務器端返回的內容轉換成普通文本格式 "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行。 "script": 嘗試將返回值當作JavaScript去執行,然后再將服務器端返回的內容轉換成普通文本格式 "json": 將服務器端返回的內容轉換成相應的JavaScript對象 "jsonp": JSONP 格式 使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數名,以執行回調函數 如果不指定,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 converters: 轉換器,將服務器端的內容根據指定的dataType轉換類型,並傳值給success回調函數 $.ajax({ accepts: { mycustomtype: 'application/x-some-custom-type' }, // Expect a `mycustomtype` back from server dataType: 'mycustomtype' // Instructions for how to deserialize a `mycustomtype` converters: { 'text mycustomtype': function(result) { // Do Stuff return newresult; } }, });
- 基於jQueryAjax - Demo
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="XmlSendRequest();" value='Ajax請求' /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'text', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html>
ajax跨域
跨域,跨域名訪問,如:http://www.c1.com 域名向 http://www.c2.com域名發送請求
由於瀏覽器存在同源策略機制,同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。
- 瀏覽器的同源策略
通過Ajax,如果在當前域名去訪問其他域名時,瀏覽器會出現同源策略,從而阻止請求的返回。特別的:由於同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。
特別的:由於同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。
- 瀏覽器同源策略並不是對所有的請求均制約:
制約: XmlHttpRequest
不叼: img、iframe、script等具有src屬性的標簽
JSONP實現跨域請求
JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標簽的src屬性(瀏覽器允許script標簽跨域),通過動態創建一個script標簽,指定src屬性為跨域的api,那么html會把返回的字符創當作javascript代碼來進行解析,如果我們在返回的字符串中使用自定義函數形式包裝起來,然后在html中調用自定義函數,即可拿到返回的字符串
基於JSONP實現跨域Ajax - Demo
- django view api 代碼
def api(request): li = ['alex', 'eric', 'tony'] # "['alex', 'eric', 'tony']" temp = "fafafa(%s)" %(json.dumps(li)) #使用fafafa對字符串進行包裝 # fafafa(['alex', 'eric', 'tony']) return HttpResponse(temp)
- html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="Jsonp1();" value='提交'/> </p> <p> <input type="button" onclick="Jsonp2();" value='提交'/> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function Jsonp1(){ var tag = document.createElement('script'); //創建一個script標簽 tag.src = "http://c2.com:8000/test/"; //設置src屬性為api的url document.head.appendChild(tag); //添加到head中 document.head.removeChild(tag); //當script添加到head中后,會自動執行src,執行完之后,在刪除script標簽 } //事先定義好fafafa這個函數,當src請求之后,返回fafafa(li[aaaaaa])時候,自動找到fafafa這個函數,然后執行 function fafafa(arg) { console.log(arg) } //使用jquery封裝的ajax function Jsonp2() { $.ajax({ url:"http://c2.com:8000/test/", type: 'GET', dataType: 'jsonp', //注意此時的datatype為 jsonp jsonp: 'callback', //指定回調函數的key,用戶服務器端獲取回調函數名 jsonpCallback: 'list' //指定回調函數名 }) function list(arg){ console.log(arg); } } </script> </body> </html>
jquery的ajax中jsonp callback說明
- jsonp: 'callback', //指定回調函數的key,用戶服務器端獲取回調函數名
- jsonpCallback: 'list' //指定回調函數名
指定callback之后,請求的url就變成了http://www.c2.com:8000/test?callback=list
而我們服務端,只需要從拿到callback的值,然后用其值來封裝字符串,這樣實現了用戶自定義返回的封裝函數,更加靈活
CORS跨站資源共享實現跨域
隨着技術的發展,現在的瀏覽器可以支持主動設置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器允許跨域請求
簡單請求 OR 非簡單請求
條件:
1、請求方式:HEAD、GET、POST
2、請求頭信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 對應的值是以下三個中的任意一個
application/x-www-form-urlencoded
multipart/form-data
text/plain
注意:同時滿足以上兩個條件時,則是簡單請求,否則為復雜請求
* 簡單請求和非簡單請求的區別?
簡單請求:一次請求
非簡單請求:兩次請求,在發送數據之前會先發一次請求用於做“預檢”,只有“預檢”通過后才再發送一次請求用於數據傳輸。
* 關於“預檢”
- 請求方式:OPTIONS
- “預檢”其實做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息
- 如何“預檢”
=> 如果復雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過
Access-Control-Request-Method
=> 如果復雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過
Access-Control-Request-Headers
服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*'
數據庫操作Model
django有內置的ORM,並遵循Code Frist 的原則,即:根據代碼中定義的類來自動生成數據庫表。並根據objeck方法對數據庫進行操作
- 創建表
from django.db import models class userinfo(models.Model): name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField()
更多字段
1、models.AutoField 自增列 = int(11) 如果沒有的話,默認會生成一個名稱為 id 的列,如果要顯示的自定義一個自增列,必須將給列設置為主鍵 primary_key=True。 2、models.CharField 字符串字段 必須 max_length 參數 3、models.BooleanField 布爾類型=tinyint(1) 不能為空,Blank=True 4、models.ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,所以必須 max_lenght 參數 5、models.DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次創建添加,之后的更新不再改變。 6、models.DateTimeField 日期類型 datetime 同DateField的參數 7、models.Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places 8、models.EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 9、models.FloatField 浮點類型 = double 10、models.IntegerField 整形 11、models.BigIntegerField 長整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 12、models.IPAddressField 字符串類型(ip4正則表達式) 13、models.GenericIPAddressField 字符串類型(ip4和ip6是可選的) 參數protocol可以是:both、ipv4、ipv6 驗證時,會根據設置報錯 14、models.NullBooleanField 允許為空的布爾類型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 減號、下划線、字母、數字 18、models.SmallIntegerField 數字 數據庫中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 20、models.TimeField 時間 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正則表達式 22、models.BinaryField 二進制 23、models.ImageField 圖片 24、models.FilePathField 文件
更多參數:
1、null=True 數據庫中字段是否可以為空 2、blank=True django的 Admin 中添加數據時是否可允許空值 3、primary_key = False 主鍵,對AutoField設置主鍵后,就會代替原來的自增 id 列 4、auto_now 和 auto_now_add auto_now 自動創建---無論添加或修改,都是當前操作的時間 auto_now_add 自動創建---永遠是創建時的時間 5、choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 7、default 默認值 8、verbose_name Admin中字段的顯示名稱 9、name|db_column 數據庫中的字段名稱 10、unique=True 不允許重復 11、db_index = True 數據庫索引 12、editable=True 在Admin里是否可編輯 13、error_messages=None 錯誤提示 14、auto_created=False 自動創建 15、help_text 在Admin中提示幫助信息 16、validators=[] 17、upload-to