在上一章節中,使用 django.http.HttpResponse() 來輸出 "Hello World!",該方式將數據與視圖混合在一起,不符合 Django 的 MVC 思想。
本章節我們將為大家詳細介紹 Django 模板的應用,模板是一個文本,用於分離文檔的表現形式和內容。
1. 模板應用實例
1)創建 hello.html 文件
在 HelloWorld 目錄底下創建 templates 目錄並建立 hello.html 文件,整個目錄結構如下:
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py
| |-- urls.pyc
| |-- view.py
| |-- view.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- manage.py
`-- templates
`-- hello.html
hello.html 文件代碼如下:
變量在模板中使用雙括號。
2)編輯 settings.py 文件
向 Django 說明模板文件的路徑,編輯 HelloWorld/settings.py,修改 TEMPLATES 中的 DIRS 為 [BASE_DIR+"/templates",],如下所示:
3)編輯 view.py 文件
修改 view.py,增加一個新的對象,用於向模板提交數據:
1 from django.shortcuts import render
2
3 def hello(request):
4 context = {}
5 context['hello'] = 'Hello World!'
6 return render(request, 'hello.html', context)
這里使用 render 來替代之前使用的 HttpResponse,render 使用了一個字典 context 作為參數,context 字典中元素的鍵值 'hello' 對應了模板中的變量 '{{ hello }}'。
4)測試
訪問地址:http://127.0.0.1:8000/hello,可以看到頁面:
此時,已完成了使用模板來輸出數據,從而實現數據與視圖分離。
2. Django 模板標簽
1)if/else 標簽
基本語法格式如下:
if:
{% if condition %}
... display
{% endif %}
if/elif/else:
{% if condition1 %}
... display 1
{% elif condiiton2 %}
... display 2
{% else %}
... display 3
{% endif %}
根據條件判斷是否輸出。
if/else 支持嵌套。
{% if %} 標簽接受 and , or 或者 not 關鍵字來對多個變量做判斷 ,或者對變量取反(not),例如:
{% if athlete_list and coach_list %}
athletes 和 coaches 變量都是可用的。
{% endif %}
2)for 標簽
基本語法格式如下:
{% for %}
...
{% endfor %}
允許在一個序列上迭代。
與 Python 的 for 語句的情形類似,循環語法是 for X in Y ,Y 是要迭代的序列而X是在每一個特定的循環中使用的變量名稱。
每一次循環中,模板系統會渲染在 {% for %} 和 {% endfor %} 之間的所有內容。
例如,給定一個運動員列表 athlete_list 變量,我們可以使用下面的代碼來顯示這個列表:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
給標簽增加一個 reversed 使得該列表被反向迭代:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
可以嵌套使用 {% for %} 標簽:
{% for athlete in athlete_list %}
<h1>{{ athlete.name }}</h1>
<ul>
{% for sport in athlete.sports_played %}
<li>{{ sport }}</li>
{% endfor %}
</ul>
{% endfor %}
3)ifequal/ifnotequal 標簽
{% ifequal %} 標簽比較兩個值,當他們相等時,顯示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。
下面的例子比較兩個模板變量 user 和 currentuser :
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}
和 {% if %} 類似, {% ifequal %} 支持可選的 {% else%} 標簽:
{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% else %}
<h1>No News Here</h1>
{% endifequal %}
4)注釋標簽
Django 注釋使用 {# #}。
5)過濾器
模板過濾器可以在變量被顯示前修改它,過濾器使用管道字符,如下所示:
{{ name }} 變量被過濾器 lower 處理后,文檔大寫轉換文本為小寫。
過濾管道可以被 * 套接 * ,既是說,一個過濾器管道的輸出又可以作為下一個管道的輸入:
{{ my_list|first|upper }}
以上實例將第一個元素並將其轉化為大寫。
有些過濾器有參數,過濾器的參數跟隨冒號之后並且總是以雙引號包含。 例如:
{{ bio|truncatewords:"30" }}
這個將顯示變量 bio 的前30個詞。
其他過濾器:
6)include 標簽
{% include %} 標簽允許在模板中包含其它的模板的內容。
下面這個例子都包含了 nav.html 模板:
3. 模板繼承
模板可以用繼承的方式來實現復用。
1)創建原始文件
在項目的 templates 目錄中添加 base.html 文件,代碼如下:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>測試</title>
6 </head>
7 <body>
8 <h1>Hello World!</h1>
9 <p>Django 測試</p>
10 {% block mainbody %}
11 <p>original</p>
12 {% endblock %}
13 </body>
14 </html>
以上代碼中,名為 mainbody 的 block 標簽是可以被繼承者們替換掉的部分。
所有的 {% block %} 標簽告訴模板引擎,子模板可以重載這些部分。
2)繼承原始文件
hello.html 中繼承 base.html,並替換特定 block,hello.html 修改后的代碼如下:
1 {% extends "base.html" %}
2 {% block mainbody %}
3 <p>繼承了 base.html 文件</p>
4 {% endblock %}
第一行代碼說明 hello.html 繼承了 base.html 文件。
可以看出,這里相同名字的 block 標簽用以替換 base.html 的相應 block。
3)測試
訪問地址 http://127.0.0.1:8000,輸出結果如下:
五、Django 模型
Django 對各種數據庫提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。
Django 為這些數據庫提供了統一的調用API,根據業務需求選擇不同的數據庫。
MySQL 是 Web 應用中最常用的數據庫,本章節我們將以 Mysql 作為實例進行介紹。
1. 安裝 mysql 驅動
執行以下命令安裝:
>pip3 install mysqlclient
返回信息:

2. 數據庫配置
在項目的 settings.py 文件中找到 DATABASES 配置項,將其信息修改為:
1 DATABASES = {
2 'default': {
3 'ENGINE': 'django.db.backends.mysql', # 或者使用 mysql.connector.django
4 'NAME': 'day18',
5 'USER': 'ruready',
6 'PASSWORD': 'ruready',
7 'HOST': 'localhost',
8 'PORT': '3306',
9 }
10 }
上面包含數據庫名稱和用戶的信息,它們與 MySQL 中對應數據庫和用戶的設置相同。Django 根據這一設置,與 MySQL 中相應的數據庫和用戶連接起來。
3. 定義模型
1)創建 APP
Django 規定,如果要使用模型,必須要創建一個app。
使用以下命令創建一個 TestModel 的 app:
>python manage.py startapp TestModel
目錄結構如下:
HelloWorld
|-- TestModel
| |-- __init__.py
| |-- admin.py
| |-- models.py
| |-- tests.py
| `-- views.py
2)編輯 models.py 文件
修改 TestModel/models.py 文件,代碼如下:
1 from django.db import models
2
3 class Test(models.Model):
4 name = models.CharField(max_length=20)
以上的類名代表了數據庫表名,且繼承了 models.Model,類里面的字段代表數據表中的字段(name),數據類型則由 CharField(相當於varchar)、DateField(相當於datetime), max_length 參數限定長度。
3)修改 settings.py 文件
接下來在 settings.py 中找到 INSTALLED_APPS 這一項,如下:
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 'TestModel', #添加此項
9 ]
4)創建表結構
創建表結構,在命令行中運行:
返回信息:

讓 Django 知道我們在我們的模型有一些變更:
python manage.py makemigrations TestModel
返回信息:

創建表結構:
python manage.py migrate TestModel
返回信息:

表名組成結構為:應用名_類名(如:TestModel_test)。
注意:盡管我們沒有 在models 給表設置主鍵,但是 Django 會自動添加一個 id 作為主鍵。
4. 數據庫操作
1)新建 testdb.py 文件
在 HelloWorld 目錄中添加 testdb.py 文件,與 views.py 同級,然后添加數據。
添加數據需要先創建對象,然后再執行 save 函數,相當於 SQL 中的 INSERT。
1 # -*- conding:UTF-8 -*-
2
3 from django.http import HttpResponse
4 from TestModel.models import Test
5
6 # 數據庫操作
7 def testdb(request):
8 test1 = Test(name='ruready')
9 test1.save()
10 return HttpResponse('<p>數據添加成功!</p>')
2)編輯 urls.py 文件
1 from django.conf.urls import url
2 from django.contrib import admin
3 from . import view, testdb
4
5 urlpatterns = [
6 url(r'^admin/', admin.site.urls),
7 url(r'^hello/', view.hello),
8 url(r'^testdb$, testdb.testdb'),
9 ]
3)測試
訪問 http://127.0.0.1:8000/testdb
輸出結果如下:

5. 獲取數據
Django 提供了多種方式來獲取數據庫的內容。
修改 testdb.py文件,如下代碼所示:
1 # -*- coding: utf-8 -*-
2
3 from django.http import HttpResponse
4 from TestModel.models import Test
5
6 # 數據庫操作
7 def testdb(request):
8 # 初始化
9 response = ""
10 response1 = ""
11
12 # 通過objects這個模型管理器的 all() 獲得所有數據行,相當於 SQL 中的 SELECT * FROM
13 list = Test.objects.all()
14
15 # filter 相當於 SQL 中的 WHERE,可設置條件過濾結果
16 response2 = Test.objects.filter(id=1)
17
18 # 獲取單個對象
19 response3 = Test.objects.get(id=1)
20
21 # 限制返回的數據,相當於 SQL 中的 OFFSET 0 LIMIT 2;
22 Test.objects.order_by('name')[0:2]
23
24 #數據排序
25 Test.objects.order_by("id")
26
27 # 上面的方法可以連鎖使用
28 Test.objects.filter(name="ruready").order_by("id")
29
30 # 輸出所有數據
31 for var in list:
32 response1 += var.name + " "
33 response = response1
34 return HttpResponse("<p>" + response + "</p>")
輸出結果如下圖所示:

6. 更新數據
更新數據可以使用 save() 或 update(),修改 testdb.py 文件,如下代碼所示:
1 # -*- coding: utf-8 -*-
2 from django.http import HttpResponse
3 from TestModel.models import Test
4
5 # 數據庫操作
6 def testdb(request):
7 # 修改其中一個id=1的name字段,再save,相當於SQL中的UPDATE
8 test1 = Test.objects.get(id=1)
9 test1.name = 'Google'
10 test1.save()
11 # 另外一種方式
12 # Test.objects.filter(id=1).update(name='Google')
13 # 修改所有的列
14 # Test.objects.all().update(name='Google')
15 return HttpResponse("<p>修改成功!</p>")
輸出結果如下圖所示:

數據庫中數據已完成修改:

7. 刪除數據
刪除數據庫中的對象只需調用該對象的 delete() 方法即可。
修改 testdb.py 文件,如下代碼所示:
1 # -*- coding: utf-8 -*-
2 from django.http import HttpResponse
3 from TestModel.models import Test
4 # 數據庫操作
5 def testdb(request):
6 # 刪除id=1的數據
7 test1 = Test.objects.get(id=1)
8 test1.delete()
9 # 另外一種方式
10 # Test.objects.filter(id=1).delete()
11 # 刪除所有數據
12 # Test.objects.all().delete()
13 return HttpResponse("<p>刪除成功!</p>")
輸出結果如下圖所示:

數據庫中已無數據:
六、Django 表單
HTML表單是網站交互性的經典方式。 本章將介紹如何用 Django 對用戶提交的表單數據進行處理。
1. HTTP 請求
HTTP 協議以"請求-回復"的方式工作。客戶發送請求時,可以在請求中附加數據。服務器通過解析請求,就可以獲得客戶傳來的數據,並根據 URL 來提供特定的服務。
1)GET 方法
創建一個 search.py 文件,用於接收用戶的請求:
1 # -*- coding: utf-8 -*-
2 from django.http import HttpResponse
3 from django.shortcuts import render_to_response
4
5 # 表單
6 def search_form(request):
7 return render_to_response('search_form.html')
8
9 # 接收請求數據
10 def search(request):
11 request.encoding='utf-8'
12 if 'q' in request.GET:
13 message = '你搜索的內容為: ' + request.GET['q']
14 else:
15 message = '你提交了空表單'
16 return HttpResponse(message)
在模板目錄 templates 中添加 search_form.html 表單:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>Django 表單</title>
6 </head>
7 <body>
8 <form action="/search" method="get">
9 <input type="text" name="q">
10 <input type="submit" value="搜索">
11 </form>
12 </body>
13 </html>
urls.py 規則修改為如下形式:
1 from django.conf.urls import url
2 from . import view,testdb,search
3 urlpatterns = [
4 url(r'^$', view.hello),
5 url(r'^testdb$', testdb.testdb),
6 url(r'^search-form$', search.search_form),
7 url(r'^search$', search.search),
8 ]
訪問地址:http://127.0.0.1:8000/search-form 並搜索,結果如下所示:



2)POST 方法
上面使用了GET方法,視圖顯示和請求處理分成兩個函數處理。提交數據時更常用POST方法。
下面使用該方法,並用一個 URL 和處理函數,同時顯示視圖和處理請求。
在 tmplate 創建 post.html,代碼如下:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>Django 表單</title>
6 </head>
7 <body>
8 <form action="/search-post" method="post">
9 {% csrf_token %}
10 <input type="text" name="q">
11 <input type="submit" value="搜索">
12 </form>
13 <p>{{ rlt }}</p>
14 </body>
15 </html>
在模板的末尾,我們增加一個 rlt 記號,為表格處理結果預留位置。
表格后面還有一個 {% csrf_token %} 的標簽。csrf 全稱是 Cross Site Request Forgery。這是 Django 提供的防止偽裝提交請求的功能。POST 方法提交的表格,必須有此標簽。
在 HelloWorld 目錄下新建 search2.py 文件並使用 search_post 函數來處理 POST 請求:
1 # -*- coding: utf-8 -*-
2
3 from django.shortcuts import render
4 from django.views.decorators import csrf
5
6 # 接收POST請求數據
7 def search_post(request):
8 ctx ={}
9 if request.POST:
10 ctx['rlt'] = request.POST['q']
11 return render(request, "post.html", ctx)
urls.py 規則修改為如下形式:
1 from django.conf.urls import url
2 from . import view,testdb,search,search2
3
4 urlpatterns = [
5 url(r'^hello$', view.hello),
6 url(r'^testdb$', testdb.testdb),
7 url(r'^search-form$', search.search_form),
8 url(r'^search$', search.search),
9 url(r'^search-post$', search2.search_post),
10 ]
訪問 http://127.0.0.1:8000/search-post 顯示結果如下:



完成以上實例后,目錄結構為:
HelloWorld
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- search.py
| |-- search.pyc
| |-- search2.py
| |-- search2.pyc
| |-- settings.py
| |-- settings.pyc
| |-- testdb.py
| |-- testdb.pyc
| |-- urls.py
| |-- urls.pyc
| |-- view.py
| |-- view.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- TestModel
| |-- __init__.py
| |-- __init__.pyc
| |-- admin.py
| |-- admin.pyc
| |-- apps.py
| |-- migrations
| | |-- 0001_initial.py
| | |-- 0001_initial.pyc
| | |-- __init__.py
| | `-- __init__.pyc
| |-- models.py
| |-- models.pyc
| |-- tests.py
| `-- views.py
|-- db.sqlite3
|-- manage.py
`-- templates
|-- base.html
|-- hello.html
|-- post.html
`-- search_form.html
2. Request 對象
每個 view 函數的第一個參數是一個 HttpRequest 對象,就像下面這個 hello() 函數:
1 from django.http import HttpResponse
2
3 def hello(request):
4 return HttpResponse("Hello world")
HttpRequest對象包含當前請求URL的一些信息:
屬性 |
描述 |
path |
請求頁面的全路徑,不包括域名—例如, "/hello/"。 |
method |
請求中使用的HTTP方法的字符串表示。全大寫表示。例如: if request.method == 'GET': do_something() elif request.method == 'POST': do_something_else() |
GET |
包含所有HTTP GET參數的類字典對象。 |
POST |
包含所有HTTP POST參數的類字典對象。 服務器收到空的POST請求的情況也是有可能發生的。也就是說,表單form通過HTTP POST方法提交請求,但是表單中可以沒有數據。因此,不能使用語句if request.POST來判斷是否使用HTTP POST方法;應該使用if request.method == "POST" (參見本表的method屬性)。 注意: POST不包括file-upload信息。參見 FILES 屬性。 |
REQUEST |
為了方便,該屬性是POST和GET屬性的集合體,但是有特殊性,先查找POST屬性,然后再查找GET屬性。借鑒PHP's $_REQUEST。 例如,如果GET = {"name": "john"} 和POST = {"age": '34'},則 REQUEST["name"] 的值是"john", REQUEST["age"]的值是"34". 強烈建議使用GET and POST,因為這兩個屬性更加顯式化,寫出的代碼也更易理解。 |
COOKIES |
包含所有cookies的標准Python字典對象。Keys和values都是字符串。 |
FILES |
包含所有上傳文件的類字典對象。FILES中的每個Key都是<input type="file" name="" />標簽中name屬性的值. FILES中的每個value 同時也是一個標准Python字典對象,包含下面三個Keys:
- filename: 上傳文件名,用Python字符串表示
- content-type: 上傳文件的Content type
- content: 上傳文件的原始內容
注意:只有在請求方法是POST,並且請求頁面中<form>有enctype="multipart/form-data"屬性時FILES才擁有數據。否則,FILES 是一個空字典。 |
META |
包含所有可用HTTP頭部信息的字典。 例如:
- CONTENT_LENGTH
- CONTENT_TYPE
- QUERY_STRING: 未解析的原始查詢字符串
- REMOTE_ADDR: 客戶端IP地址
- REMOTE_HOST: 客戶端主機名
- SERVER_NAME: 服務器主機名
- SERVER_PORT: 服務器端口
META 中這些頭加上前綴HTTP_最為Key, 例如:
- HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE
- HTTP_HOST: 客戶發送的HTTP主機頭信息
- HTTP_REFERER: referring頁
- HTTP_USER_AGENT: 客戶端的user-agent字符串
- HTTP_X_BENDER: X-Bender頭信息
|
user |
是一個django.contrib.auth.models.User 對象,代表當前登錄的用戶。 如果訪問用戶當前沒有登錄,user將被初始化為django.contrib.auth.models.AnonymousUser的實例。 你可以通過user的is_authenticated()方法來辨別用戶是否登錄: if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users. 只有激活Django中的AuthenticationMiddleware時該屬性才可用 |
session |
唯一可讀寫的屬性,代表當前會話的字典對象。只有激活Django中的session支持時該屬性才可用。 |
raw_post_data |
原始HTTP POST數據,未解析過。 高級處理時會有用處。 |
Request對象也有一些有用的方法:
方法 |
描述 |
__getitem__(key) |
返回GET/POST的鍵值,先取POST,后取GET。如果鍵不存在拋出 KeyError。 這是我們可以使用字典語法訪問HttpRequest對象。 例如,request["foo"]等同於先request.POST["foo"] 然后 request.GET["foo"]的操作。 |
has_key() |
檢查request.GET or request.POST中是否包含參數指定的Key。 |
get_full_path() |
返回包含查詢字符串的請求路徑。例如, "/music/bands/the_beatles/?print=true" |
is_secure() |
如果請求是安全的,返回True,就是說,發出的是HTTPS請求。 |
3. QueryDict 對象
在 HttpRequest 對象中, GET 和 POST 屬性是 django.http.QueryDict 類的實例。
QueryDict 類似字典的自定義類,用來處理單鍵對應多值的情況。
QueryDict 實現所有標准的詞典方法。還包括一些特有的方法:
方法 |
描述 |
__getitem__ |
和標准字典的處理有一點不同,就是,如果Key對應多個Value,__getitem__()返回最后一個value。 |
__setitem__ |
設置參數指定key的value列表(一個Python list)。注意:它只能在一個mutable QueryDict 對象上被調用(就是通過copy()產生的一個QueryDict對象的拷貝). |
get() |
如果key對應多個value,get()返回最后一個value。 |
update() |
參數可以是QueryDict,也可以是標准字典。和標准字典的update方法不同,該方法添加字典 items,而不是替換它們: >>> q = QueryDict('a=1') >>> q = q.copy() # to make it mutable >>> q.update({'a': '2'}) >>> q.getlist('a') ['1', '2'] >>> q['a'] # returns the last ['2'] |
items() |
和標准字典的items()方法有一點不同,該方法使用單值邏輯的__getitem__(): >>> q = QueryDict('a=1&a=2&a=3') >>> q.items() [('a', '3')] |
values() |
和標准字典的values()方法有一點不同,該方法使用單值邏輯的__getitem__(): |
此外, QueryDict也有一些方法,如下表:
方法 |
描述 |
copy() |
返回對象的拷貝,內部實現是用Python標准庫的copy.deepcopy()。該拷貝是mutable(可更改的) — 就是說,可以更改該拷貝的值。 |
getlist(key) |
返回和參數key對應的所有值,作為一個Python list返回。如果key不存在,則返回空list。 It's guaranteed to return a list of some sort.. |
setlist(key,list_) |
設置key的值為list_ (unlike __setitem__()). |
appendlist(key,item) |
添加item到和key關聯的內部list. |
setlistdefault(key,list) |
和setdefault有一點不同,它接受list而不是單個value作為參數。 |
lists() |
和items()有一點不同, 它會返回key的所有值,作為一個list, 例如: >>> q = QueryDict('a=1&a=2&a=3') >>> q.lists() [('a', ['1', '2', '3'])] |
urlencode() |
返回一個以查詢字符串格式進行格式化后的字符串(e.g., "a=2&b=3&b=5"). |
七、Django Admin 管理工具
Django 提供了基於 web 的管理工具。
Django 自動管理工具是 django.contrib 的一部分。
可以在項目的 settings.py 中的 INSTALLED_APPS 看到它:

django.contrib 是一套龐大的功能集,它是 Django 基本代碼的組成部分。
1. 激活管理工具
通常我們在生成項目時會在 urls.py 中自動設置好,我們只需去掉注釋即可。
配置項如下所示:

當這一切都配置好后,Django 管理工具就可以運行了。
2. 使用管理工具
啟動開發服務器,然后在瀏覽器中訪問 http://127.0.0.1:8000/admin/,得到如下界面:

3. 創建超級用戶
通過命令 python manage.py createsuperuser 來創建超級用戶,如下所示:

4. 登錄
輸入用戶名密碼登錄,界面如下:

5.注冊數據模型到
為了讓 admin 界面管理某個數據模型,需要先注冊該數據模型到 admin。
修改 TestModel/admin.py:
1 from django.contrib import admin
2 from TestModel.models import Test
3
4 # Register your models here.
5 admin.site.register(Test)
刷新后即可看到 Testmodel 數據表:

6. 復雜模型
管理頁面的功能強大,完全有能力處理更加復雜的數據模型。
1)在 TestModel/models.py 中增加一個更復雜的數據模型:
1 from django.db import models
2
3 class Test(models.Model):
4 name = models.CharField(max_length=20)
5
6 class Contact(models.Model):
7 name = models.CharField(max_length=200)
8 age = models.IntegerField(default=0)
9 email = models.EmailField()
10
11 def __unicode__(self):
12 return self.name
13
14 class Tag(models.Model):
15 contact = models.ForeignKey(Contact)
16 name = models.CharField(max_length=50)
17
18 def __unicode__(self):
19 return self.name
這里有兩個表。
Tag 以 Contact 為外部鍵。一個 Contact 可以對應多個 Tag。
我們還可以看到許多在之前沒有見過的屬性類型,比如 IntegerField 用於存儲整數。

2)在 TestModel/admin.py 注冊多個模型並顯示:
1 from django.contrib import admin
2 from TestModel.models import Test,Contact,Tag
3
4 admin.site.register([Test, Contact, Tag])
3)刷新管理頁面
顯示結果如下:

附:如果你之前還未創建表結構,可使用以下命令創建:
$ python manage.py makemigrations TestModel # 讓 Django 知道我們在我們的模型有一些變更
$ python manage.py migrate TestModel # 創建表結構
7. 自定義表單
1)用自定義管理頁面取代默認的頁面
比如上面的 "add" 頁面,只顯示 name 和 email 部分,修改 TestModel/admin.py 如下:
1 from django.contrib import admin
2 from TestModel.models import Test, Contact, Tag
3
4 class ContactAdmin(admin.ModelAdmin):
5 fields = ('name', 'email')
6
7 admin.site.register(Contact, ContactAdmin)
8 admin.site.register([Test, Tag])
以上代碼定義了一個 ContactAdmin 類,用以說明管理頁面的顯示格式。
里面的 fields 屬性定義了要顯示的字段。
由於該類對應的是 Contact 數據模型,在注冊的時候,需要將它們一起注冊。顯示效果如下:

2)將輸入欄分塊
每個欄也可以定義自己的格式。修改 TestModel/admin.py為:
1 from django.contrib import admin
2 from TestModel.models import Test,Contact,Tag
3
4 # Register your models here.
5 class ContactAdmin(admin.ModelAdmin):
6 fieldsets = (
7 ['Main',{
8 'fields':('name','email'),
9 }],
10 ['Advance',{
11 'classes': ('collapse',), # CSS
12 'fields': ('age',),
13 }]
14 )
15
16 admin.site.register(Contact, ContactAdmin)
17 admin.site.register([Test, Tag])
上面的欄目分為了 Main 和 Advance 兩部分。
classes 說明它所在的部分的 CSS 格式。這里讓 Advance 部分隱藏:

Advance 部分旁邊有一個 Show 按鈕,用於展開,展開后可點擊 Hide 將其隱藏,如下圖所示:

7. 內聯(Inline)顯示
上面的 Contact 是 Tag 的外部鍵,所以有外部參考的關系。
而在默認的頁面顯示中,將兩者分離開來,無法體現出兩者的從屬關系。我們可以使用內聯顯示,讓 Tag 附加在 Contact 的編輯頁面上顯示。
修改TestModel/admin.py:
1 from django.contrib import admin
2 from TestModel.models import Test,Contact,Tag
3
4 # Register your models here.
5 class TagInline(admin.TabularInline):
6 model = Tag
7
8 class ContactAdmin(admin.ModelAdmin):
9 inlines = [TagInline] # Inline
10 fieldsets = (
11 ['Main',{
12 'fields':('name','email'),
13 }],
14 ['Advance',{
15 'classes': ('collapse',),
16 'fields': ('age',),
17 }]
18
19 )
20
21 admin.site.register(Contact, ContactAdmin)
22 admin.site.register([Test])
顯示效果如下:

8. 列表頁的顯示
在 Contact 輸入數條記錄后,Contact 的列表頁看起來如下:

也可以自定義該頁面的顯示,比如在列表中顯示更多的欄目,只需要在 ContactAdmin 中增加 list_display 屬性:
1 from django.contrib import admin
2 from TestModel.models import Test,Contact,Tag
3
4 # Register your models here.
5 class TagInline(admin.TabularInline):
6 model = Tag
7
8 class ContactAdmin(admin.ModelAdmin):
9 list_display = ('name','age', 'email') # list
10 inlines = [TagInline] # Inline
11 fieldsets = (
12 ['Main',{
13 'fields':('name','email'),
14 }],
15 ['Advance',{
16 'classes': ('collapse',),
17 'fields': ('age',),
18 }]
19
20 )
21
22 admin.site.register(Contact, ContactAdmin)
23 admin.site.register([Test])
刷新頁面顯示效果如下:

9. 搜索功能
搜索功能在管理大量記錄時非常有,可以使用 search_fields 為該列表頁增加搜索欄:
1 from django.contrib import admin
2 from TestModel.models import Test,Contact,Tag
3
4 # Register your models here.
5 class TagInline(admin.TabularInline):
6 model = Tag
7
8 class ContactAdmin(admin.ModelAdmin):
9 list_display = ('name','age', 'email') # list
10 search_fields = ('name',)
11 inlines = [TagInline] # Inline
12 fieldsets = (
13 ['Main',{
14 'fields':('name','email'),
15 }],
16 ['Advance',{
17 'classes': ('collapse',),
18 'fields': ('age',),
19 }]
20
21 )
22
23 admin.site.register(Contact, ContactAdmin)
24 admin.site.register([Test])
在本實例中搜索了 name 為 James 的記錄,顯示結果如下:

八、Django Nginx+uwsgi 安裝配置
在前面的章節中使用 python manage.py runserver 來運行服務器,這只適用測試環境中使用。
正式發布的服務,需要一個可以穩定而持續的服務器,比如 apache, Nginx, lighttpd 等,本文將以 Nginx 為例。
1. 安裝基礎開發包
Centos 下安裝步驟如下:
# yum groupinstall "Development tools"
# yum install zlib-devel bzip2-devel pcre-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel
# yum install python-devel
2. 安裝 Python 包管理
1)easy_install 包
下載地址:https://pypi.python.org/pypi/distribute
安裝步驟:
# tar zxvf distribute-0.6.49.tar.gz
# cd distribute-0.6.49
# python setup.py install
版本測試:
返回信息:

2)pip 包:
下載地址:https://pypi.python.org/pypi/pip
安裝步驟:
# tar zxvf pip-9.0.1.tar.gz
# cd pip-9.0.1
# python setup.py install
版本測試:
返回信息:

3. 安裝 uwsgi
1)安裝
uwsgi 下載地址:https://pypi.python.org/pypi/uWSGI
uwsgi 參數詳解:http://uwsgi-docs.readthedocs.org/en/latest/Options.html
安裝步驟:
# tar zxvf uwsgi-2.0.14.tar.gz
# cd uwsgi-2.0.14
# python setup.py install
2)測試
測試版本:
返回信息:

測試 uwsgi 是否正常(安裝的主機IP為:192.168.6.128):
新建 test.py 文件,內容如下:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return "Hello World"
然后在終端運行:
# uwsgi --http :8001 --wsgi-file test.py
返回信息:

在瀏覽器內輸入:http://192.168.6.128:8001

終端日志返回:

4. 安裝 Django
參照上述 Django 安裝過程進行安裝。
測試 django 是否正常,運行:
# django-admin.py startproject demosite
# cd demosite
# python manage.py runserver 0.0.0.0:8000
修改創建的項目中的 setting.py 文件:ALLOWED_HOSTS = ['*']
在瀏覽器內輸入:http://192.168.6.128:8000

5. 安裝 Nginx
參照 Nginx【第一篇】安裝 進行安裝。
6. uwsgi 配置
uwsgi 支持 ini、xml 等多種配置方式,本文以 ini 為例, 在/ect/目錄下新建 uwsgi9090.ini,添加如下配置:
1 [uwsgi]
2 socket = 127.0.0.1:9090
3 master = true #主進程
4 vhost = true #多站模式
5 no-site = true #多站模式時不設置入口模塊和文件
6 workers = 2 #子進程數
7 reload-mercy = 10
8 vacuum = true #退出、重啟時清理文件
9 max-requests = 1000
10 limit-as = 512
11 buffer-size = 30000
12 pidfile = /var/run/uwsgi9090.pid #pid文件,用於下面的腳本啟動、停止該進程
13 daemonize = /website/uwsgi9090.log
7. Nginx 配置
找到 nginx 的安裝目錄(如:/usr/local/nginx/),打開 conf/nginx.conf 文件,修改 server 配置:
1 server {
2 listen 80;
3 server_name localhost;
4
5 location / {
6 include uwsgi_params;
7 uwsgi_pass 127.0.0.1:9090; # 必須和uwsgi中的設置一致
8 uwsgi_param UWSGI_SCRIPT demosite.wsgi; # 入口文件,即 wsgi.py 相對於項目根目錄的位置,“.”相當於一層目錄
9 uwsgi_param UWSGI_CHDIR /demosite; # 項目根目錄
10 index index.html index.htm;
11 client_max_body_size 35m;
12 }
13 }
8. 測試
設置完成后,在終端運行:
# uwsgi --ini /etc/uwsgi9090.ini &
# /usr/local/nginx/sbin/nginx
在瀏覽器輸入:http://IP:PORT,就可以看到 django 的 "It work" 了。