django框架之BBS項目之個人博客頁面
內容回顧:
首先我們來回顧一下ORM的分組和聚合
https://www.cnblogs.com/liwenzhou/p/8660826.html
上一步實現了博客園的頁面展示,今天我們實現個人博客頁面的展示
當我們進入個人的博客園的時候,我們想讓url上會拼接個人的名字:http://127.0.0.1:8000/blog/yangbo 類似這樣。
所以我們實現的思路是當我們點擊個人的名字時,跳轉到相應的個人blog,我們的思路是這樣的,在匹配url路由時,點擊人名,我們將人名傳到後面的視圖函數中,然後在視圖函數中通過數據庫的查找,在頁面上渲染相應的數據。
這裏提供兩種方法。
第一種:
匹配路由時這樣匹配:
url(r‘^blog/(?P<username>\w+)/$‘,views.PersonIndex.as_view(),name=‘name‘),
然後再頁面上利用地址的反向解析取到url,並且把username傳給了後面的試圖函數。
<a href="{% url ‘name‘ username=article.user.username %}"><span>{{ article.user.username }}</span></a>
第二種:
在頁面上直接這樣寫:
<a href="/blog/{{article.user.username}}"><span>{{ article.user.username }}</span></a>
匹配路由時這樣匹配:
url(r‘^blog/(\w+)/$‘,views.PersonIndex.as_view()),
這裏也可以嘗試用一下二級路由,先在urls.py文件下這樣寫:
from blog import urls as blog_urls # 二級路由 url(r‘^blog/‘, include(blog_urls)),
在app的文件夾下在創建一個urls.py文件,這樣寫:
from django.conf.urls importurl from blog import views urlpatterns = [ url(r‘^(\w+)/$‘, views.PersonIndex.as_view()), ]
然後就可以寫試圖函數了。
再寫視圖函數之前,可以復習一下mysql的增刪改查操作和ORM的操作。
https://www.cnblogs.com/liwenzhou/p/8660826.html
我們在數據庫查詢歸檔日期的時候,需要學習一個新的知識:就是時間的格式化
我們用原生的sql語句格式化:
select DATA_FORMAT(create_time,‘%Y-%m‘) from blog_article
ORM的日期格式化:
from django.db.models import Count # 對當前blog的所有文章按照年月 分組 查詢
# 1. models.Article.objects.filter(user=user_obj) --> 查詢出當前作者寫的所有文章
# 2. .extra(select={"y_m": "DATE_FORMAT(create_time, ‘%%Y-%%m‘)"} --> 將所有文章的創建時間格式化成年-月的格式,方便後續分組
# 3. .values("y_m").annotate(c=Count("id")) --> 用上一步時間格式化得到的y_m字段做分組,統計出每個分組對應的文章數
# 4. .values("y_m", "c") --> 把頁面需要的日期歸檔和文章數字段取出來 archive_list = models.Aticle.objects.filter(user=username).extra( select={‘y_m‘:‘DATE_FORMAT‘(create,"%%Y-%%m")} ).value(‘y_m‘).annotate(c=Count(‘id‘)).value(‘y_m‘,‘c‘)
還有一種方法:就是
# 更高靈活度的方式執行原生SQL語句 from django.db import connection cursor = connection.cursor() cursor.execute("""SELECT DATE_FORMAT(create_time, ‘%Y-%m‘) FROM blog_article;""") ret = cursor.fetchall() print(ret)
然後再頁面中渲染。
整個的視圖函數就是:
class PersonIndex(views.View): def get(self,request,username): user_obj = models.UserInfo.objects.filter(username=username).first() blog = user_obj.blog category_list = models.Category.objects.filter(blog=blog) tag_list = models.Tag.objects.filter(blog=blog) article_list = models.Article.objects.filter(user=user_obj) archive_list = models.Article.objects.filter(user=user_obj).extra( select={‘y_m‘:‘DATE_FORMAT(create_time,"%%Y-%%m")‘} ).values(‘y_m‘).annotate(c=Count(‘id‘)).values(‘y_m‘,‘c‘) return render(request,‘person.html‘,{ ‘article_list‘:article_list, ‘user_obj‘:user_obj, ‘category_list‘:category_list, ‘tag_list‘:tag_list, ‘archive_list‘:archive_list })
現在我們的需求就是當我們點擊相應的文章標簽就展示文章,點擊相應的文章分類就展示文章。
接著上一步想,當我們點擊文章分類的某一個時,會在url上顯示blog/yangbo/category/標簽名。我們就可以把url設計成這樣,
url(r‘^blog/(\w+)/category/(\w+)/$‘, views.category), url(r‘^blog/(\w+)/tag/(\w+)/$‘, views.tag), url(r‘^blog/(\w+)/archive/(\w+)/$‘, views.archive),
但是這樣寫會不會很麻煩,因為有三個url就會有三個試圖函數,我們想著優化一下
優化第一版 url(r‘^blog/(\w+)/(category|tag|archive)/(\w+)/$‘, views.threeinone),
我們將三個url合成一個,但是我們又想到點擊標簽後的頁面和原來的頁面是一樣的只是頁面展示的文章不一樣,所以我們可以繼續優化。
# 優化第二版 url(r‘^(\w+)/(category|tag|archive)/(.*)/$‘, views.PersonIndex.as_view()),
這樣我們不用重新寫一個視圖函數,我們可以在原來的視圖函數中相應判斷如果是category中的文章,就展示相應的文章,因為url中的正則分組把括號中的東西都傳給試圖函數了
views.py代碼:
class PersonIndex(views.View): def get(self,request,username,*args): user_obj = models.UserInfo.objects.filter(username=username).first() blog = user_obj.blog category_list = models.Category.objects.filter(blog=blog) tag_list = models.Tag.objects.filter(blog=blog) article_list = models.Article.objects.filter(user=user_obj) archive_list = models.Article.objects.filter(user=user_obj).extra( select={‘y_m‘:‘DATE_FORMAT(create_time,"%%Y-%%m")‘} ).values(‘y_m‘).annotate(c=Count(‘id‘)).values(‘y_m‘,‘c‘) print(username) print(args) if args: if args[0] == ‘category‘: article_list = article_list.filter(category__title=args[1]) elif args[0] == ‘tag‘: article_list = article_list.filter(tags__title=args[1]) else: try: year,mouth = args[1].split("-") print(year,mouth) article_list = article_list.filter(create_time__year=year,create_time__mouth=mouth) except Exception as e: article_list = [] print(article_list) print(args[1]) return render(request,‘person.html‘,{ ‘article_list‘:article_list, ‘user_obj‘:user_obj, ‘category_list‘:category_list, ‘tag_list‘:tag_list, ‘archive_list‘:archive_list })
在html中我們需要將文章標簽分類歸檔的代碼改一下:
#文章分類
<a href="/blog/{{ user_obj.username }}/category/{{ category.title }}">{{ category.title }} ({{ category.article_set.all.count }})</a>
#文章標簽
<a href="/blog/{{ user_obj.username }}/tag/{{ tag.title }}">{{ tag.title }} ({{ tag.article_set.all.count }})</a>
#歸檔
<a href="/blog/{{ user_obj.username }}/archive/{{ archive.y_m }}">{{ archive.y_m }} ({{ archive.c }})</a>
django框架之BBS項目之個人博客頁面