文章被浏览的数量,简单的方式处理是通过Post里设置read_num进行记录,在views中对应详情页处理函数detail(request,pk)里处理,引入cookie优化阅读量概念的——关闭浏览器表示一次阅读。
models.py:Post #read_num = models.PositiveIntegerField('阅读量',default=0)
views.py:detail(request,pk) post = get_object_or_404(Post,pk=pk) strs = 'post_%s_readed'% pk obj_type = ContentType.objects.get_for_model(Post) v = ViewNum.objects.get_or_create(content_type=obj_type,object_id=post.id) if strs not in request.COOKIES: post.read_num+=1 post.save() …… #设置临时cookie,该cookie有效期知道浏览器关闭 response.set_cookie( strs,True)
然而,每次打开详情页调用一次detail就保存了一次post,使得Post中设置了auto_now的modified_time概念上从“最后修改”变成了“最后浏览”。
modified_time = models.DateTimeField('更新时间',auto_now=True,null=True)
所以一个解决办法是把read_num放到另一个模型表中保持更新,而不影响Post,通过设置一般外键关系建立两模型表的关系。
新的模型表ViewNum利用ContentObject——这是一个模型总表实例的概念,通过ContentType和Object_id可以访问关联的ViewNum记录。
class ViewNum(models.Model): content_type=models.ForeignKey(ContentType) object_id=models.PositiveIntegerField() content_object=GenericForeignKey() view_nums = models.PositiveIntegerField(default=0)
此处,我们只需用Post和post便可以访问view_nums
views.py:detail(request,pk) obj_type = ContentType.objects.get_for_model(Post) v = ViewNum.objects.get_or_create(content_type=obj_type,object_id=post.id) if strs not in request.COOKIES: v[0].view_nums+=1 v[0].save()
在模板文件中,通过自定义标签访问view_nums,自定义模板标签get_view_num
@register.simple_tag def get_view_num(post_id): obj_type = ContentType.objects.get_for_model(Post) v = ViewNum.objects.get_or_create(content_type=obj_type, object_id=post_id) return v[0].view_nums
在这里与杨仕航的做法不一样,自定义模板标签传入参数Object_id,概念更加清晰,即已知一个post实例,获取该实例对应的view_nums。v[0]因为get_or_create返回一个元组,其第一个元素为ViewNum实例。
自定义标签使用如下:
{% load blog_tags %} …… {% get_view_num post.id %}
其中自定义标签get_view_num位于blog_tags中,在templatetags文件夹下。
在admin中Post管理注册时,也不能通过字段read_num了,需要通过函数访问对应的ViewNum。
admin.py:PostAdmin def view_num_count(self,obj): return sum(map(lambda x:x.view_nums,obj.view_num.all())) view_num_count.short_description = '阅读量'
lambda取实例对应的字段,同时需要设置逆向关联,才能使用view_num.all()。
models.py:Post view_num = GenericRelation(ViewNum)
当设置了逆向关联时,即可通过post.view_num.all()取得关联对象。自定义模板标签也可以修改如下,给自定义标签传递的是Post实例post
@register.simple_tag def get_view_n(post): return sum(map(lambda x:x.view_nums,post.view_num.all()))
总结:MVC中,M中通过GenericForeignKey,GenericRelation设置一般外键关系和逆向关联;C中通过ContentType和Object_id获取关联的对象进行操作,V中通过自定标签进行呈现。
Last Modified·2017年5月6日 22:14
您尚未登录,请先登录才能评论。