Django web編程1 -- 建立項目和應用

python:3.7.2html

Django:2.1.7python

一、建立虛擬環境

虛擬環境是系統的一個位置,能夠在其中安裝包,並將其與其餘python包隔離。web

建立目錄,命名爲learning_log,並切換到這個目錄下,並建立一個虛擬環境。正則表達式

$ mkdir learning_log
$ cd learning_log/
learning_log$ python3 -m venv ll_env

二、激活虛擬環境並安裝Django

learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ pip3 install Django

三、新建項目

在處於活動的虛擬環境的狀況下(ll_env包含在括號內,如下的步驟都是在虛擬環境下),執行以下命令來新建項目:sql

(ll_env)learning_log$ django-admin.py startproject learning_log .  # 建立項目,點號是讓新項目使用合適的目錄結構,不能缺乏。
(ll_env)learning_log$ ls   # Django新建了一個名爲learning_log的目錄。它還建立了一個名爲manage.py的文件
learning_log ll_env manage.py
(ll_env)learning_log$ ls learning_log  # learning_log包含4個文件
__init__.py settings.py urls.py wsgi.py

settings.py:指定Django如何與你的系統交互以及如何管理項目。在開發項目的過程當中,咱們將修改其中一些設置,並添加一些設置。shell

urls.py:告訴Django應建立哪些網頁來響應瀏覽器請求。數據庫

wsgi.py:幫助Django提供它建立的文件,這個文件名是web server gateway interface(Web服務器網關接口 )的首字母縮寫。django

四、建立數據庫

(ll_env)learning_log$ python3 manage.py migrate
Operations to perform:...

將修改數據庫稱爲遷移數據庫。首次執行命令migrate 時,將讓Django確保數據庫與項目的當前狀態匹配。Django將新建一個數據庫。Django指出它將建立必要的數據庫表,用於存儲咱們將在這個項目(Synchronize unmigrated apps,同步未遷移的應用程序 )中使用的 信息,再確保數據庫結構與當前代碼(Applyallmigrations,應用全部的遷移 )匹配。編程

(ll_env)learning_log$ ls
db.sqlite3 learning_log ll_env manage.py

咱們運行了命令ls ,其輸出代表Django又建立了一個文件——db.sqlite3。SQLite是一種使用單個文件的數據庫,是編寫簡單應用程序的理想選擇,由於它讓你不用太關 注數據庫管理的問題。瀏覽器

五、查看項目

(ll_env)learning_log$ python3 manage.py runserver 0.0.0.0:405   # 容許全部IP地址訪問,使用405端口
Performing system checks...

System check identified no issues (0 silenced).    # 檢查確認正確地建立了項目
March 06, 2019 - 01:45:25
Django version 2.1.7, using settings 'learning_log.settings'   # Django版本以及設置文件的名稱
Starting development server at http://0.0.0.0:405/   # 訪問地址和端口,若是出現端口占用,則嘗試其餘端口
Quit the server with CONTROL-C.

六、建立應用程序

新開另外一個終端窗口,並切換到manage.py所在的目錄,激活該虛擬環境,並執行命令startapp。

learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ python3 manage.py startapp learning_logs   # 建立應用程序
(ll_env)learning_log$ ls    #  新增了文件夾learning_logs
db.sqlite3 learning_log learning_logs ll_env manage.py 
(ll_env)learning_log$ ls learning_logs/     # 最重要的文件是models.py、admin.py和views.py
admin.py __init__.py migrations models.py tests.py views.py

 七、定義模型

模型models.py(在learning_logs目錄下面)用於定義咱們要在應用程序中管理的數據。在代碼層面,模型就是一個類,就像前面討論的每一個類同樣,包含屬性 和方法。下面是表示用戶將要存儲的主題的模型:

from django.db import models

class Topic(models.Model):    # 建立Topic主題的類
    """用戶學習的主題"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):    # 默認應使用哪一個屬性來顯示有關主題的信息,若是是python2.7,應調用__unicode__()
        """返回模型的字符串表示"""
        return self.text
  • text屬性:CharField——由字符或文本組成的數據,適用於須要存儲少許的文本,如名稱、標題或城市。定義CharField 屬性時,必須告訴Django該在數據庫中預留多少空間。在這裏,咱們將max_length 設置成了200(即200個字符)
  • date_added 是一個DateTimeField ——記錄日期和時間的數據。咱們傳遞了實參auto_add_now=True ,每當用戶建立新主題時,這都讓Django將這個屬性自動設置成當前日期和時間。
  • __str__():默認應使用哪一個屬性來顯示有關主題的信息。這裏返回的是text中的字符串。

其餘的屬性能夠參考:https://docs.djangoproject.com/en/1.8/ref/models/fields/

八、激活模型

須要在learning_log文件夾修改settings.py文件,告訴Django哪些應用程序安裝到learning_log項目中。

請將INSTALLED_APPS(這是個元組) 修改爲下面這樣,將前面的應用程序名稱添加到這個元組中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 個人應用程序
    'learning_logs',
]

接下來,須要讓Django修改數據庫,使其可以存儲與模型Topic 相關的信息。爲此,在終端窗口中執行下面的命令:

(ll_env)learning_log$ python3 manage.py makemigrations learning_logs 
Migrations for 'learning_logs': 0001_initial.py: - Create model Topic

命令makemigrations 讓Django肯定該如何修改數據庫,使其可以存儲與咱們定義的新模型相關聯的數據。輸出代表Django建立了一個名爲0001_initial.py的遷移文件,這個文件將在數據庫中爲模型Topic 建立一個表。
下面來應用這種遷移,讓Django替咱們修改數據庫:

(ll_env)learning_log$ python3 manage.py migrate
--snip--
Running migrations:
Rendering model states... DONE
Applying learning_logs.0001_initial... OK    # 應用遷移正常

每當須要修改「學習筆記」管理的數據時,都採起以下三個步驟:

  • 修改models.py;
  • 對learning_logs 調用makemigrations ;
  • 讓Django遷移項目。

九、Django管理網站

(1)建立超級用戶:建立具有全部權限的用戶。

(ll_env)learning_log$ python3 manage.py createsuperuser

(2)向管理網站註冊模型:咱們建立應用程序learning_logs 時,Django在models.py所在的目錄中建立了一個名爲admin.py的文件。爲向管理網站註冊Topic ,請在admin.py輸入下面的代碼:

from django.contrib import admin

from learning_logs.models import Topic
admin.site.register(Topic)

如今,使用超級用戶帳戶訪問管理網站:訪問http://localhost:8000/admin/ ,並輸入你剛建立的超級用戶的用戶名和密碼,你將看到相似於下圖所示的屏幕。這個網頁讓你可以添加和修改用戶和用戶組,還能夠管理與剛纔定義的模型Topic 相關的數據。

(3)添加主題:向管理網站註冊Topic 後,咱們來添加第一個主題。爲此,單擊Topics進入主題網頁,它幾乎是空的,這是由於咱們尚未添加任何主題。單擊Add,你將看到一個用於添加新主題的表單。在第一個方框中輸入Chess ,再單擊Save,這將返回到主題管理頁面,其中包含剛建立的主題。

十、定義模型Entry

修改models.py中的代碼:

# Create your models here.


class Topic(models.Model):
    """用戶學習的主題"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.text


class Entry(models.Model):  #  繼承了Django基類Model 
    """學到的有關某個主題的具體指示"""

    topic = models.ForeignKey(Topic,on_delete=models.CASCADE)  # 外鍵。每一個主題建立時,都給它分配了一個鍵(或ID).  
    text = models.TextField()    # 不須要長度限制
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:  # 用於管理模型的額外信息,在須要時使用Entries來表示多個條目。若沒有,將使用Entrys來表示多個條目。
        verbose_name_plural = 'entries'

    def __str__(self):    # 只呈現text前50個字符。
        """返回模型的字符串表示"""
        return self.text[:50] + "..."

十一、遷移模型Entry

因爲咱們添加了一個新模型,所以須要再次遷移數據庫。

將慢慢地對這個過程瞭如指掌:

  • 修改models.py
  • 執行命令python manage.py makemigrations app_name
  • 再執行命令python manage.py migrate。
(ll_env)learning_log$ python3 manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0002_entry.py  # 生成了一個新的遷移文件0002_...
    - Create model Entry
(ll_env)learning_log$ python3 manage.py migrate

十二、向管理網站註冊Entry

咱們還須要註冊模型Entry 。爲此,須要將admin.py修改爲相似於下面這樣:

from django.contrib import admin

from learning_logs.models import Topic, Entry

admin.site.register(Topic)
admin.site.register(Entry)

返回到http://localhost:405/admin/learning_logs/ ,你將看到learning_logs下列出了Entries:

單擊Entries的Add連接,或者單擊Entries再選擇Add entry。你將看到一個下拉列表,讓你可以選擇要爲哪一個主題創 建條目,還有一個用於輸入條目的文本框。從下拉列表中選擇Chess,並添加一個條目(略)。

1三、Django shell

輸入一些數據後,就可經過交互式終端會話以編程方式查看這些數據了。命令python manage.py shell啓動一個Python解釋器,可以使用它來探索存儲在項目數據庫中的數據。

(ll_env)learning_log$ python3 manage.py shell
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
... 
1 Chess
2 Rock Climbing
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'>>> t.date_added
datetime.datetime(2019, 3, 7, 2, 14, 27, 770273, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry: In the opening phase of the game, it's important t...>]>

1四、建立網頁

使用Django建立網頁的過程一般分三個階段:定義URL、編寫視圖和編寫模板。首先,你必須定義URL模式。URL模式描述了URL是如何設計的,讓Django知道如何將瀏覽器請求 與網站URL匹配,以肯定返回哪一個網頁。

每一個URL都被映射到特定的視圖 ——視圖函數獲取並處理網頁所需的數據。視圖函數一般調用一個模板,後者生成瀏覽器可以理解的網頁。爲明白其中的工做原理,咱們來建立 學習筆記的主頁。咱們將定義該主頁的URL、編寫其視圖函數並建立一個簡單的模板。

(1)映射URL

用戶經過在瀏覽器中輸入URL以及單擊連接來請求網頁,所以咱們須要肯定項目須要哪些URL。主頁的URL最重要,它是用戶用來訪問項目的基礎URL。當前,基礎
URL(http://localhost:8000/)返回默認的Django網站,讓咱們知道正確地創建了項目。咱們將修改這一點,將這個基礎URL映射到「學習筆記」的主頁。

打開項目主文件夾learning_log中的文件urls.py,咱們須要在原來的基礎上包含learning_logs的URL:

from django.contrib import admin
from django.conf.urls import url, include

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include('learning_logs.urls',namespace='learning_logs')),  # 包含earning_logs.urls內容
]

在文件夾learning_logs中建立另外一個urls.py文件:

"""定義learning_logs的URL模式"""

from django.conf.urls import url   # 函數url用於建立URL映射到視圖

from . import views    # 當前的urls.py模塊所在的文件夾中導入視圖

app_name='learning_logs'  # 防止出現錯誤:Specifying a namespace in include() without providing an app_name

urlpatterns = [
    # 主頁
    url(r'^$', views.index, name='index'),  
]

url()函數接受三個實參:

  • 第一個是一個正則表達式,查找找開頭和末尾之間沒有任何東西的URL;
  • 第二個指定了要調用的視圖函數(下節編寫);
  • 第三個實參將 這個URL模式的名稱指定爲index,讓咱們可以在代碼的其餘地方引用它。每當須要提供到這個主頁的連接時,咱們都將使用這個名稱,而不編寫URL。

(2)編寫視圖

修改learning_logs中的文件views.py文件:

from django.shortcuts import render

def index(request):
    """學習筆記的主頁"""
    return render(request, 'learning_logs/index.html')

URL請求與咱們剛纔定義的模式匹配時,Django將在文件views.py中查找函數index() ,再將請求對象傳遞給這個視圖函數。在這裏,咱們不須要處理任何數據,所以這個函數只 包含調用render() 的代碼。這裏向函數render() 提供了兩個實參:原始請求對象以及一個可用於建立網頁的模板。下面來編寫這個模板。

(3)編寫模板

模板定義了網頁的結構。模板指定了網頁是什麼樣的,而每當網頁被請求時,Django將填入相關的數據。模板讓你可以訪問視圖提供的任何數據。咱們的主頁視圖沒有提供任何數據,所以相應的模板很是簡單。

在文件夾learning_logs中新建一個文件夾,並將其命名爲templates。在文件夾templates中,再新建一個文件夾,並將其命名爲learning_logs。這好像有點多餘(咱們在文件夾 learning_logs中建立了文件夾templates,又在這個文件夾中建立了文件夾learning_logs),但創建了Django可以明確解讀的結構,即使項目很大,包含不少應用程序亦如此。在最裏面 的文件夾learning_logs中,新建一個文件,並將其命名爲index.html,再在這個文件中編寫以下代碼:

<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>

如今,若是你請求這個項目的基礎URL——http://localhost:8000/,將看到剛纔建立的網頁,而不是默認的Django網頁。Django接受請求的URL,發現該URL與模式r'^$' 匹配,所以 調用函數views.index() ,這將使用index.html包含的模板來渲染網頁,結果以下圖所示。

 1五、建立其餘網頁

 咱們將建立兩個顯示數據的網頁,其中一個列出全部的主題,另外一個顯示特定主題的全部條目。對於每一個網頁,咱們 都將指定URL模式,編寫一個視圖函數,並編寫一個模板。但這樣作以前,咱們先建立一個父模板,項目中的其餘模板都將繼承它。

15.1 模板繼承

建立網站時,幾乎都有一些全部網頁都將包含的元素。在這種狀況下,可編寫一個包含通用元素的父模板,並讓每一個網頁都繼承這個模板,而沒必要在每一個網頁中重複定義這些通
用元素。這種方法能讓你專一於開發每一個網頁的獨特方面,還能讓修改項目的總體外觀容易得多。

(1)父模板

咱們首先來建立一個名爲base.html的模板,並將其存儲在index.html所在的目錄中。這個文件包含全部頁面都有的元素;其餘的模板都繼承base.html。當前,全部頁面都包含的元素 只有頂端的標題。咱們將在每一個頁面中包含這個模板,所以咱們將這個標題設置爲到主頁的連接:

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>

{% block content %}{% endblock content %}

這個文件的第一部分建立一個包含項目名的段落,該段落也是一個到主頁的連接。爲建立連接,咱們使用了一個模板標籤 ,它是用大括號和百分號({% %} )表示的。模板標籤是一小段代碼,生成要在網頁中顯示的信息。在這個實例中,模板標籤{% url 'learning_logs:index' %}生成一個URL,該URL與learning_logs/urls.py中定義的名 爲index 的URL模式匹配。在這個示例中,learning_logs 是一個命名空間 ,而index 是該命名空間中一個名稱獨特的URL模式。

咱們插入了一對塊標籤。這個塊名爲content ,是一個佔位符,其中包含的信息將由子模板指定。子模板並不是必須定義父模板中的每一個塊,所以在父模板中,可以使用任意多個塊來預留空間,而子模板可根據須要定義相應數量的塊。

在Python代碼中,咱們幾乎老是縮進四個空格。相比於Python文件,模板文件的縮進層級更多,所以每一個層級一般只縮進兩個空格。

(2)子模塊

如今須要從新編寫index.html,使其繼承base.html,以下所示:

{% extends "learning_logs/base.html" %}

{% block content %}
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
{% endblock content %}

若是將這些代碼與原來的index.html進行比較,可發現咱們將標題LearningLog替換成了從父模板那裏繼承的代碼。子模板的第一行必須包含標籤{% extends %},讓 Django知道它繼承了哪一個父模板。文件base.html位於文件夾learning_logs中,所以父模板路徑中包含learning_logs。這行代碼導入模板base.html的全部內容,讓index.html可以指定要 在content 塊預留的空間中添加的內容。
咱們插入了一個名爲content的{% block %}標籤,以定義content塊。不是從父模板繼承的內容都包含在content塊中,在這裏是一個描述項目「學習筆記」的 段落。咱們使用標籤{% endblock content %}指出了內容定義的結束位置。
模板繼承的優勢開始顯現出來了:在子模板中,只需包含當前網頁特有的內容。這不只簡化了每一個模板,還使得網站修改起來容易得多。要修改不少網頁都包含的元素,只需在父模板中修改該元素,你所作的修改將傳導到繼承該父模板的每一個頁面。在包含數十乃至數百個網頁的項目中,這種結構使得網站改進起來容易並且快捷得多。
在大型項目中,一般有一個用於整個網站的父模板——base.html,且網站的每一個主要部分都有一個父模板。每一個部分的父模板都繼承base.html,而網站的每一個網 頁都繼承相應部分的父模板。這讓你可以輕鬆地修改整個網站的外觀、網站任何一部分的外觀以及任何一個網頁的外觀。這種配置提供了一種效率極高的工做方式, 讓你樂意不斷地去改進網站。

15.2 顯示全部主題的頁面

(1)URL模式:首先,咱們來定義顯示全部主題的頁面的URL。一般,使用一個簡單的URL片斷來指出網頁顯示的信息;咱們將使用單詞topics,所以URL http://localhost:8000/topics/將返回顯示全部 主題的頁面。下面演示了該如何修改learning_logs/urls.py:

"""定義learning_logs的URL模式"""

from django.conf.urls import url

from . import views
app_name='learning_logs'

urlpatterns = [
    # 主頁
    url(r'^$', views.index, name='index'),
    
    # 顯示全部的主題
    url(r'^topics/$', views.topics, name='topics'),
]

咱們只是在用於主頁URL的正則表達式中添加了topics/。Django檢查請求的URL時,這個模式與這樣的URL匹配:基礎URL後面跟着topics 。能夠在末尾包含斜 槓,也能夠省略它,但單詞topics 後面不能有任何東西,不然就與該模式不匹配。其URL與該模式匹配的請求都將交給views.py中的函數topics() 進行處理。

(2)視圖:函數topics() 須要從數據庫中獲取一些數據,並將其發送給模板。咱們須要在views.py中添加的代碼以下:

from django.shortcuts import render

from .models import Topic

def index(request):
    """學習筆記的主頁"""
    return render(request, 'learning_logs/index.html')

def topics(request):
    """顯示全部的主題"""
    topics = Topic.objects.order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

咱們首先導入了與所需數據相關聯的模型。

函數topics() 包含一個形參:Django從服務器那裏收到的request 對象。咱們查詢數據庫——請求提供Topic 對象,並按屬性date_added 對它們進行排序。咱們將返回的查詢集存儲在topics 中。
咱們定義了一個將要發送給模板的上下文。上下文是一個字典,其中的鍵是咱們將在模板中用來訪問數據的名稱,而值是咱們要發送給模板的數據。在這裏,只有一個 鍵—值對,它包含咱們將在網頁中顯示的一組主題。建立使用數據的網頁時,除對象request 和模板的路徑外,咱們還將變量context 傳遞給render() 。

(3)模板:顯示全部主題的頁面的模板接受字典context ,以便可以使用topics() 提供的數據。請建立一個文件,將其命名爲topics.html,並存儲到index.html所在的目錄中。下面演示瞭如何在這個模板中顯示主題:

{% extends "learning_logs/base.html" %}

{% block content %}

<p>Topics</p>
  <ul>
    {% for topic in topics %}
      <li>{{ topic }}</li>
      {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>

{% endblock content %}

就像模板index.html同樣,咱們首先使用標籤{% extends %}來繼承base.html,再開始定義content塊。這個網頁的主體是一個項目列表,其中列出了用戶輸入的主題。在標準 HTML中,項目列表被稱爲無序列表,用標籤<ul></ul> 表示。
咱們使用了一個至關於for 循環的模板標籤,它遍歷字典context 中的列表topics 。模板中使用的代碼與Python代碼存在一些重要差異:Python使用縮進來指出哪些 代碼行是for循環的組成部分,而在模板中,每一個for循環都必須使用{% endfor %}標籤來顯式地指出其結束位置。所以在模板中,循環相似於下面這樣:

{% for item in list %}
  do something with each item
{% endfor %}

在循環中,咱們要將每一個主題轉換爲一個項目列表項。要在模板中打印變量,須要將變量名用雙花括號括起來。每次循環時,代碼{{ topic }}都被替換爲topic的當 前值。這些花括號不會出如今網頁中,它們只是用於告訴Django咱們使用了一個模板變量。HTML標籤<li></li> 表示一個項目列表項,在標籤對<ul></ul> 內部,位於標 籤<li> 和</li> 之間的內容都是一個項目列表項。
咱們使用了模板標籤{% empty %},它告訴Django在列表topics爲空時該怎麼辦:這裏是打印一條消息,告訴用戶尚未添加任何主題。最後兩行分別結束for循 環和項目列表。
如今須要修改父模板base.html,使其包含到顯示全部主題的頁面的連接:

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a> -
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>

{% block content %}{% endblock content %}

咱們在到主頁的連接後面添加了一個連字符,而後添加了一個到顯示全部主題的頁面的連接——使用的也是模板標籤url 。這一行讓Django生成一個連接,它 與learning_logs/ urls.py中名爲topics 的URL模式匹配。
如今若是你刷新瀏覽器中的主頁,將看到連接Topics。單擊這個連接,將看到相似於圖18-4所示的網頁。

 15.3 顯示特定主題的頁面

一、URL模式

顯示特定主題的頁面的URL模式與前面的全部URL模式都稍有不一樣,由於它將使用主題的id 屬性來指出請求的是哪一個主題。例如,若是用戶要查看主題Chess(其id 爲1)的詳細頁面,URL將爲http://localhost:8000/topics/1/。下面是與這個URL匹配的模式,它包含在learning_logs/urls.py中:

"""定義learning_logs的URL模式"""

from django.conf.urls import url

from . import views
app_name='learning_logs'

urlpatterns = [
    # 主頁
    url(r'^$', views.index, name='index'),
    
    # 顯示全部的主題
    url(r'^topics/$', views.topics, name='topics'),

    # 制定主題的詳細頁面
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic')
]

r'^topics/(?P<topic_id>\d+)/$' 。

r 讓Django將這個字符串視爲原始字符串,並指出正則表達式包含在引號內。

(/(?P<topic_id>\d+)/ )與包含在兩個斜槓內的整數匹配,並將這個整數存儲在一個名爲topic_id 的實參中。這部分表達式兩邊的括號捕獲URL中的 值;?P<topic_id> 將匹配的值存儲到topic_id 中;而表達式\d+ 與包含在兩個斜杆內的任何數字都匹配,無論這個數字爲多少位。
發現URL與這個模式匹配時,Django將調用視圖函數topic() ,並將存儲在topic_id 中的值做爲實參傳遞給它。在這個函數中,咱們將使用topic_id 的值來獲取相應的主 題。

二、視圖

函數topic() 須要從數據庫中獲取指定的主題以及與之相關聯的全部條目,以下所示:

from django.shortcuts import render

from .models import Topic

def index(request):
    """學習筆記的主頁"""
    return render(request, 'learning_logs/index.html')

def topics(request):
    """顯示全部的主題"""
    topics = Topic.objects.order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

def topic(request, topic_id):
    """顯示特定主題的詳細頁面"""
    topic = Topic.objects.get(id=topic_id)  # 查詢
    entries = topic.entry_set.order_by('-date_added')  # 查詢
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

這是第一個除request 對象外還包含另外一個形參的視圖函數。這個函數接受正則表達式(?P<topic_id>\d+) 捕獲的值,並將其存儲到topic_id 中。

我 們使用get() 來獲取指定的主題,就像前面在Django shell中所作的那樣。

咱們獲取與該主題相關聯的條目,並將它們按date_added 排序:date_added 前面的減號 指定按降序排列,即先顯示最近的條目。咱們將主題和條目都存儲在字典context 中,再將這個字典發送給模板topic.html。
在本身的項目中編寫這樣的查詢時,先在Django shell中進行嘗試大有裨益。相比於編寫視 圖和模板,再在瀏覽器中檢查結果,在shell中執行代碼可更快地得到反饋。

(3)模板

這個模板topic.html須要顯示主題的名稱和條目的內容;若是當前主題不包含任何條目,咱們還需向用戶指出這一點:

{% extends 'learning_logs/base.html' %}

{% block content %}

<p>Topic: {{ topic }}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
  <li>
      <p>{{ entry.date_added|date:'M d, Y H:i' }}</p> 
      <p>{{ entry.text|linebreaks }}</p>
  </li>
  {% empty %}
  <li>
    There are no entries for this topic yet.
  </li>
  {% endfor %} 
</ul>
{% endblock content %}

像這個項目的其餘頁面同樣,這裏也繼承了base.html。接下來,咱們顯示當前的主題,它存儲在模板變量{{ topic }}中。爲何可使用變量topic呢?由於它包含在字典context 中。接下來,咱們開始定義一個顯示每一個條目的項目列表,並像前面顯示全部主題同樣遍歷條目。
每一個項目列表項都將列出兩項信息:條目的時間戳和完整的文本。爲列出時間戳,咱們顯示屬性date_added 的值。在Django模板中,豎線(| )表示模板過濾器—— 對模板變量的值進行修改的函數。過濾器date: 'M d, Y H:i'以這樣的格式顯示時間戳:January1,2015 23:00。接下來的一行顯示text的完整值,而不只僅是entry的前 50個字符。過濾器linebreaks將包含換行符的長條目轉換爲瀏覽器可以理解的格式,以避免顯示爲一個不間斷的文本塊。咱們使用模板標籤{% empty %}打 印一條消息,告訴用戶當前主題尚未條目。

(4) 將顯示全部主題的頁面中的每一個主題都設置爲連接

 在瀏覽器中查看顯示特定主題的頁面前,咱們須要修改模板topics.html,讓每一個主題都連接到相應的網頁,以下所示:

{% extends "learning_logs/base.html" %}

{% block content %}

<p>Topics</p>
  <ul>
    {% for topic in topics %}
      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
      </li>
      {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>

{% endblock content %}

咱們使用模板標籤url 根據learning_logs中名爲topic 的URL模式來生成合適的連接。這個URL模式要求提供實參topic_id ,所以咱們在模板標籤url 中添加了屬性topic.id 。如今,主題列表中的每一個主題都是一個連接,連接到顯示相應主題的頁面,如http://localhost:8000/topics/1/。
若是你刷新顯示全部主題的頁面,再單擊其中的一個主題,將看到相似於圖18-5所示的頁面。

 

參考資料:

一、python編程,從入門到實踐

相關文章
相關標籤/搜索