Python系列19-Web應(yīng)用程序-Django入門(mén)

一.Django入門(mén)

當(dāng)今的網(wǎng)站實(shí)際上都是富應(yīng)用程序(rich application)唧龄,就像成熟的桌面應(yīng)用程序一樣。Python提供了一組開(kāi)發(fā)Web應(yīng)用程序的卓越工具摊溶。在本章中溅呢,你將學(xué)習(xí)如何使用Django(http://djangoproject.com/ )來(lái)開(kāi)發(fā)一個(gè)名為“學(xué)習(xí)筆記”(Learning Log)的項(xiàng)目,這是一個(gè)在線日志系統(tǒng)梆暖,讓你能夠記錄所學(xué)習(xí)的有關(guān)特定主題的知識(shí)。

我們將為這個(gè)項(xiàng)目制定規(guī)范掂骏,然后為應(yīng)用程序使用的數(shù)據(jù)定義模型轰驳。我們將使用Django的管理系統(tǒng)來(lái)輸入一些初始數(shù)據(jù),再學(xué)習(xí)編寫(xiě)視圖和模板芭挽,讓Django能夠?yàn)槲覀兊木W(wǎng)站創(chuàng)建網(wǎng)頁(yè)滑废。

Django是一個(gè)Web框架 ——一套用于幫助開(kāi)發(fā)交互式網(wǎng)站的工具。Django能夠響應(yīng)網(wǎng)頁(yè)請(qǐng)求袜爪,還能讓你更輕松地讀寫(xiě)數(shù)據(jù)庫(kù)蠕趁、管理用戶等。

1.1 建立項(xiàng)目

建立項(xiàng)目時(shí)辛馆,首先需要以規(guī)范的方式對(duì)項(xiàng)目進(jìn)行描述俺陋,再建立虛擬環(huán)境,以便在其中創(chuàng)建項(xiàng)目昙篙。

1.1.1 制定規(guī)范

完整的規(guī)范詳細(xì)說(shuō)明了項(xiàng)目的目標(biāo)腊状,闡述了項(xiàng)目的功能,并討論了項(xiàng)目的外觀和用戶界面苔可。與任何良好的項(xiàng)目規(guī)劃和商業(yè)計(jì)劃書(shū)一樣缴挖,規(guī)范應(yīng)突出重點(diǎn),幫助避免項(xiàng)目偏離軌道焚辅。這里不會(huì)制定完整的項(xiàng)目規(guī)劃映屋,而只列出一些明確的目標(biāo),以突出開(kāi)發(fā)的重點(diǎn)同蜻。我們制定的規(guī)范如下:

我們要編寫(xiě)一個(gè)名為“學(xué)習(xí)筆記”的Web應(yīng)用程序棚点,讓用戶能夠記錄感興趣的主題,并在學(xué)習(xí)每個(gè)主題的過(guò)程中添加日志條目湾蔓√蔽觯“學(xué)習(xí)筆記”的主頁(yè)對(duì)這個(gè)網(wǎng)站進(jìn)行描述,
并邀請(qǐng)用戶注冊(cè)或登錄默责。用戶登錄后贬循,就可創(chuàng)建新主題、添加新條目以及閱讀既有的條目桃序。

1.1.2 建立虛擬環(huán)境

要使用Django甘有,首先需要建立一個(gè)虛擬工作環(huán)境。虛擬環(huán)境 是系統(tǒng)的一個(gè)位置葡缰,你可以在其中安裝包亏掀,并將其與其他Python包隔離忱反。

為項(xiàng)目新建一個(gè)目錄,將其命名為my_learning_log滤愕,再在終端中切換到這個(gè)目錄温算,并創(chuàng)建一個(gè)虛擬環(huán)境。如果你使用的是Python 3间影,可使用如下命令來(lái)創(chuàng)建虛擬環(huán)境

代碼:

python -m venv ll_env

測(cè)試記錄:

C:\Users\Administrator>E:

E:\>cd E:\python\my_learning_log

E:\python\my_learning_log>python -m venv ll_env

E:\python\my_learning_log>

如報(bào)錯(cuò)注竿,參考下一章節(jié) 安裝virtualenv

1.1.3 安裝virtualenv

安裝virtualenv

C:\>pip install virtualenv
Collecting virtualenv
  Downloading virtualenv-20.4.3-py2.py3-none-any.whl (7.2 MB)
     |████████████████████████████████| 7.2 MB 21 kB/s
Collecting importlib-resources>=1.0
  Downloading importlib_resources-5.1.2-py3-none-any.whl (25 kB)
Requirement already satisfied: six<2,>=1.9.0 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from virtualenv) (1.12.0)
Collecting importlib-metadata>=0.12
  Downloading importlib_metadata-3.10.0-py3-none-any.whl (14 kB)
Collecting distlib<1,>=0.3.1
  Downloading distlib-0.3.1-py2.py3-none-any.whl (335 kB)
     |████████████████████████████████| 335 kB 15 kB/s
Collecting appdirs<2,>=1.4.3
  Downloading appdirs-1.4.4-py2.py3-none-any.whl (9.6 kB)
Collecting filelock<4,>=3.0.0
  Downloading filelock-3.0.12-py3-none-any.whl (7.6 kB)
Requirement already satisfied: typing-extensions>=3.6.4 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from importlib-metad
ata>=0.12->virtualenv) (3.7.2)
Collecting zipp>=0.5
  Downloading zipp-3.4.1-py3-none-any.whl (5.2 kB)
Installing collected packages: zipp, importlib-resources, importlib-metadata, filelock, distlib, appdirs, virtualenv
Successfully installed appdirs-1.4.4 distlib-0.3.1 filelock-3.0.12 importlib-metadata-3.10.0 importlib-resources-5.1.2 virtualenv-20.4.3 zipp-3.4.1

1.1.4 激活虛擬環(huán)境

建立虛擬環(huán)境后,需要使用下面的命令激活它:

-- 激活虛擬環(huán)境
ll_env\Scripts\activate
-- 關(guān)閉虛擬環(huán)境
deactivate

測(cè)試記錄:

E:\python\my_learning_log>ll_env\Scripts\activate
(ll_env) E:\python\my_learning_log>deactivate
E:\python\my_learning_log>

如果關(guān)閉運(yùn)行虛擬環(huán)境的終端魂贬,虛擬環(huán)境也將不再處于活動(dòng)狀態(tài)巩割。

1.1.5 安裝Django

創(chuàng)建并激活虛擬環(huán)境后,就可安裝Django了:

代碼:

pip install Django

測(cè)試記錄:

C:\Users\Administrator>E:

E:\>
E:\>cd E:\python\my_learning_log

E:\python\my_learning_log>pip install Django
Collecting Django
  Downloading Django-3.1.7-py3-none-any.whl (7.8 MB)
     |████████████████████████████████| 7.8 MB 1.6 MB/s
Collecting sqlparse>=0.2.2
  Downloading sqlparse-0.4.1-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 420 kB/s
Requirement already satisfied: pytz in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from Django) (2018.7)
Collecting asgiref<4,>=3.2.10
  Downloading asgiref-3.3.1-py3-none-any.whl (19 kB)
Installing collected packages: sqlparse, asgiref, Django
Successfully installed Django-3.1.7 asgiref-3.3.1 sqlparse-0.4.1

E:\python\my_learning_log>

由于我們是在虛擬環(huán)境中工作付燥,因此在所有的系統(tǒng)中宣谈,安裝Django的命令都相同:不需要指定標(biāo)志--user ,也無(wú)需使用python -m pip install package_name 這樣較長(zhǎng)的命令键科。

別忘了闻丑,Django僅在虛擬環(huán)境處于活動(dòng)狀態(tài)時(shí)才可用。

1.1.6 在Django中創(chuàng)建項(xiàng)目

在依然處于活動(dòng)的虛擬環(huán)境的情況下(ll_env包含在括號(hào)內(nèi))勋颖,執(zhí)行如下命令來(lái)新建一個(gè)項(xiàng)目

django-admin startproject my_learning_log .
dir
dir my_learning_log

測(cè)試記錄:

(ll_env) E:\python\my_learning_log>django-admin startproject learning_log .

(ll_env) E:\python\my_learning_log>
(ll_env) E:\python\my_learning_log>dir
 驅(qū)動(dòng)器 E 中的卷是 新加卷
 卷的序列號(hào)是 823D-B082

 E:\python\my_learning_log 的目錄

2021/04/01  15:59    <DIR>          .
2021/04/01  15:59    <DIR>          ..
2021/04/01  15:59    <DIR>          learning_log
2021/04/01  15:51    <DIR>          ll_env
2021/04/01  15:59               690 manage.py
               1 個(gè)文件            690 字節(jié)
               4 個(gè)目錄 56,977,850,368 可用字節(jié)

(ll_env) E:\python\my_learning_log>dir learning_log
 驅(qū)動(dòng)器 E 中的卷是 新加卷
 卷的序列號(hào)是 823D-B082

 E:\python\my_learning_log\learning_log 的目錄

2021/04/01  15:59    <DIR>          .
2021/04/01  15:59    <DIR>          ..
2021/04/01  15:59               417 asgi.py
2021/04/01  15:59             3,200 settings.py
2021/04/01  15:59               775 urls.py
2021/04/01  15:59               417 wsgi.py
2021/04/01  15:59                 0 __init__.py
               5 個(gè)文件          4,809 字節(jié)
               2 個(gè)目錄 56,977,850,368 可用字節(jié)

(ll_env) E:\python\my_learning_log>

1.1.7 創(chuàng)建數(shù)據(jù)庫(kù)

Django將大部分與項(xiàng)目相關(guān)的信息都存儲(chǔ)在數(shù)據(jù)庫(kù)中嗦嗡,因此我們需要?jiǎng)?chuàng)建一個(gè)供Django使用的數(shù)據(jù)庫(kù)。為給項(xiàng)目“學(xué)習(xí)筆記”創(chuàng)建數(shù)據(jù)庫(kù)饭玲,請(qǐng)?jiān)谔幱诨顒?dòng)虛擬環(huán)境中的情況下執(zhí)行下
面的命令:

python manage.py migrate
dir

測(cè)試記錄:

(ll_env) E:\python\my_learning_log>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

(ll_env) E:\python\my_learning_log>dir
 驅(qū)動(dòng)器 E 中的卷是 新加卷
 卷的序列號(hào)是 823D-B082

 E:\python\my_learning_log 的目錄

2021/04/01  16:42    <DIR>          .
2021/04/01  16:42    <DIR>          ..
2021/04/01  16:06    <DIR>          .idea
2021/04/01  16:42           131,072 db.sqlite3
2021/04/01  16:42    <DIR>          learning_log
2021/04/01  16:04    <DIR>          ll_env
2021/04/01  15:59               690 manage.py
               2 個(gè)文件        131,762 字節(jié)
               5 個(gè)目錄 56,942,923,776 可用字節(jié)

(ll_env) E:\python\my_learning_log>

我們將修改數(shù)據(jù)庫(kù)稱為遷移 數(shù)據(jù)庫(kù)侥祭。首次執(zhí)行命令migrate 時(shí),將讓Django確保數(shù)據(jù)庫(kù)與項(xiàng)目的當(dāng)前狀態(tài)匹配茄厘。在使用SQLite(后面將更詳細(xì)地介紹)的新項(xiàng)目中首次執(zhí)行這個(gè)命令時(shí)矮冬,Django將新建一個(gè)數(shù)據(jù)庫(kù)。Django指出它將創(chuàng)建必要的數(shù)據(jù)庫(kù)表蚕断,用于存儲(chǔ)我們將在這個(gè)項(xiàng)目(Synchronize unmigrated apps,同步未遷移的應(yīng)用程序 )中使用的信息入挣,再確保數(shù)據(jù)庫(kù)結(jié)構(gòu)與當(dāng)前代碼(Apply all migrations亿乳,應(yīng)用所有的遷移 )匹配。

我們運(yùn)行了命令ls 径筏,其輸出表明Django又創(chuàng)建了一個(gè)文件——db.sqlite3葛假。SQLite是一種使用單個(gè)文件的數(shù)據(jù)庫(kù),是編寫(xiě)簡(jiǎn)單應(yīng)用程序的理想選擇滋恬,因?yàn)樗屇悴挥锰P(guān)注數(shù)據(jù)庫(kù)管理的問(wèn)題聊训。

1.1.8 查看項(xiàng)目

下面來(lái)核實(shí)Django是否正確地創(chuàng)建了項(xiàng)目。為此恢氯,可執(zhí)行命令runserver 带斑,如下所示:

(ll_env) E:\python\my_learning_log>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
April 01, 2021 - 16:44:58
Django version 3.1.7, using settings 'learning_log.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Django啟動(dòng)一個(gè)服務(wù)器鼓寺,讓你能夠查看系統(tǒng)中的項(xiàng)目,了解它們的工作情況勋磕。當(dāng)你在瀏覽器中輸入U(xiǎn)RL以請(qǐng)求網(wǎng)頁(yè)時(shí)妈候,該Django服務(wù)器將進(jìn)行響應(yīng):生成合適的網(wǎng)頁(yè),并將其發(fā)送給瀏覽器挂滓。

Django通過(guò)檢查確認(rèn)正確地創(chuàng)建了項(xiàng)目苦银;它指出了使用的Django版本以及當(dāng)前使用的設(shè)置文件的名稱;它指出了項(xiàng)目的URL赶站。URL http://127.0.0.1:8000/表明項(xiàng)目將在你的計(jì)算機(jī)(即localhost)的端口8000上偵聽(tīng)請(qǐng)求幔虏。localhost是一種只處理當(dāng)前系統(tǒng)發(fā)出的請(qǐng)求,而不允許其他任何人查看你正在開(kāi)發(fā)的網(wǎng)頁(yè)的服務(wù)器贝椿。
現(xiàn)在打開(kāi)一款Web瀏覽器想括,并輸入U(xiǎn)RL:http://localhost:8000/;如果這不管用团秽,請(qǐng)輸入http://127.0.0.1:8000/主胧。你將看到類似于圖18-1所示的頁(yè)面,這個(gè)頁(yè)面是Django創(chuàng)建的习勤,讓你知道
到目前為止一切正匙俣埃。現(xiàn)在暫時(shí)不要關(guān)閉這個(gè)服務(wù)器图毕。若要關(guān)閉這個(gè)服務(wù)器夷都,按Ctrl + C即可。

image.png

1.2 創(chuàng)建應(yīng)用程序

Django項(xiàng)目 由一系列應(yīng)用程序組成予颤,它們協(xié)同工作囤官,讓項(xiàng)目成為一個(gè)整體。我們暫時(shí)只創(chuàng)建一個(gè)應(yīng)用程序蛤虐,它將完成項(xiàng)目的大部分工作党饮。

當(dāng)前,在前面打開(kāi)的終端窗口中應(yīng)該還運(yùn)行著runserver 驳庭。請(qǐng)?jiān)俅蜷_(kāi)一個(gè)終端窗口(或標(biāo)簽頁(yè))刑顺,并切換到manage.py所在的目錄。激活該虛擬環(huán)境饲常,再執(zhí)行命令startapp :

C:\Users\Administrator>E:

E:\>cd E:\python\my_learning_log

E:\python\my_learning_log>ll_env\Scripts\activate
(ll_env) E:\python\my_learning_log>python manage.py startapp learning_logs

(ll_env) E:\python\my_learning_log>dir
 驅(qū)動(dòng)器 E 中的卷是 新加卷
 卷的序列號(hào)是 823D-B082

 E:\python\my_learning_log 的目錄

2021/04/01  16:48    <DIR>          .
2021/04/01  16:48    <DIR>          ..
2021/04/01  16:06    <DIR>          .idea
2021/04/01  16:42           131,072 db.sqlite3
2021/04/01  16:42    <DIR>          learning_log
2021/04/01  16:48    <DIR>          learning_logs
2021/04/01  16:04    <DIR>          ll_env
2021/04/01  15:59               690 manage.py
               2 個(gè)文件        131,762 字節(jié)
               6 個(gè)目錄 56,942,854,144 可用字節(jié)

(ll_env) E:\python\my_learning_log>dir learning_logs
 驅(qū)動(dòng)器 E 中的卷是 新加卷
 卷的序列號(hào)是 823D-B082

 E:\python\my_learning_log\learning_logs 的目錄

2021/04/01  16:48    <DIR>          .
2021/04/01  16:48    <DIR>          ..
2021/04/01  16:48                66 admin.py
2021/04/01  16:48               105 apps.py
2021/04/01  16:48    <DIR>          migrations
2021/04/01  16:48                60 models.py
2021/04/01  16:48                63 tests.py
2021/04/01  16:48                66 views.py
2021/04/01  16:48                 0 __init__.py
               6 個(gè)文件            360 字節(jié)
               3 個(gè)目錄 56,942,854,144 可用字節(jié)

(ll_env) E:\python\my_learning_log>

命令startapp appname 讓Django建立創(chuàng)建應(yīng)用程序所需的基礎(chǔ)設(shè)施蹲堂。如果現(xiàn)在查看項(xiàng)目目錄,將看到其中新增了一個(gè)文件夾learning_logs贝淤。打開(kāi)這個(gè)文件夾柒竞,看看Django都創(chuàng)建了什么。其中最重要的文件是models.py播聪、admin.py和views.py朽基。我們將使用models.py來(lái)定義我們要在應(yīng)用程序中管理的數(shù)據(jù)布隔。admin.py和views.py將在稍后介紹。

1.2.1 定義模型

我們來(lái)想想涉及的數(shù)據(jù)踩晶。每位用戶都需要在學(xué)習(xí)筆記中創(chuàng)建很多主題执泰。用戶輸入的每個(gè)條目都與特定主題相關(guān)聯(lián),這些條目將以文本的方式顯示渡蜻。我們還需要存儲(chǔ)每個(gè)條目的時(shí)間戳术吝,以便能夠告訴用戶各個(gè)條目都是什么時(shí)候創(chuàng)建的。

打開(kāi)文件models.py茸苇,看看它當(dāng)前包含哪些內(nèi)容:
models.py

from django.db import models

# Create your models here.

這為我們導(dǎo)入了模塊models排苍,還讓我們創(chuàng)建自己的模型。模型告訴Django如何處理應(yīng)用程序中存儲(chǔ)的數(shù)據(jù)学密。在代碼層面淘衙,模型就是一個(gè)類,就像前面討論的每個(gè)類一樣腻暮,包含屬性和方法彤守。下面是表示用戶將要存儲(chǔ)的主題的模型:
models.py

from django.db import models

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

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

我們創(chuàng)建了一個(gè)名為T(mén)opic 的類,它繼承了Model ——Django中一個(gè)定義了模型基本功能的類哭靖。Topic 類只有兩個(gè)屬性:text 和date_added 具垫。

屬性text是一個(gè)CharField——由字符或文本組成的數(shù)據(jù)。需要存儲(chǔ)少量的文本试幽,如名稱筝蚕、標(biāo)題或城市時(shí),可使用CharField 铺坞。定義CharField 屬性時(shí)起宽,必須告訴Django該在數(shù)據(jù)庫(kù)中預(yù)留多少空間。在這里济榨,我們將max_length 設(shè)置成了200(即200個(gè)字符)坯沪,這對(duì)存儲(chǔ)大多數(shù)主題名來(lái)說(shuō)足夠了。

屬性date_added 是一個(gè)DateTimeField ——記錄日期和時(shí)間的數(shù)據(jù)擒滑。我們傳遞了實(shí)參auto_add_now=True 腐晾,每當(dāng)用戶創(chuàng)建新主題時(shí),這都讓Django將這個(gè)屬性自動(dòng)設(shè)置成當(dāng)前日期和時(shí)間橘忱。

1.2.2 激活模型

要使用模型赴魁,必須讓Django將應(yīng)用程序包含到項(xiàng)目中十减。為此烂叔,打開(kāi)settings.py(它位于目錄my_learning_log/learning_log中)昆庇,你將看到一個(gè)這樣的片段,即告訴Django哪些應(yīng)用程序安裝在項(xiàng)目中:

settings.py

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

這是一個(gè)元組凝颇,告訴Django項(xiàng)目是由哪些應(yīng)用程序組成的潘拱。請(qǐng)將INSTALLED_APPS 修改成下面這樣,將前面的應(yīng)用程序添加到這個(gè)元組中:

--snip--
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # 我的應(yīng)用程序
    'learning_logs'
]
--snip--

通過(guò)將應(yīng)用程序編組拧略,在項(xiàng)目不斷增大芦岂,包含更多的應(yīng)用程序時(shí),有助于對(duì)應(yīng)用程序進(jìn)行跟蹤垫蛆。這里新建了一個(gè)名為My apps的片段禽最,當(dāng)前它只包含應(yīng)用程序learning_logs。

接下來(lái)袱饭,需要讓Django修改數(shù)據(jù)庫(kù)川无,使其能夠存儲(chǔ)與模型Topic 相關(guān)的信息。為此虑乖,在終端窗口中執(zhí)行下面的命令:

(ll_env) E:\python\my_learning_log>python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs\migrations\0001_initial.py
    - Create model Topic

(ll_env) E:\python\my_learning_log>

命令makemigrations 讓Django確定該如何修改數(shù)據(jù)庫(kù)懦趋,使其能夠存儲(chǔ)與我們定義的新模型相關(guān)聯(lián)的數(shù)據(jù)。輸出表明Django創(chuàng)建了一個(gè)名為0001_initial.py的遷移文件疹味,這個(gè)文件將在數(shù)據(jù)庫(kù)中為模型Topic 創(chuàng)建一個(gè)表仅叫。

下面來(lái)應(yīng)用這種遷移,讓Django替我們修改數(shù)據(jù)庫(kù):

(ll_env) E:\python\my_learning_log>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0001_initial... OK

(ll_env) E:\python\my_learning_log>

這個(gè)命令的大部分輸出都與我們首次執(zhí)行命令migrate的輸出相同糙捺。我們需要檢查輸出行诫咱,在這里,Django確認(rèn)為learning_logs 應(yīng)用遷移時(shí)一切正常(OK )继找。
每當(dāng)需要修改“學(xué)習(xí)筆記”管理的數(shù)據(jù)時(shí)遂跟,都采取如下三個(gè)步驟:修改models.py;對(duì)learning_logs 調(diào)用makemigrations 婴渡;讓Django遷移項(xiàng)目幻锁。

1.2.3 Django管理網(wǎng)站

為應(yīng)用程序定義模型時(shí),Django提供的管理網(wǎng)站(admin site)讓你能夠輕松地處理模型边臼。網(wǎng)站的管理員可使用管理網(wǎng)站哄尔,但普通用戶不能使用。在本節(jié)中柠并,我們將建立管理網(wǎng)站岭接,并通過(guò)它使用模型Topic 來(lái)添加一些主題。

1. 創(chuàng)建超級(jí)用戶
Django允許你創(chuàng)建具備所有權(quán)限的用戶——超級(jí)用戶臼予。權(quán)限決定了用戶可執(zhí)行的操作鸣戴。最嚴(yán)格的權(quán)限設(shè)置只允許用戶閱讀網(wǎng)站的公開(kāi)信息;注冊(cè)了的用戶通痴呈埃可閱讀自己的私有數(shù)據(jù)窄锅,還可查看一些只有會(huì)員才能查看的信息。為有效地管理Web應(yīng)用程序缰雇,網(wǎng)站所有者通常需要訪問(wèn)網(wǎng)站存儲(chǔ)的所有信息入偷。優(yōu)秀的管理員會(huì)小心對(duì)待用戶的敏感信息追驴,因?yàn)橛脩魧?duì)其訪問(wèn)的應(yīng)用程序有極大的信任。

為在Django中創(chuàng)建超級(jí)用戶疏之,請(qǐng)執(zhí)行下面的命令并按提示做:

(ll_env) E:\python\my_learning_log>python manage.py createsuperuser
Username (leave blank to use 'administrator'): ll_admin
Email address:
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

(ll_env) E:\python\my_learning_log>

你執(zhí)行命令createsuperuser 時(shí)殿雪,Django提示你輸入超級(jí)用戶的用戶名。這里我們輸入的是ll_admin锋爪,但你可以輸入任何用戶名丙曙,比如電子郵件地址,也可讓這個(gè)字段為空其骄。你需要輸入密碼兩次河泳。

2. 向管理網(wǎng)站注冊(cè)模型
Django自動(dòng)在管理網(wǎng)站中添加了一些模型,如User 和Group 年栓,但對(duì)于我們創(chuàng)建的模型拆挥,必須手工進(jìn)行注冊(cè)。

我們創(chuàng)建應(yīng)用程序learning_logs 時(shí)某抓,Django在models.py所在的目錄中創(chuàng)建了一個(gè)名為admin.py的文件:
admin.py

from django.contrib import admin

# Register your models here.

為向管理網(wǎng)站注冊(cè)Topic 纸兔,請(qǐng)輸入下面的代碼:

from django.contrib import admin
from learning_logs.models import  Topic

admin.site.register(Topic)

這些代碼導(dǎo)入我們要注冊(cè)的模型Topic ,再使用admin.site.register() 讓Django通過(guò)管理網(wǎng)站管理我們的模型否副。

現(xiàn)在汉矿,使用超級(jí)用戶賬戶訪問(wèn)管理網(wǎng)站:訪問(wèn)http://localhost:8000/admin/ ,并輸入你剛創(chuàng)建的超級(jí)用戶的用戶名和密碼备禀。這個(gè)網(wǎng)頁(yè)讓你能夠添加和修改用戶和用戶組洲拇,還可以管理與剛才定義的模型Topic 相關(guān)的數(shù)據(jù)。

image.png
image.png

3. 添加主題
向管理網(wǎng)站注冊(cè)Topic 后曲尸,我們來(lái)添加第一個(gè)主題赋续。為此,單擊Topics進(jìn)入主題網(wǎng)頁(yè)另患,它幾乎是空的纽乱,這是因?yàn)槲覀冞€沒(méi)有添加任何主題。單擊Add昆箕,你將看到一個(gè)用于添加新主題的表單鸦列。在第一個(gè)方框中輸入Chess ,再單擊Save鹏倘,這將返回到主題管理頁(yè)面薯嗤,其中包含剛創(chuàng)建的主題

下面再創(chuàng)建一個(gè)主題,以便有更多的數(shù)據(jù)可供使用纤泵。再次單擊Add骆姐,并創(chuàng)建另一個(gè)主題Rock Climbing 。當(dāng)你單擊Save時(shí),將重新回到主題管理頁(yè)面诲锹,其中包含主題Chess和Rock Climbing。


image.png

1.2.4 定義模型Entry

要記錄學(xué)到的國(guó)際象棋和攀巖知識(shí)涉馅,需要為用戶可在學(xué)習(xí)筆記中添加的條目定義模型归园。每個(gè)條目都與特定主題相關(guān)聯(lián),這種關(guān)系被稱為多對(duì)一關(guān)系稚矿,即多個(gè)條目可關(guān)聯(lián)到同一個(gè)
主題庸诱。
下面是模型Entry 的代碼:
models.py

from django.db import models

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

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


class Entry(models.Model):
    """ 學(xué)到的有關(guān)某個(gè)主題的具體知識(shí) """
    topic = models.ForeignKey(Topic, on_delete=models.DO_NOTHING)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'entries'

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

像Topic 一樣,Entry 也繼承了Django基類Model 晤揣。第一個(gè)屬性topic 是一個(gè)ForeignKey 實(shí)例桥爽。外鍵是一個(gè)數(shù)據(jù)庫(kù)術(shù)語(yǔ),它引用了數(shù)據(jù)庫(kù)中的另一條記錄昧识;這些代碼將每個(gè)條目關(guān)聯(lián)到特定的主題钠四。每個(gè)主題創(chuàng)建時(shí),都給它分配了一個(gè)鍵(或ID)跪楞。需要在兩項(xiàng)數(shù)據(jù)之間建立聯(lián)系時(shí)缀去,Django使用與每項(xiàng)信息相關(guān)聯(lián)的鍵。稍后我們將根據(jù)這些聯(lián)系獲取與特定主題相關(guān)聯(lián)的所有條目甸祭。

接下來(lái)是屬性text 缕碎,它是一個(gè)TextField 實(shí)例。這種字段不需要長(zhǎng)度限制池户,因?yàn)槲覀儾幌胂拗茥l目的長(zhǎng)度咏雌。屬性date_added 讓我們能夠按創(chuàng)建順序呈現(xiàn)條目,并在每個(gè)條目旁邊放置時(shí)間戳校焦。

我們?cè)贓ntry 類中嵌套了Meta 類赊抖。Meta 存儲(chǔ)用于管理模型的額外信息,在這里寨典,它讓我們能夠設(shè)置一個(gè)特殊屬性熏迹,讓Django在需要時(shí)使用Entries 來(lái)表示多個(gè)條目。如果沒(méi)有這個(gè)類凝赛, Django將使用Entrys來(lái)表示多個(gè)條目注暗。最后,方法str() 告訴Django墓猎,呈現(xiàn)條目時(shí)應(yīng)顯示哪些信息捆昏。由于條目包含的文本可能很長(zhǎng),我們讓Django只顯示text 的前50個(gè)字符毙沾。我們還添加了一個(gè)省略號(hào)骗卜,指出顯示的并非整個(gè)條目。

1.2.5 遷移模型Entry

由于我們添加了一個(gè)新模型,因此需要再次遷移數(shù)據(jù)庫(kù)寇仓。你將慢慢地對(duì)這個(gè)過(guò)程了如指掌:修改models.py举户,執(zhí)行命令python manage.py makemigrations app_name ,
再執(zhí)行命令python manage.py migrate 遍烦。
下面來(lái)遷移數(shù)據(jù)庫(kù)并查看輸出:

(ll_env) E:\python\my_learning_log>python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs\migrations\0002_entry.py
    - Create model Entry

(ll_env) E:\python\my_learning_log>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0002_entry... OK

(ll_env) E:\python\my_learning_log>

生成了一個(gè)新的遷移文件——0002_entry.py俭嘁,它告訴Django如何修改數(shù)據(jù)庫(kù),使其能夠存儲(chǔ)與模型Entry 相關(guān)的信息服猪。執(zhí)行命令migrate 供填,我們發(fā)現(xiàn)Django應(yīng)用了這種遷移且一切順利。

1.2.6 向管理網(wǎng)站注冊(cè)Entry

我們還需要注冊(cè)模型Entry 罢猪。為此近她,需要將admin.py修改成類似于下面這樣:
admin.py

from django.contrib import admin
from learning_logs.models import  Topic, Entry

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

返回到http://localhost/admin/ ,你將看到learning_logs下列出了Entries膳帕。單擊Entries的Add鏈接粘捎,或者單擊Entries再選擇Add entry。你將看到一個(gè)下拉列表危彩,讓你能夠選擇要為哪個(gè)主題創(chuàng)建條目晌端,還有一個(gè)用于輸入條目的文本框。從下拉列表中選擇Chess恬砂,并添加一個(gè)條目咧纠。下面是我添加的第一個(gè)條目。

The opening is the first part of the game, roughly the first ten moves or so. In the opening, it's a good idea to do three things— bring out your bishops and knights, try to control the center of the board, and castle your king.(國(guó)際象棋的第一個(gè)階段是開(kāi)局泻骤,大致是前10步左右漆羔。在開(kāi)局階段,最好做三件事情:將象和馬調(diào)出來(lái)狱掂;努力控制棋盤(pán)的中間區(qū)域演痒;用車將王護(hù)住。)

Of course, these are just guidelines. It will be important to learn when to follow these guidelines and when to disregard these suggestions.(當(dāng)然趋惨,這些只是指導(dǎo)原則鸟顺。學(xué)習(xí)什么情況下遵守這些原則、什么情況下不用遵守很重要器虾。)

當(dāng)你單擊Save時(shí)讯嫂,將返回到主條目管理頁(yè)面。在這里兆沙,你將發(fā)現(xiàn)使用text[:50] 作為條目的字符串表示的好處:管理界面中欧芽,只顯示了條目的開(kāi)頭部分而不是其所有文本,這使得管理多個(gè)條目容易得多葛圃。

再來(lái)創(chuàng)建一個(gè)國(guó)際象棋條目千扔,并創(chuàng)建一個(gè)攀巖條目憎妙,以提供一些初始數(shù)據(jù)。下面是第二個(gè)國(guó)際象棋條目曲楚。

In the opening phase of the game, it's important to bring out your bishops and knights. These pieces are powerful and maneuverable enough to play a significant role in the beginning moves of a
game.(在國(guó)際象棋的開(kāi)局階段厘唾,將象和馬調(diào)出來(lái)很重要。這些棋子威力大龙誊,機(jī)動(dòng)性強(qiáng)抚垃,在開(kāi)局階段扮演著重要角色。)

下面是第一個(gè)攀巖條目:

One of the most important concepts in climbing is to keep your weight on your feet as much as possible. There's a myth that climbers can hang all day on their arms. In reality, good climbers have
practiced specific ways of keeping their weight over their feet whenever possible.(最重要的攀巖概念之一是盡可能讓雙腳承受體重载迄。有謬誤認(rèn)為攀巖者能依靠手臂的力量堅(jiān)持一整天。實(shí)際上抡蛙,優(yōu)秀的攀巖者都經(jīng)過(guò)專門(mén)訓(xùn)練护昧,能夠盡可能讓雙腳承受體重。)

繼續(xù)往下開(kāi)發(fā)“學(xué)習(xí)筆記”時(shí)粗截,這三個(gè)條目可為我們提供使用的數(shù)據(jù)惋耙。


image.png

1.2.7 Django shell

輸入一些數(shù)據(jù)后,就可通過(guò)交互式終端會(huì)話以編程方式查看這些數(shù)據(jù)了熊昌。這種交互式環(huán)境稱為Django shell绽榛,是測(cè)試項(xiàng)目和排除其故障的理想之地。下面是一個(gè)交互式shell會(huì)話示例:

(ll_env) E:\python\my_learning_log>python manage.py shell
Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
>>>

在活動(dòng)的虛擬環(huán)境中執(zhí)行時(shí)婿屹,命令python manage.py shell 啟動(dòng)一個(gè)Python解釋器灭美,可使用它來(lái)探索存儲(chǔ)在項(xiàng)目數(shù)據(jù)庫(kù)中的數(shù)據(jù)。在這里昂利,我們導(dǎo)入了模塊learning_logs.models 中的模型Topic 届腐,然后使用方法Topic.objects.all() 來(lái)獲取模型Topic 的所有實(shí)例;它返回的是一個(gè)列表蜂奸,稱為查詢集(queryset)犁苏。

我們可以像遍歷列表一樣遍歷查詢集。下面演示了如何查看分配給每個(gè)主題對(duì)象的ID:

>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
...
1 Chess
2 Rock Climbing
>>>
>>>

我們將返回的查詢集存儲(chǔ)在topics 中扩所,然后打印每個(gè)主題的id 屬性和字符串表示围详。從輸出可知,主題Chess的ID為1祖屏,而Rock Climbing的ID為2助赞。

知道對(duì)象的ID后,就可獲取該對(duì)象并查看其任何屬性袁勺。下面來(lái)看看主題Chess的屬性text 和date_added 的值:

>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2021, 4, 1, 9, 21, 41, 378000, tzinfo=<UTC>)
>>>

我們還可以查看與主題相關(guān)聯(lián)的條目嫉拐。前面我們給模型Entry 定義了屬性topic ,這是一個(gè)ForeignKey 魁兼,將條目與主題關(guān)聯(lián)起來(lái)婉徘。利用這種關(guān)聯(lián)漠嵌,Django能夠獲取與特定主題相關(guān)聯(lián)的所有條目,如下所示:

>>> 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...>]>
>>>

為通過(guò)外鍵關(guān)系獲取數(shù)據(jù)盖呼,可使用相關(guān)模型的小寫(xiě)名稱儒鹿、下劃線和單詞set。例如几晤,假設(shè)你有模型Pizza 和Topping 约炎,而Topping通過(guò)一個(gè)外鍵關(guān)聯(lián)到Pizza ;如果你有一個(gè)名為my_pizza 的對(duì)象蟹瘾,表示一張比薩圾浅,就可使用代碼my_pizza.topping_set.all() 來(lái)獲取這張比薩的所有配料。

編寫(xiě)用戶可請(qǐng)求的網(wǎng)頁(yè)時(shí)憾朴,我們將使用這種語(yǔ)法狸捕。確認(rèn)代碼能獲取所需的數(shù)據(jù)時(shí),shell很有幫助众雷。如果代碼在shell中的行為符合預(yù)期灸拍,那么它們?cè)陧?xiàng)目文件中也能正確地工作。如果代碼引發(fā)了錯(cuò)誤或獲取的數(shù)據(jù)不符合預(yù)期砾省,那么在簡(jiǎn)單的shell環(huán)境中排除故障要比在生成網(wǎng)頁(yè)的文件中排除故障容易得多鸡岗。我們不會(huì)太多地使用shell,但應(yīng)繼續(xù)使用它來(lái)熟悉對(duì)存儲(chǔ)在項(xiàng)目中的數(shù)據(jù)進(jìn)行訪問(wèn)的Django語(yǔ)法编兄。

1.3 創(chuàng)建網(wǎng)頁(yè):學(xué)習(xí)筆記主頁(yè)

使用Django創(chuàng)建網(wǎng)頁(yè)的過(guò)程通常分三個(gè)階段:定義URL轩性、編寫(xiě)視圖和編寫(xiě)模板。首先狠鸳,你必須定義URL模式炮姨。URL模式描述了URL是如何設(shè)計(jì)的,讓Django知道如何將瀏覽器請(qǐng)求與網(wǎng)站URL匹配碰煌,以確定返回哪個(gè)網(wǎng)頁(yè)舒岸。

每個(gè)URL都被映射到特定的視圖 ——視圖函數(shù)獲取并處理網(wǎng)頁(yè)所需的數(shù)據(jù)。視圖函數(shù)通常調(diào)用一個(gè)模板芦圾,后者生成瀏覽器能夠理解的網(wǎng)頁(yè)蛾派。為明白其中的工作原理,我們來(lái)創(chuàng)建學(xué)習(xí)筆記的主頁(yè)个少。我們將定義該主頁(yè)的URL洪乍、編寫(xiě)其視圖函數(shù)并創(chuàng)建一個(gè)簡(jiǎn)單的模板。

鑒于我們只是要確币菇梗“學(xué)習(xí)筆記”按要求的那樣工作壳澳,我們將暫時(shí)讓這個(gè)網(wǎng)頁(yè)盡可能簡(jiǎn)單。Web應(yīng)用程序能夠正常運(yùn)行后茫经,設(shè)置樣式可使其更有趣巷波,但中看不中用的應(yīng)用程序毫無(wú)意義萎津。就目前而言,主頁(yè)只顯示標(biāo)題和簡(jiǎn)單的描述抹镊。

1.3.1 映射URL

用戶通過(guò)在瀏覽器中輸入U(xiǎn)RL以及單擊鏈接來(lái)請(qǐng)求網(wǎng)頁(yè)锉屈,因此我們需要確定項(xiàng)目需要哪些URL。主頁(yè)的URL最重要垮耳,它是用戶用來(lái)訪問(wèn)項(xiàng)目的基礎(chǔ)URL颈渊。當(dāng)前,基礎(chǔ)URL(http://localhost:8000/)返回默認(rèn)的Django網(wǎng)站终佛,讓我們知道正確地建立了項(xiàng)目俊嗽。我們將修改這一點(diǎn),將這個(gè)基礎(chǔ)URL映射到“學(xué)習(xí)筆記”的主頁(yè)铃彰。

打開(kāi)項(xiàng)目主文件夾learning_log中的文件urls.py绍豁,你將看到如下代碼:
urls.py

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

前兩行導(dǎo)入了為項(xiàng)目和管理網(wǎng)站管理URL的函數(shù)和模塊。這個(gè)文件的主體定義了變量urlpatterns 豌研。在這個(gè)針對(duì)整個(gè)項(xiàng)目的urls.py文件中妹田,變量urlpatterns 包含項(xiàng)目中的應(yīng)用程序的URL唬党。代碼包含模塊admin.site.urls 鹃共,該模塊定義了可在管理網(wǎng)站中請(qǐng)求的所有URL。

我們需要包含learning_logs的URL:

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include(('learning_logs.urls', "learning_logs"), namespace="learning_logs")),
]

我們添加了一行代碼來(lái)包含模塊learning_logs.urls 驶拱。這行代碼包含實(shí)參namespace 霜浴,讓我們能夠?qū)earning_logs 的URL同項(xiàng)目中的其他URL區(qū)分開(kāi)來(lái),這在項(xiàng)目開(kāi)始擴(kuò)展時(shí)很有幫助蓝纲。
默認(rèn)的urls.py包含在文件夾learning_log中阴孟,現(xiàn)在我們需要在文件夾learning_logs中創(chuàng)建另一個(gè)urls.py文件:

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

from django.conf.urls import url
from . import views

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

為弄清楚當(dāng)前位于哪個(gè)urls.py文件中,我們?cè)谶@個(gè)文件開(kāi)頭添加了一個(gè)文檔字符串税迷。接下來(lái)永丝,我們導(dǎo)入了函數(shù)url ,因?yàn)槲覀冃枰褂盟鼇?lái)將URL映射到視圖箭养。

我們還導(dǎo)入了模塊views 慕嚷,其中的句點(diǎn)讓Python從當(dāng)前的urls.py模塊所在的文件夾中導(dǎo)入視圖。在這個(gè)模塊中毕泌,變量urlpatterns 是一個(gè)列表喝检,包含可在應(yīng)用程序learning_logs 中請(qǐng)求的網(wǎng)頁(yè)。

實(shí)際的URL模式是一個(gè)對(duì)函數(shù)url() 的調(diào)用撼泛,這個(gè)函數(shù)接受三個(gè)實(shí)參挠说。第一個(gè)是一個(gè)正則表達(dá)式。Django在urlpatterns 中查找與請(qǐng)求的URL字符串匹配的正則表達(dá)式愿题,因此正則表達(dá)式定義了Django可查找的模式损俭。

我們來(lái)看看正則表達(dá)式r'^$' 蛙奖。其中的r 讓Python將接下來(lái)的字符串視為原始字符串,而引號(hào)告訴Python正則表達(dá)式始于和終于何處撩炊。脫字符(^ )讓Python查看字符串的開(kāi)頭外永,而美元符號(hào)讓Python查看字符串的末尾∨】龋總體而言伯顶,這個(gè)正則表達(dá)式讓Python查找開(kāi)頭和末尾之間沒(méi)有任何東西的URL。Python忽略項(xiàng)目的基礎(chǔ)URL(http://localhost:8000/)骆膝,因此這個(gè)正則表達(dá)式與基礎(chǔ)URL匹配祭衩。其他URL都與這個(gè)正則表達(dá)式不匹配。如果請(qǐng)求的URL不與任何URL模式匹配阅签,Django將返回一個(gè)錯(cuò)誤頁(yè)面掐暮。

url() 的第二個(gè)實(shí)參指定了要調(diào)用的視圖函數(shù)。請(qǐng)求的URL與前述正則表達(dá)式匹配時(shí)政钟,Django將調(diào)用views.index (這個(gè)視圖函數(shù)將在下一節(jié)編寫(xiě))路克。第三個(gè)實(shí)參將這個(gè)URL模式的名稱指定為index,讓我們能夠在代碼的其他地方引用它养交。每當(dāng)需要提供到這個(gè)主頁(yè)的鏈接時(shí)精算,我們都將使用這個(gè)名稱,而不編寫(xiě)URL碎连。

1.3.2 編寫(xiě)視圖

視圖函數(shù)接受請(qǐng)求中的信息灰羽,準(zhǔn)備好生成網(wǎng)頁(yè)所需的數(shù)據(jù),再將這些數(shù)據(jù)發(fā)送給瀏覽器——這通常是使用定義了網(wǎng)頁(yè)是什么樣的模板實(shí)現(xiàn)的鱼辙。

learning_logs中的文件views.py是你執(zhí)行命令python manage.py startapp 時(shí)自動(dòng)生成的廉嚼,當(dāng)前其內(nèi)容如下:
views.py

from django.shortcuts import render

# 在這里創(chuàng)建視圖

當(dāng)前,這個(gè)文件只導(dǎo)入了函數(shù)render() 倒戏,它根據(jù)視圖提供的數(shù)據(jù)渲染響應(yīng)怠噪。下面的代碼演示了該如何為主頁(yè)編寫(xiě)視圖:

from django.shortcuts import render

def index(request):
    """ 學(xué)習(xí)筆記的主頁(yè) """
    return render(request, 'learning_logs/index.html')

URL請(qǐng)求與我們剛才定義的模式匹配時(shí),Django將在文件views.py中查找函數(shù)index() 杜跷,再將請(qǐng)求對(duì)象傳遞給這個(gè)視圖函數(shù)傍念。在這里,我們不需要處理任何數(shù)據(jù)葱椭,因此這個(gè)函數(shù)只包含調(diào)用render() 的代碼捂寿。這里向函數(shù)render() 提供了兩個(gè)實(shí)參:原始請(qǐng)求對(duì)象以及一個(gè)可用于創(chuàng)建網(wǎng)頁(yè)的模板。下面來(lái)編寫(xiě)這個(gè)模板孵运。

1.3.3 編寫(xiě)模板

模板定義了網(wǎng)頁(yè)的結(jié)構(gòu)秦陋。模板指定了網(wǎng)頁(yè)是什么樣的,而每當(dāng)網(wǎng)頁(yè)被請(qǐng)求時(shí)治笨,Django將填入相關(guān)的數(shù)據(jù)驳概。模板讓你能夠訪問(wèn)視圖提供的任何數(shù)據(jù)赤嚼。我們的主頁(yè)視圖沒(méi)有提供任何數(shù)據(jù),因此相應(yīng)的模板非常簡(jiǎn)單顺又。

在文件夾learning_logs中新建一個(gè)文件夾更卒,并將其命名為templates。在文件夾templates中稚照,再新建一個(gè)文件夾蹂空,并將其命名為learning_logs。這好像有點(diǎn)多余(我們?cè)谖募Alearning_logs中創(chuàng)建了文件夾templates果录,又在這個(gè)文件夾中創(chuàng)建了文件夾learning_logs)上枕,但建立了Django能夠明確解讀的結(jié)構(gòu),即便項(xiàng)目很大弱恒,包含很多應(yīng)用程序亦如此辨萍。在最里面的文件夾learning_logs中,新建一個(gè)文件返弹,并將其命名為index.html锈玉,再在這個(gè)文件中編寫(xiě)如下代碼:
index.html

<p>Learing Log</p>

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

這個(gè)文件非常簡(jiǎn)單。對(duì)于不熟悉HTML的讀者义起,這里解釋一下:標(biāo)簽<p></p> 標(biāo)識(shí)段落拉背;標(biāo)簽<p> 指出了段落的開(kāi)頭位置,而標(biāo)簽</p> 指出了段落的結(jié)束位置并扇。這里定義了兩個(gè)段落:第一個(gè)充當(dāng)標(biāo)題去团,第二個(gè)闡述了用戶可使用“學(xué)習(xí)筆記”來(lái)做什么抡诞。

現(xiàn)在穷蛹,如果你請(qǐng)求這個(gè)項(xiàng)目的基礎(chǔ)URL——http://localhost:8000/,將看到剛才創(chuàng)建的網(wǎng)頁(yè)昼汗,而不是默認(rèn)的Django網(wǎng)頁(yè)肴熏。Django接受請(qǐng)求的URL,發(fā)現(xiàn)該URL與模式r'^$' 匹配顷窒,因此調(diào)用函數(shù)views.index() 蛙吏,這將使用index.html包含的模板來(lái)渲染網(wǎng)頁(yè),結(jié)果如下圖所示:

image.png

創(chuàng)建網(wǎng)頁(yè)的過(guò)程看起來(lái)可能很復(fù)雜鞋吉,但將URL鸦做、視圖和模板分離的效果實(shí)際上很好。這讓我們能夠分別考慮項(xiàng)目的不同方面谓着,且在項(xiàng)目很大時(shí)泼诱,讓各個(gè)參與者可專注于其最擅長(zhǎng)的方面。例如赊锚,數(shù)據(jù)庫(kù)專家可專注于模型治筒,程序員可專注于視圖代碼屉栓,而Web設(shè)計(jì)人員可專注于模板。

1.4 創(chuàng)建其他網(wǎng)頁(yè)

制定創(chuàng)建網(wǎng)頁(yè)的流程后耸袜,可以開(kāi)始擴(kuò)充“學(xué)習(xí)筆記”項(xiàng)目了友多。我們將創(chuàng)建兩個(gè)顯示數(shù)據(jù)的網(wǎng)頁(yè),其中一個(gè)列出所有的主題堤框,另一個(gè)顯示特定主題的所有條目域滥。對(duì)于每個(gè)網(wǎng)頁(yè),我們都將指定URL模式蜈抓,編寫(xiě)一個(gè)視圖函數(shù)骗绕,并編寫(xiě)一個(gè)模板。但這樣做之前资昧,我們先創(chuàng)建一個(gè)父模板酬土,項(xiàng)目中的其他模板都將繼承它。

1.4.1 模板繼承

創(chuàng)建網(wǎng)站時(shí)格带,幾乎都有一些所有網(wǎng)頁(yè)都將包含的元素撤缴。在這種情況下,可編寫(xiě)一個(gè)包含通用元素的父模板叽唱,并讓每個(gè)網(wǎng)頁(yè)都繼承這個(gè)模板屈呕,而不必在每個(gè)網(wǎng)頁(yè)中重復(fù)定義這些通用元素。這種方法能讓你專注于開(kāi)發(fā)每個(gè)網(wǎng)頁(yè)的獨(dú)特方面棺亭,還能讓修改項(xiàng)目的整體外觀容易得多虎眨。
1. 父模板
我們首先來(lái)創(chuàng)建一個(gè)名為base.html的模板,并將其存儲(chǔ)在index.html所在的目錄中镶摘。這個(gè)文件包含所有頁(yè)面都有的元素嗽桩;其他的模板都繼承base.html。當(dāng)前凄敢,所有頁(yè)面都包含的元素只有頂端的標(biāo)題碌冶。我們將在每個(gè)頁(yè)面中包含這個(gè)模板,因此我們將這個(gè)標(biāo)題設(shè)置為到主頁(yè)的鏈接:
base.html

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

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

這個(gè)文件的第一部分創(chuàng)建一個(gè)包含項(xiàng)目名的段落涝缝,該段落也是一個(gè)到主頁(yè)的鏈接扑庞。為創(chuàng)建鏈接,我們使用了一個(gè)模板標(biāo)簽 拒逮,它是用大括號(hào)和百分號(hào)({% %} )表示的罐氨。模板標(biāo)簽是一小段代碼,生成要在網(wǎng)頁(yè)中顯示的信息滩援。在這個(gè)實(shí)例中栅隐,模板標(biāo)簽{% url 'learning_logs:index' %} 生成一個(gè)URL,該URL與learning_logs/urls.py中定義的名為index 的URL模式匹配。在這個(gè)示例中约啊,learning_logs 是一個(gè)命名空間 邑遏,而index 是該命名空間中一個(gè)名稱獨(dú)特的URL模式。

在簡(jiǎn)單的HTML頁(yè)面中恰矩,鏈接是使用錨 標(biāo)簽定義的:

<a href="link_url">link text</a>

讓模板標(biāo)簽來(lái)生成URL记盒,可讓鏈接保持最新容易得多。要修改項(xiàng)目中的URL外傅,只需修改urls.py中的URL模式纪吮,這樣網(wǎng)頁(yè)被請(qǐng)求時(shí),Django將自動(dòng)插入修改后的URL萎胰。在我們的項(xiàng)目中碾盟,每個(gè)網(wǎng)頁(yè)都將繼承base.html,因此從現(xiàn)在開(kāi)始技竟,每個(gè)網(wǎng)頁(yè)都包含到主頁(yè)的鏈接冰肴。

我們插入了一對(duì)塊標(biāo)簽。這個(gè)塊名為content 榔组,是一個(gè)占位符靠汁,其中包含的信息將由子模板指定哺窄。
子模板并非必須定義父模板中的每個(gè)塊,因此在父模板中圣贸,可使用任意多個(gè)塊來(lái)預(yù)留空間成洗,而子模板可根據(jù)需要定義相應(yīng)數(shù)量的塊课梳。

2. 子模板
現(xiàn)在需要重新編寫(xiě)index.html仓洼,使其繼承base.html宦言,如下所示:
index.html

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

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

如果將這些代碼與原來(lái)的index.html進(jìn)行比較,可發(fā)現(xiàn)我們將標(biāo)題Learning Log替換成了從父模板那里繼承的代碼换可。子模板的第一行必須包含標(biāo)簽{% extends %} 椎椰,讓Django知道它繼承了哪個(gè)父模板。文件base.html位于文件夾learning_logs中锦担,因此父模板路徑中包含learning_logs俭识。這行代碼導(dǎo)入模板base.html的所有內(nèi)容慨削,讓index.html能夠指定要在content 塊預(yù)留的空間中添加的內(nèi)容洞渔。

我們插入了一個(gè)名為content 的{% block %} 標(biāo)簽,以定義content 塊缚态。不是從父模板繼承的內(nèi)容都包含在content 塊中磁椒,在這里是一個(gè)描述項(xiàng)目“學(xué)習(xí)筆記”的段落。我們使用標(biāo)簽{% endblock content %} 指出了內(nèi)容定義的結(jié)束位置玫芦。模板繼承的優(yōu)點(diǎn)開(kāi)始顯現(xiàn)出來(lái)了:在子模板中浆熔,只需包含當(dāng)前網(wǎng)頁(yè)特有的內(nèi)容。這不僅簡(jiǎn)化了每個(gè)模板桥帆,還使得網(wǎng)站修改起來(lái)容易得多医增。要修改很多網(wǎng)頁(yè)都包含的元素慎皱,只需在父模板中修改該元素,你所做的修改將傳導(dǎo)到繼承該父模板的每個(gè)頁(yè)面叶骨。在包含數(shù)十乃至數(shù)百個(gè)網(wǎng)頁(yè)的項(xiàng)目中茫多,這種結(jié)構(gòu)使得網(wǎng)站改進(jìn)起來(lái)容易而且快捷得多。

1.4.2 顯示所有主題的頁(yè)面

有了高效的網(wǎng)頁(yè)創(chuàng)建方法忽刽,就能專注于另外兩個(gè)網(wǎng)頁(yè)了:顯示全部主題的網(wǎng)頁(yè)以及顯示特定主題中條目的網(wǎng)頁(yè)天揖。所有主題頁(yè)面顯示用戶創(chuàng)建的所有主題,它是第一個(gè)需要使用數(shù)據(jù)的網(wǎng)頁(yè)跪帝。

1. URL模式
首先今膊,我們來(lái)定義顯示所有主題的頁(yè)面的URL。通常伞剑,使用一個(gè)簡(jiǎn)單的URL片段來(lái)指出網(wǎng)頁(yè)顯示的信息斑唬;我們將使用單詞topics,因此URL http://localhost:8000/topics/將返回顯示所有主題的頁(yè)面黎泣。下面演示了該如何修改learning_logs/urls.py
urls.py

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

from django.conf.urls import url
from . import views

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

    # 顯示所有的主題
    url(r'^topics/$', views.topics, name='topics'),
]

我們只是在用于主頁(yè)URL的正則表達(dá)式中添加了topics/赖钞。Django檢查請(qǐng)求的URL時(shí),這個(gè)模式與這樣的URL匹配:基礎(chǔ)URL后面跟著topics 聘裁⊙┯可以在末尾包含斜杠,也可以省略它衡便,但單詞topics 后面不能有任何東西献起,否則就與該模式不匹配。其URL與該模式匹配的請(qǐng)求都將交給views.py中的函數(shù)topics() 進(jìn)行處理镣陕。

2. 視圖
函數(shù)topics() 需要從數(shù)據(jù)庫(kù)中獲取一些數(shù)據(jù)谴餐,并將其發(fā)送給模板。我們需要在views.py中添加的代碼如下:
views.py

from django.shortcuts import render
from .models import Topic

def index(request):
    """ 學(xué)習(xí)筆記的主頁(yè) """
    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)

我們首先導(dǎo)入了與所需數(shù)據(jù)相關(guān)聯(lián)的模型呆抑。函數(shù)topics() 包含一個(gè)形參:Django從服務(wù)器那里收到的request 對(duì)象岂嗓。我們查詢數(shù)據(jù)庫(kù)——請(qǐng)求提供Topic 對(duì)象,并按屬性date_added 對(duì)它們進(jìn)行排序鹊碍。我們將返回的查詢集存儲(chǔ)在topics 中厌殉。

我們定義了一個(gè)將要發(fā)送給模板的上下文。上下文是一個(gè)字典侈咕,其中的鍵是我們將在模板中用來(lái)訪問(wèn)數(shù)據(jù)的名稱公罕,而值是我們要發(fā)送給模板的數(shù)據(jù)。在這里耀销,只有一個(gè)鍵—值對(duì)楼眷,它包含我們將在網(wǎng)頁(yè)中顯示的一組主題。創(chuàng)建使用數(shù)據(jù)的網(wǎng)頁(yè)時(shí),除對(duì)象request 和模板的路徑外罐柳,我們還將變量context 傳遞給render() 掌腰。

3. 模板
顯示所有主題的頁(yè)面的模板接受字典context ,以便能夠使用topics() 提供的數(shù)據(jù)张吉。請(qǐng)創(chuàng)建一個(gè)文件辅斟,將其命名為topics.html,并存儲(chǔ)到index.html所在的目錄中芦拿。下面演示了如何在這個(gè)模板中顯示主題:
topics.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 yes.</li>
    {% endfor %}
</ul>
{% endblock content %}

就像模板index.html一樣士飒,我們首先使用標(biāo)簽{% extends %} 來(lái)繼承base.html,再開(kāi)始定義content 塊蔗崎。這個(gè)網(wǎng)頁(yè)的主體是一個(gè)項(xiàng)目列表酵幕,其中列出了用戶輸入的主題。在標(biāo)準(zhǔn)HTML中缓苛,項(xiàng)目列表被稱為無(wú)序列表芳撒,用標(biāo)簽<ul></ul> 表示。我們使用了一個(gè)相當(dāng)于for 循環(huán)的模板標(biāo)簽未桥,它遍歷字典context 中的列表topics 笔刹。模板中使用的代碼與Python代碼存在一些重要差別:Python使用縮進(jìn)來(lái)指出哪些代碼行是for 循環(huán)的組成部分,而在模板中冬耿,每個(gè)for 循環(huán)都必須使用{% endfor %} 標(biāo)簽來(lái)顯式地指出其結(jié)束位置舌菜。因此在模板中,循環(huán)類似于下面這樣:

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

在循環(huán)中亦镶,我們要將每個(gè)主題轉(zhuǎn)換為一個(gè)項(xiàng)目列表項(xiàng)日月。要在模板中打印變量,需要將變量名用雙花括號(hào)括起來(lái)缤骨。每次循環(huán)時(shí)爱咬,代碼{{ topic }} 都被替換為topic 的當(dāng)前值。這些花括號(hào)不會(huì)出現(xiàn)在網(wǎng)頁(yè)中绊起,它們只是用于告訴Django我們使用了一個(gè)模板變量精拟。HTML標(biāo)簽<li></li> 表示一個(gè)項(xiàng)目列表項(xiàng),在標(biāo)簽對(duì)<ul></ul> 內(nèi)部虱歪,位于標(biāo)簽<li> 和</li> 之間的內(nèi)容都是一個(gè)項(xiàng)目列表項(xiàng)蜂绎。

我們使用了模板標(biāo)簽{% empty %} ,它告訴Django在列表topics 為空時(shí)該怎么辦:這里是打印一條消息实蔽,告訴用戶還沒(méi)有添加任何主題荡碾。最后兩行分別結(jié)束for 循環(huán)和項(xiàng)目列表。

現(xiàn)在需要修改父模板局装,使其包含到顯示所有主題的頁(yè)面的鏈接:
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 %}

我們?cè)诘街黜?yè)的鏈接后面添加了一個(gè)連字符,然后添加了一個(gè)到顯示所有主題的頁(yè)面的鏈接——使用的也是模板標(biāo)簽url 。這一行讓Django生成一個(gè)鏈接铐尚,它與learning_logs/ urls.py中名為topics 的URL模式匹配拨脉。

現(xiàn)在如果你刷新瀏覽器中的主頁(yè),將看到鏈接Topics宣增。單擊這個(gè)鏈接玫膀,將看到類似于下圖所示.


image.png
image.png

1.4.3 顯示特定主題的頁(yè)面

接下來(lái),我們需要?jiǎng)?chuàng)建一個(gè)專注于特定主題的頁(yè)面——顯示該主題的名稱及該主題的所有條目爹脾。同樣帖旨,我們將定義一個(gè)新的URL模式,編寫(xiě)一個(gè)視圖并創(chuàng)建一個(gè)模板灵妨。我們還將修改顯示所有主題的網(wǎng)頁(yè)解阅,讓每個(gè)項(xiàng)目列表項(xiàng)都是一個(gè)鏈接,單擊它將顯示相應(yīng)主題的所有條目泌霍。

1. URL模式
顯示特定主題的頁(yè)面的URL模式與前面的所有URL模式都稍有不同货抄,因?yàn)樗鼘⑹褂弥黝}的id 屬性來(lái)指出請(qǐng)求的是哪個(gè)主題。例如朱转,如果用戶要查看主題Chess(其id 為1)的詳細(xì)頁(yè)面蟹地,URL將為http://localhost:8000/topics/1/。下面是與這個(gè)URL匹配的模式藤为,它包含在learning_logs/urls.py中:
urls.py

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

from django.conf.urls import url
from . import views

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

    # 顯示所有的主題
    url(r'^topics/$', views.topics, name='topics'),

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

我們來(lái)詳細(xì)研究這個(gè)URL模式中的正則表達(dá)式——r'^topics/(?P<topic_id>\d+)/$' 怪与。r 讓Django將這個(gè)字符串視為原始字符串,并指出正則表達(dá)式包含在引號(hào)內(nèi)缅疟。這個(gè)表達(dá)式的第二部分(/(?P<topic_id>\d+)/ )與包含在兩個(gè)斜杠內(nèi)的整數(shù)匹配琼梆,并將這個(gè)整數(shù)存儲(chǔ)在一個(gè)名為topic_id 的實(shí)參中。這部分表達(dá)式兩邊的括號(hào)捕獲URL中的值窿吩;?P<topic_id> 將匹配的值存儲(chǔ)到topic_id 中茎杂;而表達(dá)式\d+ 與包含在兩個(gè)斜桿內(nèi)的任何數(shù)字都匹配,不管這個(gè)數(shù)字為多少位纫雁。

發(fā)現(xiàn)URL與這個(gè)模式匹配時(shí)煌往,Django將調(diào)用視圖函數(shù)topic() ,并將存儲(chǔ)在topic_id 中的值作為實(shí)參傳遞給它轧邪。在這個(gè)函數(shù)中刽脖,我們將使用topic_id 的值來(lái)獲取相應(yīng)的主題。

2. 視圖
函數(shù)topic() 需要從數(shù)據(jù)庫(kù)中獲取指定的主題以及與之相關(guān)聯(lián)的所有條目忌愚,如下所示:
views.py

from django.shortcuts import render
from .models import Topic

def index(request):
    """ 學(xué)習(xí)筆記的主頁(yè) """
    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):
    """顯示單個(gè)主題及其所有的條目"""
    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)

這是第一個(gè)除request 對(duì)象外還包含另一個(gè)形參的視圖函數(shù)曲管。這個(gè)函數(shù)接受正則表達(dá)式(?P<topic_id>\d+) 捕獲的值,并將其存儲(chǔ)到topic_id 中硕糊。我們使用get() 來(lái)獲取指定的主題院水,就像前面在Django shell中所做的那樣腊徙。我們獲取與該主題相關(guān)聯(lián)的條目,并將它們按date_added 排序:date_added 前面的減號(hào)指定按降序排列檬某,即先顯示最近的條目撬腾。我們將主題和條目都存儲(chǔ)在字典context 中,再將這個(gè)字典發(fā)送給模板topic.html恢恼。

3. 模板
這個(gè)模板需要顯示主題的名稱和條目的內(nèi)容民傻;如果當(dāng)前主題不包含任何條目,我們還需向用戶指出這一點(diǎn):
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 yes.
    </li>
    {% endfor %}
</ul>

{% endblock content %}

像這個(gè)項(xiàng)目的其他頁(yè)面一樣场斑,這里也繼承了base.html漓踢。接下來(lái),我們顯示當(dāng)前的主題漏隐,它存儲(chǔ)在模板變量{{ topic }} 中喧半。為什么可以使用變量topic 呢?因?yàn)樗谧值鋍ontext 中锁保。接下來(lái)薯酝,我們開(kāi)始定義一個(gè)顯示每個(gè)條目的項(xiàng)目列表,并像前面顯示所有主題一樣遍歷條目爽柒。

每個(gè)項(xiàng)目列表項(xiàng)都將列出兩項(xiàng)信息:條目的時(shí)間戳和完整的文本吴菠。為列出時(shí)間戳,我們顯示屬性date_added 的值浩村。在Django模板中做葵,豎線(| )表示模板過(guò)濾器——對(duì)模板變量的值進(jìn)行修改的函數(shù)。過(guò)濾器date: 'M d, Y H:i' 以這樣的格式顯示時(shí)間戳:January 1, 2015 23:00心墅。接下來(lái)的一行顯示text 的完整值酿矢,而不僅僅是entry 的前50個(gè)字符。過(guò)濾器linebreaks 將包含換行符的長(zhǎng)條目轉(zhuǎn)換為瀏覽器能夠理解的格式怎燥,以免顯示為一個(gè)不間斷的文本塊瘫筐。我們使用模板標(biāo)簽{% empty %} 打
印一條消息,告訴用戶當(dāng)前主題還沒(méi)有條目铐姚。

4. 將顯示所有主題的頁(yè)面中的每個(gè)主題都設(shè)置為鏈接
在瀏覽器中查看顯示特定主題的頁(yè)面前策肝,我們需要修改模板topics.html,讓每個(gè)主題都鏈接到相應(yīng)的網(wǎng)頁(yè)隐绵,如下所示:
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 yes.</li>
    {% endfor %}
</ul>
{% endblock content %}

我們使用模板標(biāo)簽url 根據(jù)learning_logs中名為topic 的URL模式來(lái)生成合適的鏈接之众。這個(gè)URL模式要求提供實(shí)參topic_id ,因此我們?cè)谀0鍢?biāo)簽url 中添加了屬性topic.id∫佬恚現(xiàn)在棺禾,主題列表中的每個(gè)主題都是一個(gè)鏈接,鏈接到顯示相應(yīng)主題的頁(yè)面峭跳,如http://localhost:8000/topics/1/膘婶。

如果你刷新顯示所有主題的頁(yè)面缺前,再單擊其中的一個(gè)主題,將看到類似于下圖的頁(yè)面竣付。


image.png

參考

1.Python編程:從入門(mén)到實(shí)踐

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诡延,一起剝皮案震驚了整個(gè)濱河市滞欠,隨后出現(xiàn)的幾起案子古胆,更是在濱河造成了極大的恐慌,老刑警劉巖筛璧,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逸绎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡夭谤,警方通過(guò)查閱死者的電腦和手機(jī)棺牧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)朗儒,“玉大人颊乘,你說(shuō)我怎么就攤上這事∽沓” “怎么了乏悄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恳不。 經(jīng)常有香客問(wèn)我檩小,道長(zhǎng),這世上最難降的妖魔是什么烟勋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任规求,我火速辦了婚禮,結(jié)果婚禮上卵惦,老公的妹妹穿的比我還像新娘阻肿。我一直安慰自己,他們只是感情好沮尿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布丛塌。 她就那樣靜靜地躺著,像睡著了一般蛹找。 火紅的嫁衣襯著肌膚如雪姨伤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天庸疾,我揣著相機(jī)與錄音乍楚,去河邊找鬼。 笑死届慈,一個(gè)胖子當(dāng)著我的面吹牛徒溪,可吹牛的內(nèi)容都是我干的忿偷。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼臊泌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鲤桥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起渠概,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茶凳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后播揪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贮喧,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年猪狈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箱沦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雇庙,死狀恐怖谓形,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疆前,我是刑警寧澤寒跳,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站峡继,受9級(jí)特大地震影響冯袍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碾牌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一康愤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舶吗,春花似錦征冷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至腹侣,卻和暖如春叔收,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背傲隶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工饺律, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跺株。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓复濒,卻偏偏與公主長(zhǎng)得像脖卖,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巧颈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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