内容回顾:
首先我们来回顾一下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 import url 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的日期格式化:(ORM执行原生sql语句)
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()
# 光标执行sql语句 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>