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