現(xiàn)在我們已經(jīng)建立了模型并且導入了一些數(shù)據(jù),現(xiàn)在我們要把這些連一起.我們將會弄清楚如何在視圖中訪問數(shù)據(jù)以及如何通過模板展示數(shù)據(jù).
1. 基本流程:數(shù)據(jù)驅(qū)動頁面
在Django中創(chuàng)建數(shù)據(jù)驅(qū)動頁面必須執(zhí)行以下5步.
- 首先,在你應用的views.py文件中導入你要添加的模型.
- 在視圖里訪問模型,導入你需要的數(shù)據(jù).
- 把模型的數(shù)據(jù)傳遞給模板.
- 設(shè)置模板給用戶呈現(xiàn)數(shù)據(jù).
- 如果還沒有映射URL,映射一下吧.
- 上面的步驟告訴你如何使用Django里的模型,視圖和模板.
2. 展示Rango主頁上的目錄
我們需要在rango的主頁顯示5個最多的目錄.
2.1 導入需要的模型
為了達到目的,我們需要完成上面的步驟.首先,打開rango/view.py并導入rango的models.py文件的Category模塊.
from rango.models import Category
2.2 修改index視圖
有了第一步,我們需要修改index()函數(shù).讓我們回想一下,這個index()函數(shù)負責管理主頁的視圖.修改如下.
def index(request):
category_list = Category.objects.order_by('-likes')[:5]
context_dict = {'categories': category_list}
return render(request, 'rango/index.html', context_dict)
這里我們做了第二步和第三步.首先,我們訪問Category模型得到5個最多的目錄.這里用order_by()方法對喜歡的數(shù)量進行降序排序 - 注意帶著-.最后我們?nèi)∏?個目錄保存到category_list
當訪問數(shù)據(jù)庫結(jié)束,我們把這個列表(category_list)傳給了字典context_dict.這個字典同時會作為render()的參數(shù)返回給模板.
2.3 修改index模板
修改完視圖后,最后剩下的就是更改rango/index.html模板了.代碼如下.
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Rango says...hello world!</h1>
{% if categories %}
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
<a href="/rango/about/">About</a>
</body>
</html>
這里我們用了Django模板語言里的if和for控制語句.在頁面的<body>里我們檢查categories是否為空(例如,{% if categories %}).
如果不為空,會建立一個無序HTML列表(在ul標簽里)
.for循環(huán)({% for category in categories %})會依次在li標簽里打印出每個目錄的名字({{ category.name }}).
如果不存在categories,將會輸出There are no categories present..
作為模板語言,所有的命令都包含在{%和%}標簽里,所有的變量都在{{和}}里.
如果訪問 http://127.0.0.1:8000/rango/ ,如下圖所示.
3. 創(chuàng)建詳細頁面
1. URL設(shè)計與映射
通過Rango的詳細描述,我們需要列出目錄的每個頁面.現(xiàn)在我們需要克服許多困難.我們需要創(chuàng)建一個新的視圖作為參數(shù).我們同事需要創(chuàng)建URL模式和URL字符串來對應每個目錄的名字.
讓我們著手解決URL問題.有一種方法是為我們的目錄在URL中設(shè)立唯一的ID,我們可以創(chuàng)建像/rango/category/1/或者/rango/category/2/,這里的數(shù)字1和2就是它們的ID.但是這樣做對我們來說不太好理解.盡管我們知道數(shù)字關(guān)聯(lián)著目錄,但我們怎么知道1和2代表哪個目錄呢?用戶不試一下就不會知道.
另一種方法就是用目錄名作為URL./rango/category/Python/將會返回給我們關(guān)于Python的目錄.這是一個簡單的,可讀的URl
2. 為Category表增加Slug字段.
為了建立簡潔的url我們需要在Category模型里增加slug字段.首先我們需要從django導入slugify函數(shù),這個函數(shù)的作用是把空格用連字符代替,例如"how do i create a slug in django"將會轉(zhuǎn)換成"how-do-i-create-a-slug-in-djang".
接下來我們將會重寫Category模型的save方法,我們將會調(diào)用slugify方法并更新slug字段.注意任何時候目錄名稱更改都會更改slug.像下面一樣修改模型.
from django.template.defaultfilters import slugify
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __str__(self):
return self.name
現(xiàn)在需要運行下面的命令更新模型和數(shù)據(jù)庫.
$ python3 manage.py makemigrations rango
$ python3 manage.py migrate
因為我們slug沒有設(shè)置默認值,而且模型中已經(jīng)加入進數(shù)據(jù),所以migrate命令將會給你兩個選項.選擇提供默認值選項并輸入默認值''.它會馬上進行修改.現(xiàn)在重新運行population腳本.因為每個目錄都會執(zhí)行save方法,所以重寫的save方法將會被執(zhí)行修改slug字段.運行Django服務,你講會在管理界面看到修改的數(shù)據(jù).
注意:這里原書會有錯誤,原因見http://stackoverflow.com/questions/27788456/integrityerror-column-slug-is-not-unique ,修改見 https://github.com/leifos/tango_with_django/issues/19
j
解決方法:
- 刪除db.sqlite3
- python manage.py makemigrations
選擇第一個盖矫,填一個默認值 - python3 manage.py migrate
在管理界面你或許希望在填寫目錄名的時候自動填充slug字段.按照下面的方法.
from django.contrib import admin
from rango.models import Category, Page
# Add in this class to customized the Admin Interface
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name',)}
# Update the registeration to include this customised interface
admin.site.register(Category, CategoryAdmin)
admin.site.register(Page)
在管理界面嘗試增加新的目錄.看到了吧!現(xiàn)在我們可以加入slug字段用作我們的url.
1. 目錄視圖
在rango/views.py中,我們需要導入Page模型.如下.
from rango.models import Page
下面我們將會加入我們的category()視圖:
def category(request, category_name_slug):
context_dict = {}
try:
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
pages = Page.objects.filter(category=category)
context_dict['pages'] = pages
context_dict['category'] = category
except Category.DoesNotExist:
pass
return render(request, 'rango/category.html', context_dict)
和index()視圖一樣我們的新視圖也要執(zhí)行同樣的基本步驟.我們需要定義一個字典,然后嘗試從模型中導出數(shù)據(jù),并把數(shù)據(jù)添加到字典里.我們通過參數(shù)category_name_slug的值來決定是哪個目錄.如果在Category模型中找到目錄,我們就會把context_dict字典傳遞給相關(guān)頁面.
2. 目錄模板
現(xiàn)在為我們的新視圖創(chuàng)建模板.在<workspace>/tango_with_django_project/templates/rango/目錄創(chuàng)建category.html.
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>{{ category_name }}</h1>
{% if category %}
{% if pages %}
<ul>
{% for page in pages %}
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<strong>No pages currently in category.</strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
</body>
</html>
上面的HTML代碼同樣給我們展示了如何把數(shù)據(jù)通過字典傳遞給模板.我們用到了category_name變量和category和pages對象.如果category在模板上下文并沒有定義,或者在數(shù)據(jù)庫并沒有發(fā)現(xiàn)這個目錄,那么就會提示一個友好的錯誤信息.相反的話如果存在,我們將會檢查pages.如果pages沒有被定義或者不存在元素,我們同樣也會呈現(xiàn)友好的錯誤提示.否則的話目錄里包含的頁面就會寫入HTML李彪.對于在pages列表的每個頁面我們都會展示它的title和url.
3. 參數(shù)化的URL映射
現(xiàn)在讓我們來看看如何把category_name_url參數(shù)值傳遞給category().我們需要修改rango的urls.py文件和urlpatterns元組.
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^about/$', views.about, name='about'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),] # New!
你能看到當正則表達式r'^(?P<category_name_slug>\w+)/$匹配時會調(diào)用view.category()函數(shù).我們的正則表達式會匹配URL斜杠前所有的字母數(shù)字(例如 a-z, A-Z, 或者 0-9)和連字符(-).然后把這個值作為category_name_slug參數(shù)傳遞給views.category(),這個參數(shù)必須在強制的request參數(shù)之后.
url(r'^category/(?P<category_name_slug>[\w-]+)/$', views.category, name='category') 我們可以從這里找到在category/和后面的/之間的字符串,并把它作為參數(shù)category_name_slug傳遞給views.category()參數(shù).例如,URLcategory/python-books/將會返回的category_name_slug參數(shù)是python-books. 需要知道的十,所有的視圖函數(shù)必須帶至少一個參數(shù).這個參數(shù)是request - 它會提供HTTP請求用戶的相關(guān)信息牵祟。當參數(shù)化URL時,可以給視圖添加已經(jīng)命名德爾參數(shù).使用上面的例子,我們的category視圖是這樣的. def category(request, category_name_slug): 附加參數(shù)的位置不重要,重要的是在URL模式中定義的參數(shù)名稱.注意如何為我們的視圖在URL模式匹配中定義category_name_slug參數(shù).
4. 修改index模板
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Rango says..hello world!</h1>
{% if categories %}
<ul>
{% for category in categories %}
<!-- Following line changed to add an HTML hyperlink -->
<li><a href="/rango/category/{{ category.slug }}">{{ category.name }}</a></li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
</body>
</html>
練習
代碼: