django--使用ContentType对阅读数的统计进行改进

上一篇博客中讲到如果我们在Blog这个模块里面加入了read_num这个属性。

但是这样做就会导致每次点击进入博客的时候,虽然阅读数增加了,但是对应的last_updated_time也会被改变。因此我们要换一种方式来解决这个问题。

django--使用ContentType对阅读数的统计进行改进

我们通过contenttype就可以解决问题。先说contenttype是什么,我去找了官方文档。有这样一段字。

django--使用ContentType对阅读数的统计进行改进

这是一个通用关系,我们知道,我们不同的model之间可以通过外键来进行联系并且进一步的获得其他model的属性的值,

因此我们利用contenttype就是为了做这一步操作。

django--使用ContentType对阅读数的统计进行改进

我的个人理解是首先content_type里面的ContentType是一个类型,因此传给content_type的model就必须是ContentType类的,因此如果想要给content_type赋值,首先要通过ContentType.objects.get_for_model(model)得到这个model。

然后object_id就是这个model的主键值,

最后content_object这一句就是将这两个统一并且变成一个统一的外键,这个时候,ContentType这个外键可以表示任意的model。

django--使用ContentType对阅读数的统计进行改进

可以看到ContentType关联到了这么多的model.

我们先在命令行的shell模式下运行下面的代码

比如说Blog这个model,我们可以通过ContentType.objects.get_for_model(Blog)得到这个model,我们必须要知道的是,这个ContentType并不是通过某种设置之后才可以关联到这么多model,而是它本身就是可以这样子的。

因此我们在别的model里使用ContentType就可以得到我们想关联的model。所以我们看下面这个model

django--使用ContentType对阅读数的统计进行改进,

然后再看

django--使用ContentType对阅读数的统计进行改进

看这个函数的最后一句,我们将请求某个页面的request,和model-blog传入了read_statistics_once_read这个函数里面,我们看看这个函数。

django--使用ContentType对阅读数的统计进行改进

这个函数接收两个参数,一个是请求,一个是model,我们一开始说ContentType关联所有的model,函数的形参obj就是blog,因此我们通过ContentType.objects.get_for_model(obj)得到了这个model并且赋值给ct,所以这个ct就是这个blog。

obj.pk就是blog这个model个主键。我一开始想的是直接把ct改成blog,结果发现提示错误,

django--使用ContentType对阅读数的统计进行改进

django--使用ContentType对阅读数的统计进行改进

所以我们要先ContentType.objects.get_for_model(obj)才行,这样会返回一个ContentType类型的blog,我们知道ContentType类型的model可以关联到所有model,因此我们的ReadNum才可以关联到我们的blog.

ReadNUM.objects.filter(content_type=ct,object_id=obj.pk).count()是在ReadNum这个表中查找对应的blog的记录,如果没有则返回None,有则返回1。不为None的时候,直接获取然后将阅读数readnum+1,否则的话就通过ReadNum对象新建一条记录。

不过在讲之前先进入后台,因为我是把代码全写好了才写这个博客的,所以会有点出入。

django--使用ContentType对阅读数的统计进行改进

好,这是我们后台的博客管理页面,我们看到GET READ NUM那一栏,在最开始的时候,里面的参数全部都是横杆,也就是

“-”这个符号。

然后我要将其在没有阅读数的时候设置默认值为0。在将怎么设置之前先说明,这个图是我在admin里面截出来的,因此我们要去admin.py里面设置,

django--使用ContentType对阅读数的统计进行改进django--使用ContentType对阅读数的统计进行改进我们看到Blog里面是没有get_read_num这个属性的,再看Blog类,它继承了ReadNumExpandMethod这个类,它长这样。

需要注意的一点是,这个list_display里面的get_read_num必须要和继承的类的函数名相同,也就是下面这个图的函数名。这样才不会报错。

django--使用ContentType对阅读数的统计进行改进

在Blog继承了这个ReadNumExpandMethod后,Blog就会拥有get_read_num这个函数,它的返回值有两种情况,一种是存在该blog的阅读数,一种是不存在。

存在的时候就直接返回该blog的阅读数,如果不存在的话就返回0,然后通过admin.py里面的list_display显示在后台界面上。

因此阅读数为0的就显示0,不为0的就显示该博客的阅读数。