zoukankan      html  css  js  c++  java
  • 博客阅读计数优化

    为了解决上一篇写到的计数功能的单一,我们把把计数功能独立,把博客内容和计数字段分开,再通过外键关联

    class Blog(models.Model):
    title = models.CharField(max_length=50)
    blog_type = models.ForeignKey(BlogType,on_delete=models.CASCADE)
    content = RichTextUploadingField()
    author = models.ForeignKey(User,on_delete=models.CASCADE)

    created_time = models.DateTimeField(auto_now_add=True)
    last_updated_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
    return '<Blog: %s>' %self.title

    class Meta:
    ordering = ['-created_time']

    class ReadNum(models.Model):
    read_num = models.IntegerField(default=0)
    blog = models.OneToOneField(Blog,on_delete=models.CASCADE)
    把原来Blog模型中的计数字段删除,新增ReadNum类,并于Blog一对一关联,再同步数据库
    admin中显示
    @admin.register(ReadNum)
    class ReadNumAdmin(admin.ModelAdmin):
    list_display = ('read_num','blog')
    此时在admin后台修改博客时就不会影响到博客的计数。

    为了在后台blogs中看到每篇博客自己的计数,可以在Blog模型写一个方法,然后admin中调用这个方法。模型中的方法在admin和前端可以调用。
    因为是一对一关联,此时反向查询,基于对象,只需对象.类名小写得到目标对象
    利用错误如果不存在记录则返回0,这里是不管什么错误,也可以导入错误的集合,错误的集合里有对象不存在的情况。
    def get_read_num(self):
    try:
    return self.readnum.read_num
    except Exception as e:
    return 0

    from django.db.models.fields import exceptions
    def get_read_num(self):
    try:
    return self.readnum.read_num
    except exceptions.ObjectDoesNotExist:
    return 0

    在前端显示的需要修改vires和前端页面,views中计数+1因为博客和计数的模型分离,需要判断对应的记录是否存在
    if ReadNum.objects.filter(blog=blog).count(): #判断这条博客对应的计数模型有没有
    #存在记录,获取这个计数对象
    readnum = ReadNum.objects.get(blog=blog)
    else:
    #不存在对应的记录,创建
    readnum = ReadNum(blog=blog)
    #计数加1
    readnum.read_num +=1
    readnum.save()


    2.可以对任意模型计数
    计数——>博客、教程、公告、其他等等 都需要进行阅读的计数,如果我们要对一个新的模型进行计数,此时计数是一对一绑定的,那么只能再写一次代码,每多一个需要计数的,
    就需要多创建一个模型。
    可以让计数模型——>关联哪个模型、对应主键值,这样一个模型可以统计各种模型的数据——>Django中有ContentType自动把这些东西记录下来,它记录了我们这个项目所有的模型,

    >>> from django.contrib.contenttypes.models import ContentType>>> ContentType

    <class 'django.contrib.contenttypes.models.ContentType'>
    >>> ContentType.objects.all()
    <QuerySet [<ContentType: log entry>, <ContentType: group>, <ContentType: permission>, <ContentType: user>, <ContentType: blog>, <ContentType: blog type>, <Conten
    tType: read num>, <ContentType: content type>, <ContentType: session>]>

    删除原有计数模型,建立一个read_statistics app

    from django.db import models
    from django.contrib.contenttypes.fields import GenericForeignKey
    from django.contrib.contenttypes.models import ContentType

    class ReadNum(models.Model):
    read_num = models.IntegerField(default=0)

    #将您的模型ForeignKey 设为ContentType 通过ContentType找到具体的模型
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField() #记录对应模型的主键值 该字段可以存储您将要关联的模型中的主键值
    #给您的模型一个 GenericForeignKey,并为其传递上述两个字段的名称。如果将这些字段分别命名
    # 为“ content_type”和“ object_id”,则可以忽略这些-这些是默认字段名称 GenericForeignKey。
    content_object = GenericForeignKey('content_type', 'object_id')

    在admin中注册显示
    from django.contrib import admin
    from .models import ReadNum

    @admin.register(ReadNum)
    class ReadNumAdmin(admin.ModelAdmin):
    list_display = ('read_num','content_object')

    添加一条记录后,在shell中调试

    >>> from read_statistics.models import ReadNum
    >>> from blog.models import Blog
    >>> from django.contrib.contenttypes.models import ContentType
    >>> ContentType.objects.get_for_model(Blog)
    <ContentType: blog>
    >>> ct = ContentType.objects.get_for_model(Blog)
    >>> blog = Blog.objects.first()
    >>> blog
    <Blog: <Blog: for 30>>
    >>> blog.pk
    36
    >>> ReadNum.objects.filter(content_type=ct,object_id=blog.pk)
    <QuerySet [<ReadNum: ReadNum object (1)>]>
    >>> rn = ReadNum.objects.filter(content_type=ct,object_id=blog.pk)[0]
    >>> rn
    <ReadNum: ReadNum object (1)>
    >>> rn.read_num
    10

    根据shell获取数据的方法在博客模型中重写获取博客阅读数量的方法

    def get_read_num(self):
    try:
    ct = ContentType.objects.get_for_model(self) #获取模型类或模型实例,然后返回ContentType代表该模型的实例 <ContentType: blog>
    readnum = ReadNum.objects.get(content_type=ct, object_id=self.pk)
    return readnum.read_num
    except exceptions.ObjectDoesNotExist:
    return 0

    然后修改下views中的计数规则
    def blog_detail(request, blog_pk):
    blog = get_object_or_404(Blog, pk=blog_pk)
    if not request.COOKIES.get('blog_%s_readed' % blog_pk):
    ct = ContentType.objects.get_for_model(Blog)
    if ReadNum.objects.filter(content_type=ct, object_id=blog.pk).count(): #判断这条博客对应的计数模型有没有
    #存在记录,获取这个计数对象
    readnum = ReadNum.objects.get(content_type=ct, object_id=blog.pk)
    else:
    #不存在对应的记录,创建
    readnum = ReadNum(content_type=ct, object_id=blog.pk)
    #计数加1
    readnum.read_num +=1
    readnum.save()
    此时就可以了,但是还可以进行通用性处理,把该封装的代码封装到计数app里面。通过类的继承,把博客的获取阅读数量方法放到计数模型中,并创建一个类,
    之后让博客模型继承这个类。
    class ReadNumExpandMethod():
    def get_read_num(self):
    try:
    ct = ContentType.objects.get_for_model(self) #获取模型类或模型实例,然后返回ContentType代表该模型的实例
    readnum = ReadNum.objects.get(content_type=ct, object_id=self.pk)
    return readnum.read_num
    except exceptions.ObjectDoesNotExist:
    return 0
    把views中的计数规则放到计数app的工具文件中写成一个方法,让views直接调用方法
    from django.contrib.contenttypes.models import ContentType
    from .models import ReadNum

    def read_statistics_once_read(request, obj):
    ct = ContentType.objects.get_for_model(obj)
    key = '%s_%s_read' % (ct.model, obj.pk)
    if not request.COOKIES.get(key):
    if ReadNum.objects.filter(content_type=ct, object_id=obj.pk).count(): # 判断这条博客对应的计数模型有没有
    # 存在记录,获取这个计数对象
    readnum = ReadNum.objects.get(content_type=ct, object_id=obj.pk)
    else:
    # 不存在对应的记录,创建
    readnum = ReadNum(content_type=ct, object_id=obj.pk)
    # 计数加1
    readnum.read_num +=1
    readnum.save()
    return key

    可以传过来一个对象,通过对象获取模型类或模型实例,然后返回ContentType代表该模型的实例,获取主键,

    >>> ct
    <ContentType: blog>
    >>> ct.model
    'blog'

    最后返回cookie的键

    在博客的视图中调用该方法

    read_cookie_key = read_statistics_once_read(request, blog)
     




  • 相关阅读:
    异常
    带参数的方法
    变量,基本类型,数据类型和运算符
    数据类型转换(针对数字类型)
    this关键字
    面向对象DAO模式
    常见类 Object
    方法和包
    final关键字
    abstract关键字
  • 原文地址:https://www.cnblogs.com/lag1/p/13832403.html
Copyright © 2011-2022 走看看