還有五天哦
猛戳進入詳細瞭解↓↓↓
django處理請求的過程
1. 進來的請求轉入/hello/.
2. Django 透過在ROOT_URLCONF 配置來決定根URLconf.
3. Django 在 URLconf 中的所有 URL 樣式中,查詢第一個匹配/hello/的條目。
4. 如果找到匹配,將呼叫相應的檢視函式
5. 檢視函式傳回一個HttpResponse
6. Django 轉換HttpResponse 為一個適合的HTTP response, 以 Web page 顯示出來
M ,資料存取部分,由django 資料庫層處理,本章要講述的內容。
V ,選擇顯示哪些資料要及怎樣顯示的部分,由檢視和模板處理。
C ,根據使用者輸入委派檢視的部分,由Django 框架透過按照URLconf 設定,對給定URL 呼叫合適的python 函式來自行處理。
一、檢視函式(views.py中的函式):第一個引數型別是HttpRequest物件,傳回值是HttpResponse物件
二、URLconf(urls.py):系結檢視函式和URL (urlpatterns只有一個空串時django顯示歡迎頁面)
(r’^time/plus/(\d{1,2})/$’, hours_ahead),urls.py用圓括號從正則中提取資料;
def hours_ahead(request, offset):…,views.py檢視函式的第二個引數是從url中提取的字串
三、除錯,在檢視的任何位置插入一個assert False來觸發django的出錯頁
四、模板引擎
1.模板是一個文字,用於分離檔案的表現形式和內容。模板定義了佔位符以及各種用於規範檔案該如何顯示的各部分基本邏輯(模板標簽)。模板通常用於產生HTML,但是 Django 的模板也能產生任何基於文字格式的檔案。
2.用兩個大括號括起來的文字(例如{{ person_name }} )稱為變數(variable) 。這意味著將按照給定的名字插入變數的值。
3.被大括號和百分號包圍的文字(例如 {% if ordered_warranty %} )是 模板標簽(template tag) 。標簽(tag)定義比較明確,即:僅通知模板系統完成某些工作的標簽。
4.filter 過濾器,它是一種最便捷的轉換變數輸出格式的方式。如這個例子中的{{ship_date|date:”F j, Y” }},我們將變數ship_date 傳遞給date 過濾器,同時指定引數”F j,Y”。date過濾器根據引數進行格式輸出。
5.模板使用
1>可以用原始的模板程式碼字串建立一個Template 物件,Django 同樣支援用指定模板檔案路徑的方式來建立Template 物件;
2>呼叫模板物件的render 方法,並且傳入一套變數context。它將傳回一個基於模板的展現字串,模板中的變數和標簽會被context 值替換。
python manage.py shell 進入互動樣式
6.template.Context跟字典的結構類似;t.render(c)傳回的是一個unicode物件,not 普通python字串
7.在 Django 模板中遍歷複雜資料結構的關鍵是句點字元(.);假設你要向模板傳遞一個Python 字典。 要透過字典鍵訪問該字典的值,可使用一個句點;同樣,也可以透過句點來訪問物件的屬性;點語法也可以用來取用物件的”方法”,呼叫方法時並沒有使用圓括號而且也無法給該方法傳遞引數,你只能呼叫不需引數的方法;不允許使用負數串列索引,像 {{ items.-1 }} 這樣的模板變數將會引發“ TemplateSyntaxError“
8.get_template() 函式以模板名稱為引數,在檔案系統中找出模組的位置,開啟檔案並傳回一個編譯好的Template物件.要定位某個模板檔案在你的系統裡的位置, get_template()方法會自動為你連線已經設定的TEMPLATE_DIRS 目錄和你傳入該法的模板名稱引數
9.比get_template()+Context+HttpResponse更方便的方式:render_to_response() 的第一個引數必須是要使用的模板名稱。如果要給定第二個引數,那麼該引數必須是為該模板建立Context 時所使用的字典。如果不提供第二個引數,render_to_response() 使用一個空字典
10.{% include “xx.html” %} 把一個網頁嵌入到另一個中,適用於頭部和底部的共有部分,對網頁中間部分使用不方便
11.{% extents “xx.html” %} {% block yy %} {% endblock %} 模板繼承就是先構造一個基礎框架模板,而後在其子模板中對它所包含站點公用部分和定義塊進行多載
12.如果你需要訪問父模板中的塊的內容,使用{{ block.super }}這個標簽吧,這一個魔法變數將會表現出父模板中的內容。如果只想在上級程式碼塊基礎上新增內容,而不是全部多載,該變數就顯得非常有用了
補充:
1.setting.py中INSTALLED_APPS 告訴 Django 專案哪些 app 處於啟用狀態,可以啟用對應app下麵的模型
2.在app的目錄下新增management/commands目錄,django就會自動的為commands目錄下的每個模組自動註冊manage.py命令,可以用python manage.py command_name來呼叫,具體命令的檔案編寫格式如下:
3.對session的使用:request.session[‘test’] = ‘test’,設定;request.session[‘test’]或request.session.get(‘test’,None),獲取;session是一個類似於字典的結構;HttpRequest物件中除session以外,其他屬性都應該當做只讀屬性用
1.django模板的html自動轉義
在django裡預設情況下,每一個模板自動轉意每一個變數標簽的輸出。 尤其是這五個字元。
< 被轉意為
> 被轉意為 >
‘ (single quote) 被轉意為 ‘
” (double quote) 被轉意為 ”
& 被轉意為 &
另外,我強調一下這個行為預設是開啟的。 如果你正在使用django的模板系統,那麼你是被保護的。
關閉自動轉義
對於單獨變數:
This will not be escaped: {{ data|safe }}
對於模板,autoescape 標簽有兩個引數on和off 有時,你可能想阻止一部分自動轉意,對另一部分自動轉意
2.配置多個資料庫 https://docs.djangoproject.com/en/1.4/topics/db/multi-db
$ ./manage.py syncdb --database=users
syncdb會把所有的model都同步到users資料庫,所以不一定是我們想要的(可以用router控制入庫到user資料庫的app)
syncdb也會檢索對應app的
[dongsong@bogon boosencms]$ vpython manage.py sqlall app_user | vpython manage.py dbshell --database=users
這個會把名為app_user的app下麵的model都同步到資料庫users(這個是setting.py的DATABASES中定義的資料庫key,不是實際資料庫的名字)中去
sqlall會把models.py中定義的model都轉換成sql陳述句、同時會把
sqlcustom只打印
sqlcustom的使用參考https://docs.djangoproject.com/en/dev/ref/django-admin/#sqlcustom-appname-appname(sql檔案的名稱必須lowercase)
WARNING:在models.py中設定column屬性時max_length,null,db_index,premary_key,unique,unique_together這些都是可以透過syncdb等命令作用到資料庫層面的,defalt則不行
運算元據表的時候在正常語法中間加上using(dbname)
Author.objects.using('default').all()
3.資料庫路由 database router
1>setting.py的DATABASES加入資料庫配置就不說了
2>建立myapp/myrouter.py檔案,並寫入如下程式碼(每個函式的具體含義可看官網說明)
3>修改setting.py,加入下麵這行
DATABASE_ROUTERS = ['myapp.myrouter.MyAppRouter']
4>為每個model的類新增app標簽app_label
5>同步資料庫,不制定database的時候用的預設default資料庫,由路由控制需要在其他資料庫建立的資料表會被忽略
vpython manage.py syncdb --database=default vpython manage.py syncdb --database=content ....
6>資料表建立完成就可以正式工作了,具體哪些model跟哪些資料庫對應,由router決定
附加:討論一個問題,如果model的app_label不存在會怎樣?
a.要想透過syncdb建立資料表就必須保證app_label跟實際存在及setting.py中註冊的app名稱(INSTALLED_APPS)相對應,可以不等於當前所在app的名字,但必須是存在和註冊的app名,否則syncdb的時候會把該model忽略掉(syncdb --database=dbName,django會根據router找跟dbName對應的app,並安裝,但是app如果沒有註冊則失敗),結果所有資料庫中都找不到該model對應的資料表結構
b.而如果所有model的app_label都對應著實際存在的app名,加上資料庫路由是由app_label和database_name(setting.py中DATABASES的key)來作控制的,那麼就出現了一個問題:每個app_label必須跟同一個資料庫對應
c.這個也不是什麼大問題,一般都滿足需求!萬一有變態需求呢?好吧,事實上我們可以定義不存在和沒註冊的app名作為app_label,然後在路由器上根據該app_label來控制其訪問哪個資料庫,這樣我們付出的代價就是a的問題不得不手動建立資料表了....還有一種處理辦法是在router根據表名制定更細的規則,只是這樣不便於修改(一個installed_app對應一個app_label,一個app_label對應一個database最好控制了)
4.關於自增和聯合索引
5.django的DateTimeField列型別指定了auto_now=True結果生成的資料表還是沒有預設當前更新時間的性質,google結果只說到如何在django的模型層實現這個功能(下麵是兩個方案),但是這樣在資料庫層面還是沒有預設當前更新時間的性質,如果用其他程式往該資料表寫資料或者更新資料就會出現問題!!!這個問題如何從資料庫層面解決呢???!!!(見2標紅
http://stackoverflow.com/questions/5899868/django-datetimefield-auto-now-add-not-working
created_datetime = models.DateTimeField(default=datetime.datetime.now)
6.model一些語法
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
等價於
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
等價於
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
filter的上述用法就不贅述了
對於__get還有其他類似的東東
__gt 大於 __gte 大於等於 __lt 小於 __lte 小於等於 __contains 包含 __startswith 以XX開頭
distinct的用法:
Entry.objects.order_by('pub_date').distinct('pub_date') Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
values()的用法:
count()的用法:
Entry.objects.count() Entry.objects.filter(headline__contains='Lennon').count()
Avg的用法:無記錄時34.35這個值是None
sum()的用法:
from django.db.models import Sum ModelName.objects.aggregate(Sum('field_name'))
更多類似的用法https://docs.djangoproject.com/en/1.4/ref/models/querysets/
7.django的QuerySet支援以數字索引取值,以及[num1:num2],但是不支援負數索引(不同於list)
8.select xxx from xxx where x in (y,yy,yyy);
result = Test.objects.filter(test_id__in=test_ids)
9.獲取表名
XX._meta.db_table
10.如何指定查詢某些列?如果全部列都構造出來可能會太佔記憶體、網路,也可能有延時的問題
# This will defer all fields except the headline. Entry.objects.only("body", "rating").only("headline")
用only傳回的物件modelObj,django只從資料查詢和構造用only指定的列;如果你用該modelObj取其他列,則django會立即去資料庫獲取(warning:此時獲取的可能是已經被其他行程或者執行緒修改過的資料哦,要小心)
用only指定某些列獲取值並修改了這些列,save()的時候會把相應的列更新到資料庫,其他列不變(不修改、不改寫);如果修改了only指定以外的列,save()的時候會把only制定的和這些被修改的列都更新到資料庫
更新還可以用這種方式實現:
>>> WomKeyWord.objects.filter(wordId=1).update(wordStr=u"中國人") 1L
11.reverse()方法 參考http://hi.baidu.com/youngvleo/blog/item/755ecf3f177128c07c1e71da.html
views.py from django.core.urlresolvers import reverse def redirect(request): return HttpResponseRedirect(reverse('mysite.polls.views.detail',args=(1,)))
“很容易明白,第一個引數就直接添入要使用的view方法,第二個args裡邊順序填入方法的引數,(extra_context也從這裡傳入)然後剩下的就全部交給django去完成拉。於是我們就可以放心的修改url.py裡的url配置,不
必再擔心有什麼地方沒修改網站出錯啦”
說白了,reverse()就是屌絲views的逆襲,從views裡面的方法反解url,該函式傳回的字串就是一個url串。用它的好處是修改urls.py裡面的url可以不用修改views檔案中的HttpResponseRedirect()引數。
12.djang多行程和多執行緒的問題
django單行程多執行緒:每個執行緒的資料庫操作會用不同的連線,如果某行程有60個執行緒,每個執行緒都有對同一個資料庫的操作,那麼該行程會有60個對該資料庫的連線(小心mysql最大連線數達到上限)。就測試結果來看,資料庫操作結束後(執行緒還沒退出)幾分鐘,連線會自動斷開(說個跟本話題無關的,tmpThread.setDaemon(True)考慮清楚再用,今天執行緒拋異常就跟這個有關Exception in thread Thread-6 (most likely raised during interpreter shutdown))
django多行程:如果在某個django的行程裡面用multiprocessing建立新的行程,則子行程會繼承父行程的資料庫連線socket,那麼父子行程同時做資料庫操作時會出錯(資料庫socket連線會丟擲異常“資料庫已不在”/"查詢過程中出錯")
如果在某個django的行程裡面用os.popen()或者subprocess.Popen()建立新的django行程(比如啟動一個django的command),則,子行程雖然會繼承父行程的資料庫連線socket,但也會自己構建屬於自己的資料庫連線(跟從bash下啟動行程一樣嘛,可以預料到的),不會有上述問題(順便說一句,subprocess才是正道,什麼os.popen()、popen2.*已不是官方倡導的多行程用法;multiprocessing倒不至於被人遺棄,因為它是類似於多執行緒threading模組的多行程模組,和前面的那些多行程模組適用性不一樣)
13.日誌
14.關於django自動新增的primary key(id, AutoField),如果指定了其他列primary_key = True則不會自動新增這個id列;每個model必須有一個primary_key(這個真是彆扭啊)
Each model requires exactly one field to haveprimary_key=True.
15.關於django事務操作
官方檔案https://docs.djangoproject.com/en/1.4/topics/db/transactions/
兩種官方支援的方式:
1>在MIDDLEWARE_CLASSES中配置中介軟體TransactionMiddleware,這種基於http服務的request和response決定何時提交(具體見檔案,我沒細看),對於deamon process不靠譜兒
2>用裝飾器@transaction.commit_on_success、@transaction.commit_manually
還用一種方式大家應該想到了,直接編寫事務的sql陳述句,透過執行raw sql來實現事務,我要這個!
16.或者,OR語法
select * from xx where a = 1 or a = 2;
在django中的實現:
rts = XX.objects.filter(a = 1) | XX.objects.filter(a = 2)
或者
from django.db.models import Q
rts = XX.objects.filter(Q(a = 1) | Q(a = 2))
或者| 並且& 都可以用
17.QuerySet分析(2013.3.6 14:56)
8.django記錄HTTP響應時間的方法 http://www.morethanseven.net/2011/06/30/Django-performance-1-measuring-performance/
我在專案中選用的是timelog模組,veasy_install django-timelog
19.為apache安裝mod_python模組:
鳥人用的第一種方法,這樣mod_python貌似(反正我沒找到方法)只能使用系統預設路徑下的python,真是很不爽呀...第二種方式編譯mod_python時可指定使用我自己的python,可惜失敗了
20.部署Django程式到執行mod_python的apache環境:
參考:https://docs.djangoproject.com/en/1.4/howto/deployment/modpython/
1>告訴apache要載入mod_python模組(mod_python 是一個 Apache 模組,它將對 Python 程式語言的支援整合到 Web 伺服器中。與用傳統的 CGI 方法執行 Python 指令碼相比,這種方法要快得多),在httpd.conf或/var/etc/httpd/conf.d/python.conf中新增:
LoadModule python_module modules/mod_python.so
2>告訴apache講我們的Django程式關聯到那個URL,在httpd.conf或者python.conf中新增:(如需要使用virtualenv下的python環境,可參考http://blog.csdn.net/xiarendeniao/article/details/6774520item47)
Location是url匹配,
那麼就會有個問題:如果我們在同一臺機器上起了多個virtual host,一個指定8088埠、root路徑是/var/www/html/,另一個指定9000埠、root路徑是/var/www/app/,那麼"http://localhost:8088/apps/"和"http://localhost:9000/apps/"請求是等效的,都交由mod_python處理去了。如果我們實際要做的是隻對9000埠來的請求交由/var/www/app/apps下麵的django程式處理呢?答案是Direcctor!
Directory是本地目錄匹配,上述配置改成
所以在
3>告訴apache不對媒體檔案使用mod_python,在httpd.conf或python.conf中新增:
4>重啟httpd
21.部署Django程式到共享Web宿主環境(httpd.conf不可修改;使用執行FastCGI程式的Web伺服器衍生行程):
參考:http://www.ibm.com/developerworks/cn/opensource/os-django/index.html
1>建立.htaccess檔案,並放到Django程式所在目錄
2>建立Python指令碼(與前述RewriteRule配置的檔案名相同)告訴Apache我們Django專案的不同設定並執行FastCGI程式。
3>chmod 755 testproject.fcgi 或者 用FTP客戶端修改檔案屬性(如不能透過shell訪問伺服器)
4>每次更改程式程式碼之後都需要更改該fcgi檔案的時間戳,告訴apache應用程式已經更新,然後它會重啟Django程式。
22.部署Django程式到執行mod_wsgi的apache環境:
23.model.save()貌似會觸發兩次sql操作,一個SELECT (1) AS `a` FROM a_table where provimaryId = xx; 一個update a_table set ...; 這個如何規避?
如果model的實體設定了有效的主鍵值,save會先查資料庫該主鍵對應記錄是否存在,是就update,否就insert
如果model的實體沒有設定有效的主鍵值,save會直接insert
save的引數force_insert就是直接insert;save的引數force_update是直接根據主鍵update
record.save(force_update=True)的前提是record的primary_key列有值
24.settings.py中設定DEBUG = True,同時logging的級別設定為logging.DEBUG則每次資料庫操作都會列印到日誌裡面(sql+args+time)
25.用django給其他應用提供http資料介面,當收到post請求的時候會傳回403錯誤,原因為請求方沒有提供csrf_token,解決辦法是對views.py中對應的方法新增@csrf_exempt裝飾(記得要 from django.views.decorators.csrf import csrf_exempt)