Django07模型,模板和視圖

現(xiàn)在我們已經(jīng)建立了模型并且導入了一些數(shù)據(jù),現(xiàn)在我們要把這些連一起.我們將會弄清楚如何在視圖中訪問數(shù)據(jù)以及如何通過模板展示數(shù)據(jù).

1. 基本流程:數(shù)據(jù)驅(qū)動頁面

在Django中創(chuàng)建數(shù)據(jù)驅(qū)動頁面必須執(zhí)行以下5步.

  1. 首先,在你應用的views.py文件中導入你要添加的模型.
  2. 在視圖里訪問模型,導入你需要的數(shù)據(jù).
  3. 把模型的數(shù)據(jù)傳遞給模板.
  4. 設(shè)置模板給用戶呈現(xiàn)數(shù)據(jù).
  5. 如果還沒有映射URL,映射一下吧.
  6. 上面的步驟告訴你如何使用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
解決方法:

  1. 刪除db.sqlite3
  2. python manage.py makemigrations
    選擇第一個盖矫,填一個默認值
  3. 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>
效果圖

練習

練習

代碼:

views
index.html
效果圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竹握,一起剝皮案震驚了整個濱河市峦阁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抛姑,老刑警劉巖赞厕,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異定硝,居然都是意外死亡坑傅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門喷斋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唁毒,“玉大人,你說我怎么就攤上這事星爪〗鳎” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵顽腾,是天一觀的道長近零。 經(jīng)常有香客問我,道長抄肖,這世上最難降的妖魔是什么久信? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮漓摩,結(jié)果婚禮上裙士,老公的妹妹穿的比我還像新娘。我一直安慰自己管毙,他們只是感情好腿椎,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著夭咬,像睡著了一般啃炸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卓舵,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天南用,我揣著相機與錄音,去河邊找鬼掏湾。 笑死裹虫,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的忘巧。 我是一名探鬼主播恒界,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼砚嘴!你這毒婦竟也來了十酣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤际长,失蹤者是張志新(化名)和其女友劉穎耸采,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體工育,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡虾宇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了如绸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘱朽。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡旭贬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搪泳,到底是詐尸還是另有隱情稀轨,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布岸军,位于F島的核電站奋刽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏艰赞。R本人自食惡果不足惜佣谐,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望方妖。 院中可真熱鬧狭魂,春花似錦、人聲如沸吁断。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仔役。三九已至掷伙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間又兵,已是汗流浹背任柜。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沛厨,地道東北人宙地。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像逆皮,于是被迫代替她去往敵國和親宅粥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容