本节主要进行了:
post_list视图函数的重构,分类信息的获取与展示,侧边栏信息的获取与展示,html代码的重构
post_list视图函数的重构
在我们的post_list视图函数中,其实逻辑已经稍微有一点复杂了,这是因为我们把多个URL的处理逻辑都放到了一个函数里,所以我们要对它进行重构.
首先是功能的抽取,对于post_list来说,只需要通过tag_id和category_id拿到对应的对象就行,那么这两个功能我们可以将他们放到类中来实现.
再Post类中新增几个方法:
1 ...前面省略 2 @staticmethod 3 def get_by_tag(tag_id): 4 try: 5 tag = Tag.objects.get(id=tag_id) 6 except Tag.DoesNotExist: 7 tag = None 8 post_list = [] 9 else: 10 post_list = tag.post_set.filter(status=Post.STATUS_NORMAL).select_related('owner', 'category') 11 12 return post_list, tag 13 14 @staticmethod 15 def get_by_category(category_id): 16 try: 17 category = Category.objects.get(id=category_id) 18 except Category.DoesNotExist: 19 category = None 20 post_list = [] 21 else: 22 post_list = category.post_set.filter(status=Post.STATUS_NORMAL).select_related('owner', 'category') 23 24 return post_list, category 25 26 @classmethod 27 def latest_posts(cls): 28 queryset = cls.objects.filter(status=cls.STATUS_NORMAL) 29 return queryset
重构后的post_list函数:
1 def post_list(request, category_id=None, tag_id=None): 2 tag = None 3 category = None 4 5 if tag_id: 6 post_lists, tag = Post.get_by_tag(tag_id) 7 elif category_id: 8 post_lists, category = Post.get_by_category(category_id) 9 else: 10 post_lists = Post.latest_posts() 11 12 context = { 13 'category': category, 14 'tag': tag, 15 'post_lists': post_lists, 16 } 17 18 return render(request, 'list.html', context=context)
显然简洁了很多.
分类信息的获取与展示
对于数据操作的部分,我们选择放到Model层,我们应该把分类分为两类,一个是置顶的分类,一个是普通的分类.我们应该要通过一个函数来返回它们.
在Category类中新增方法
1 @classmethod 2 def get_navs(cls): 3 categories = cls.objects.filter(status=cls.STATUS_NORMAL) 4 nav_categories = [] 5 normal_categories = [] 6 for cate in categories: 7 if cate.is_nav: 8 nav_categories.append(cate) 9 else: 10 normal_categories.append(cate) 11 12 return { 13 'navs': nav_categories, 14 'normal': normal_categories, 15 }
这里采取了稍微麻烦一点的方法做,简单的方法可以这样写:
1 nav_categories = categories.filter(is_nav=True) 2 normal_categories = categories.filter(is_nav=False)
第二种方法虽然相比较起来更简单,但是却要执行两次数据库操作,而第一次只会执行一次数据库操作.当然,如果分类的数据很多的话,孰优孰劣也不好说,还得根据实际开发情况来写.
最后在视图函数return之前加一句
1 context.update(Category.get_navs())
侧边栏信息的获取与展示
在侧边栏展示中我们需要获取最热文章与最新文章,但在之前的Post中并没有定义阅读量之类的,所以这里添加定义
1 pv = models.PositiveIntegerField(default=1) 2 uv = models.PositiveIntegerField(default=1)
添加一个获取最热文章的方法
1 @classmethod 2 def hot_posts(cls): 3 return cls.objects.filter(status=cls.STATUS_NORMAL).order_by('-pv').only('title', 'id')
在这里用到了only,因为侧边栏展示并不需要其他信息,对于only的使用请参考之前写的QuerySet使用,或者查阅文档.
写完之后记得迁移一下,因为模型的字段发生了改变.
接着开始编写侧边栏相关的代码.
首先在Model中处理数据源,对于SideBar,我们给它定义了四种类型,HTML,最新文章,最热文章,最近评论
我们可以在类中定义一个方法,根据不同的类型返回不同的值.
1 DISPLAY_HTML = 1 2 DISPLAY_LATEST = 2 3 DISPLAY_HOT = 3 4 DISPLAY_COMMENT = 4 5 SIDE_TYPE = ( 6 (DISPLAY_HTML, 'HTML'), 7 (DISPLAY_LATEST, '最新文章'), 8 (DISPLAY_HOT, '最热文章'), 9 (DISPLAY_COMMENT, '最近评论'), 10 ) 11 ... 12 @property 13 def content_html(self): 14 from blogApp.models import Post 15 from comment.models import Comment 16 17 result = '' 18 19 if self.display_type == self.DISPLAY_HTML: 20 result = self.content 21 elif self.display_type == self.DISPLAY_LATEST: 22 context = { 23 'posts': Post.latest_posts() 24 } 25 result = render_to_string('config/blocks/sidebar_posts.html', context) 26 elif self.display_type == self.DISPLAY_HOT: 27 context = { 28 'posts': Post.hot_posts() 29 } 30 result = render_to_string('config/blocks/sidebar_posts.html', context) 31 elif self.display_type == self.DISPLAY_COMMENT: 32 context = { 33 'comments': Comment.objects.filter(status=Comment.STATUS_NORMAL) 34 } 35 result = render_to_string('config/blocks/sidebar_comments.html', context) 36 37 return result
1 <ul> 2 {% for post in posts %} 3 <li><a href="{% url 'blog:post-detail' post.id %}">{{ post.title }}</a></li> 4 {% endfor %} 5 </ul>
1 <ul> 2 {% for comment in comments %} 3 <li> 4 <a href="{% url 'blog:post' comment.target_id %}"> 5 {{ comment.target.title }} 6 </a> 7 </li> 8 {{ comment.nickname }} : {{ comment.content }} 9 {% endfor %} 10 </ul>
html代码的重构
在我们的list.html和detail.html中,因为要展示分类和侧边栏,已经充斥着大量的重复代码,这样显然是不好的,如果以后要修改也会很麻烦,这里可以通过继承来解决这个问题.
首先抽象一个基础模板.建立一个base.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>{% block title %} 6 首页 7 {% endblock %}-友利奈绪</title> 8 </head> 9 <body> 10 <div> 11 顶部分类: 12 {% for cate in navs %} 13 <a href="{% url 'blog:category-list' cate.id %}">{{ cate.name }}</a> 14 {% endfor %} 15 </div> 16 <hr> 17 18 {% block main %} 19 {% endblock %} 20 21 <hr> 22 <div> 23 底部分类: 24 {% for cate in normal %} 25 <a href="{% url 'blog:category-list' cate.id %}">{{ cate.name }}</a> 26 {% endfor %} 27 </div> 28 <div> 29 侧边栏展示: 30 {% for sidebar in sidebars %} 31 <h4>{{ sidebar.title }}</h4> 32 {{ sidebar.content_html }} 33 {% endfor %} 34 </div> 35 </body> 36 </html>
这里的{% block %}{% endblock %}可以理解为抽象类里的抽象方法,是需要子类去实现的.
list.html
1 {% extends 'base.html' %} 2 3 {% block title %} 4 {% if tag %} 5 标签页: {{ tag.name }} 6 7 {% elif category %} 8 分类页: {{ category.name }} 9 10 {% else %} 11 Posts 12 {% endif %} 13 {% endblock %} 14 15 {% block main %} 16 <ul> 17 {% for post in post_lists %} 18 <li> 19 <a href="{% url 'blog:post-detail' post.id %}">{{ post.title }}</a> 20 <div> 21 <span>作者:{{ post.owner.username }}</span> 22 <span>分类:{{ post.category.name }}</span> 23 </div> 24 <p>{{ post.desc }}</p> 25 </li> 26 {% endfor %} 27 </ul> 28 {% endblock %}
detail.html
1 {% extends 'base.html' %} 2 {% block title %} 3 {{ post.title }}--友利奈绪 4 {% endblock %} 5 {% block main %} 6 {% if post %} 7 <h1>{{ post.title }}</h1> 8 <div> 9 <span>作者:{{ post.owner.username }}</span> 10 <span>分类:{{ post.category.name }}</span> 11 </div> 12 <hr> 13 <p> 14 {{ post.content }} 15 </p> 16 {% endif %} 17 {% endblock %}
这样代码就减少了冗余,后期维护成本也没那么高,在书中还说了解耦硬编码,不过在我之前的编写中我一直都是这样做的,所以就不重复说了.
另外说句题外话,本来写博客是为了提高自己的表达能力,结果现在看来我就像一个无情的贴代码机器,实在是有点..emmm
还有就是我在有道云笔记上面记的笔记直接贴上来一直在转圈圈,有点难受..害,明天继续加油吧.