摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門教程。表示降序排列,默認(rèn)是升序排列。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。我們會(huì)將每周的詳細(xì)開(kāi)發(fā)文檔和代碼通過(guò)郵件列表發(fā)出。
本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。
通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,教程地址:
第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫博客的 Model 和首頁(yè)面
第二周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第二周教程 —— 博客詳情頁(yè)面和分類頁(yè)面
第三周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第三周教程 —— 文章列表分頁(yè)和代碼語(yǔ)法高亮
第四周:Django 學(xué)習(xí)小組:基于類的通用視圖詳解(一)
本周我們將實(shí)現(xiàn) blog 的標(biāo)簽云和文章按時(shí)間自動(dòng)歸檔功能。
提示:在閱讀教程的過(guò)程中,如有任何問(wèn)題請(qǐng)?jiān)L問(wèn)我們項(xiàng)目的 GithHub 或評(píng)論留言以獲取幫助,本教程的相關(guān)代碼已全部上傳在 Github。如果你對(duì)我們的教程或者項(xiàng)目有任何改進(jìn)建議,請(qǐng)您隨時(shí)告知我們。更多交流請(qǐng)加入我們的郵件列表?django_study@groups.163.com 和關(guān)注我們?cè)?GithHub 上的項(xiàng)目。
本文首發(fā)于編程派微信公眾號(hào):編程派(微信號(hào):codingpy)是一個(gè)專注Python編程的公眾號(hào),每天更新有關(guān)Python的國(guó)外教程和優(yōu)質(zhì)書籍等精選干貨,歡迎關(guān)注。
標(biāo)簽云與文章歸檔在 Blog 中也是比較常見(jiàn)的功能,標(biāo)簽云顯示每篇文章的標(biāo)簽,文章歸檔顯示某個(gè)時(shí)間段內(nèi)的發(fā)表的文章,就像這樣:
下面我們來(lái)為我們的 Blog 添加類似的功能,最終會(huì)為我們的個(gè)人 blog 實(shí)現(xiàn)類似于下面這樣的效果:
標(biāo)簽云標(biāo)簽有點(diǎn)類似于分類,只是分類由于是多對(duì)一的關(guān)系(我們規(guī)定一篇文章只有一個(gè)分類,而一個(gè)分類下可以有多篇文章),因此在我們的 model 中使用的是 ForeignKeyField 。我們規(guī)定一篇文章可以打多個(gè)標(biāo)簽,并且一個(gè)標(biāo)簽下可能會(huì)有多篇文章,是多對(duì)多的關(guān)系,因此需要使用到 ManyToManyField,其它的實(shí)現(xiàn)則和 Category(分類)十分相似。首先修改我們的 model 文件,為標(biāo)簽(tag)新建一個(gè)數(shù)據(jù)庫(kù) model,并在文章(Article)中指定它們多對(duì)多的關(guān)系:
blog/models.py class Article(models.Model): """ 文章model中添加tag關(guān)系 """ ... category = models.ForeignKey("Category", verbose_name="分類", null=True, on_delete=models.SET_NULL) tags = models.ManyToManyField("Tag", verbose_name="標(biāo)簽集合", blank=True) ... class Tag(models.Model): """ tag(標(biāo)簽)對(duì)應(yīng)的數(shù)據(jù)庫(kù)model """ name = models.CharField("標(biāo)簽名", max_length=20) created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) def __str__(self): return self.name
類似于 CategoryView,點(diǎn)擊某個(gè)標(biāo)簽可以獲取該標(biāo)簽下的全部文章,對(duì)應(yīng)的視圖函數(shù):
blog/views.py class TagView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): """ 根據(jù)指定的標(biāo)簽獲取該標(biāo)簽下的全部文章 """ article_list = Article.objects.filter(tags=self.kwargs["tag_id"], status="p") for article in article_list: article.body = markdown2.markdown(article.body, extras=["fenced-code-blocks"], ) return article_list def get_context_data(self, **kwargs): kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(TagView, self).get_context_data(**kwargs)
模板文件稍微小變了一下,添加了顯示標(biāo)簽的區(qū)域(由于模板文件代碼比較多,具體請(qǐng)參見(jiàn) github 項(xiàng)目中 blog/templates/blog/index.html 下的模板文件)。
同時(shí) IndexView 里也別忘了把 tag 加到 context 中,以便在模板中渲染顯示:
blog/views.py class IndexView(ListView): ... def get_context_data(self, **kwargs): kwargs["category_list"] = Category.objects.all().order_by("name") kwargs["date_archive"] = Article.objects.archive() # tag_list 加入 context 里: kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(IndexView, self).get_context_data(**kwargs)
配置好 url :
blog/urls.py url(r"^tag/(?P文章歸檔d+)$", views.TagView.as_view(), name="tag"),
文章歸檔我們實(shí)現(xiàn)下面的需求:
在首頁(yè)會(huì)顯示已發(fā)表文章對(duì)應(yīng)的年份列表,點(diǎn)擊相應(yīng)年份會(huì)展開(kāi)該年年份下對(duì)應(yīng)的月份列表,像這樣:
實(shí)現(xiàn)思路大概如下:Django 的 ORM 為我們提供一個(gè) datetimes 函數(shù) ( datetimes 函數(shù)用法 ),可以選出數(shù)據(jù)庫(kù)中某個(gè) model 對(duì)應(yīng)的全部已去重的時(shí)間,并且可以任意指定精度。例如,我們想選出全部文章對(duì)應(yīng)的發(fā)表時(shí)間,精確到月份:
date_list = Article.objects.datetimes("created_time", "month", order="DESC") # created_time 是 Article model 中文章發(fā)表時(shí)間,對(duì)應(yīng)的是 DatetimeField( datetimes 函數(shù)也只能用于DatetimeField ),month 即精確到月,精確到年指定為 year,天則指定為 day 即可。DESC 表示降序排列,默認(rèn)是升序排列。 # 例如有如下的一系列發(fā)表時(shí)間: 2009-01-02 2009-01-05 2009-02-02 2010-05-04 2011-06-04 2011-06-07 # 則得到的結(jié)果將是精確到月份去重后的結(jié)果: 2009-01 2009-02 2010-05 2011-06 # 這正是我們期望的結(jié)果
以這個(gè)函數(shù)為基礎(chǔ),接下來(lái)我們使用 Django 的一點(diǎn)高級(jí)技巧(自定義 Manager)來(lái)實(shí)現(xiàn)完整的功能。
什么是 Manager(管理器)?Manager 可以看成是一個(gè) model 的管理器,很多從數(shù)據(jù)庫(kù)中獲取 model 數(shù)據(jù)的方法都定義在這個(gè)類里,比如我們經(jīng)常用的 Article.objects.all(),Article.objects.filter(),這里的 objects 就是一個(gè) Manager 的實(shí)例,django 為每一個(gè) model 都指定了一個(gè)默認(rèn)的 Manager ,名字叫做 objects。但現(xiàn)在 Manager 中一些默認(rèn)的方法無(wú)法滿足我們的需求了,因此我們拓展一下 Manager 的功能,為其添加一個(gè)歸檔(archive)方法,拓展一個(gè)類的最佳方式就是繼承它:
blog/models.py class ArticleManage(models.Manager): """ 繼承自默認(rèn)的 Manager ,為其添加一個(gè)自定義的 archive 方法 """ def archive(self): date_list = Article.objects.datetimes("created_time", "month", order="DESC") # 獲取到降序排列的精確到月份且已去重的文章發(fā)表時(shí)間列表 # 并把列表轉(zhuǎn)為一個(gè)字典,字典的鍵為年份,值為該年份下對(duì)應(yīng)的月份列表 date_dict = defaultdict(list) for d in date_list: date_dict[d.year].append(d.month) # 模板不支持defaultdict,因此我們把它轉(zhuǎn)換成一個(gè)二級(jí)列表,由于字典轉(zhuǎn)換后無(wú)序,因此重新降序排序 return sorted(date_dict.items(), reverse=True)
自定義了 Manger 后需要在 model 中顯示地指定它:
blog/models.py class Article(models.model): ... # 仍然使用默認(rèn)的 objects 作為 manager 的名字 objects = ArticleManager() ...
現(xiàn)在在視圖函數(shù)中就可以調(diào)用了:
blog/views.py class IndexView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): article_list = Article.objects.filter(status="p") for article in article_list: article.body = markdown2.markdown(article.body, extras=["fenced-code-blocks"], ) return article_list def get_context_data(self, **kwargs): kwargs["category_list"] = Category.objects.all().order_by("name") # 調(diào)用 archive 方法,把獲取的時(shí)間列表插入到 context 上下文中以便在模板中渲染 kwargs["date_archive"] = Article.objects.archive() kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(IndexView, self).get_context_data(**kwargs) # 現(xiàn)在我們的時(shí)間歸檔列表格式是這樣的: [(2012,[09,02,01]),(2011,[12,10,06,01]),...] # 因此在模板中我們可以這樣循環(huán)以實(shí)現(xiàn)我們預(yù)初的設(shè)計(jì): {% for year,month_list in date_archive %} {{year}} 年 {% for month in month_list %} {{month}}月 # 使用一些 bootstrap 的組件即可實(shí)現(xiàn)上圖一樣的效果了。
完整的模板請(qǐng)參考 github 的 blog/templates/blog/index.html 模板文件。
最后一件事就是實(shí)現(xiàn)點(diǎn)擊相應(yīng)的時(shí)間后顯示該時(shí)間下的全部已發(fā)表文章列表了,實(shí)現(xiàn)思路即通過(guò) url 把對(duì)應(yīng)的年份和月份傳給視圖函數(shù),視圖函數(shù)通過(guò)年份和月份過(guò)濾所需文章,然后再模板渲染即可,實(shí)現(xiàn)和 category 與 tag 的方式十分類似:
blog/views.py class ArchiveView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): # 接收從url傳遞的year和month參數(shù),轉(zhuǎn)為int類型 year = int(self.kwargs["year"]) month = int(self.kwargs["month"]) # 按照year和month過(guò)濾文章 article_list = Article.objects.filter(created_time__year=year, created_time__month=month) for article in article_list: article.body = markdown2.markdown(article.body, extras=["fenced-code-blocks"], ) return article_list def get_context_data(self, **kwargs): kwargs["tag_list"] = Tag.objects.all().order_by("name") return super(ArchiveView, self).get_context_data(**kwargs)
url:
blog/urls.py url(r"^archive/(?Pd+)/(?P d+)$", views.ArchiveView.as_view(), name="archive"),
templates:
blog/index.html # 詳細(xì)請(qǐng)參閱 github 上的模板文件完整代碼 {% for year,month_list in date_archive %} {{year}} 年 {% for month in month_list %}接下來(lái)做什么?{{ month }} 月
我們的個(gè)人 blog 基本已經(jīng)成型了!首頁(yè)展示文章列表、標(biāo)簽云、文章歸檔、分類,文章 markdown 語(yǔ)法標(biāo)記,代碼高亮顯示,利用 django 后臺(tái),我們可以使用它來(lái)寫 blog 文章了,你可以先嘗試著找一個(gè)部署教程把 blog 部署上線。當(dāng)然我們接下來(lái)也會(huì)出如何部署的教程,敬請(qǐng)期待。下一周我們將實(shí)現(xiàn)評(píng)論功能,允許用戶對(duì)我們發(fā)表的文章進(jìn)行評(píng)論。為了學(xué)習(xí),我們將不使用第三方 app,而是重新發(fā)明輪子。
Django學(xué)習(xí)小組簡(jiǎn)介django學(xué)習(xí)小組是一個(gè)促進(jìn) django 新手互相學(xué)習(xí)、互相幫助的組織。
小組在一邊學(xué)習(xí) django 的同時(shí)將一起完成幾個(gè)項(xiàng)目,包括:
一個(gè)簡(jiǎn)單的 django 博客,用于發(fā)布小組每周的學(xué)習(xí)和開(kāi)發(fā)文檔;
django中國(guó)社區(qū),為國(guó)內(nèi)的 django 開(kāi)發(fā)者們提供一個(gè)長(zhǎng)期維護(hù)的 django 社區(qū);
上面所說(shuō)的這個(gè)社區(qū)類似于 segmentfault 和 stackoverflow ,但更加專注(只專注于 django 開(kāi)發(fā)的問(wèn)題)。
更多的信息請(qǐng)關(guān)注我們的?github 組織,本教程項(xiàng)目的相關(guān)源代碼也已上傳到 github 上。
同時(shí),你也可以加入我們的郵件列表?django_study@groups.163.com?,隨時(shí)關(guān)注我們的動(dòng)態(tài)。我們會(huì)將每周的詳細(xì)開(kāi)發(fā)文檔和代碼通過(guò)郵件列表發(fā)出。
如有任何建議,歡迎提 Issue,歡迎 fork,pr,當(dāng)然也別忘了 star 哦!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/38019.html
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門教程。我們的評(píng)論表單放在中,評(píng)論成功后返回到原始提交頁(yè)面。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。 通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,前幾期教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫博客的 Mode...
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門教程。我們的評(píng)論表單放在中,評(píng)論成功后返回到原始提交頁(yè)面。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。 通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,前幾期教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫博客的 Mode...
摘要:本節(jié)接上周的文檔學(xué)習(xí)小組博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程編寫博客的首頁(yè)面,我們繼續(xù)給博客添加功能,以及改善前面不合理的部分。返回該視圖要顯示的對(duì)象。目前小組正在完成第一個(gè)項(xiàng)目,本文即是該項(xiàng)目第二周的相關(guān)文檔。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。 上周我們完成了博客的 Model 部分,以及 Blog 的首頁(yè)視圖 IndexView。 本節(jié)接上周的文檔 Djan...
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門教程。當(dāng)分頁(yè)較多時(shí),總是顯示當(dāng)前頁(yè)及其前幾頁(yè)和后幾頁(yè)的頁(yè)碼教程中使用的是兩頁(yè),其他頁(yè)碼用省略號(hào)代替。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。 摘要:前兩期教程我們實(shí)現(xiàn)了博客的 Model 部分,以及 Blog 的首頁(yè)視圖 IndexView,詳情頁(yè)面 DetailView,以及分類頁(yè)面 CategoryVi...
摘要:學(xué)習(xí)小組是由我發(fā)起的一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。當(dāng)然如果你不喜歡英文,可以看我們的中文翻譯版本入門教程中文翻譯版。如果模板文件中有如下代碼那么渲染時(shí)就會(huì)循環(huán)渲染篇文章,并且也會(huì)被存儲(chǔ)在數(shù)據(jù)庫(kù)中文章的標(biāo)題取代。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門教程。 本節(jié)是 Django Blog 項(xiàng)目的開(kāi)篇,是?Django 學(xué)習(xí)小組的集體學(xué)習(xí)成果。Django...
閱讀 860·2021-11-25 09:44
閱讀 1063·2021-11-19 09:40
閱讀 7062·2021-09-07 10:23
閱讀 1975·2019-08-28 17:51
閱讀 1106·2019-08-26 10:59
閱讀 1928·2019-08-26 10:25
閱讀 3131·2019-08-23 18:22
閱讀 865·2019-08-23 16:58