热门统计

实现功能:

  • 今日热门文章排行
  • 昨日热门文章排行
  • 最近7天热门文章排行

UTOOLS1588061262004.png

大致步骤:

  1. 找到时间范围以及模型类型
  2. 按浏览量字段进行降序

在统计类中的utils

def get_hot_today_data(content_type):
    """获取今天的热门数据"""
    today = timezone.now().date()
    # 通过模型以及日期,进行过滤,过滤之后再降序
    read_detail = ReadDetail.objects.filter(content_type=content_type, date=today).order_by('-read_num')
    # 做演示,我们就只取两个数据
    return read_detail[:2]

然后在视图层views调用此方法

def home(request):
    context = {}
    blog_content_type = ContentType.objects.get_for_model(Blog)
    context['read_nums'], context['dates'] = get_week_read_data(blog_content_type)
    
    # 获取查询集
    context['today_hots'] = get_hot_today_data(blog_content_type)
    return render(request, 'home.html', context)

最后在模板层布局

<div class="row">
    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">今日热门</div>
            <div class="panel-body">
                <ul class="list-group">
                    {% for today_hot in today_hots %}
                    <li class="list-group-item">
                        <a href="{% url 'blog_detail' today_hot.object_id %}">{{ today_hot.content_object.title }}({{ today_hot.read_num }})</a>
                    </li>
                    {% endfor %}
                </ul>
            </div>
        </div>
    </div>
</div>

这里再说明下,我们是通过ReadNum模型取到的数据

所以这个文章标题,直接取,是拿不到的

我们模型层定义了一个content_object,所以可以通过这个间接取出文章标题以及id

例如:{{ today_hot.content_object.title }}取出文章标题

以上,就是获取今日热门数据排行的流程

昨日排行和上方类似,只是查询的时间减少了1天而已

下面,再记录下周文章热门排行

  1. 获取7天之内的所有数据
  2. 筛选符合博文类型的数据
  3. 一篇博文会多次出现,所以按博文分组
  4. 分组后的每条博文求7天内的访问总和
  5. 按每个的访问总和降序

在sql中,我们知道有group操作,在Django中同样也有此操作,只是样式不一样

在博文的模型类中,新增

# 从统计模块中导入模型
from read_record.models import ReadDetail
# ...
# 博文模型类新增
read_details = GenericRelation(ReadDetail)
# ...

GenericRelation这个在官方文档中,被称为反向通用关系

默认情况下,相关对象返回到该对象的关系不存在。设置 related_query_name 来创建一个对象从关联对象返回到对象自身。这允许查询和筛选相关的对象。

不明白上面的意思,没关系,往下看,结合实例来理解

注意:这个虽然在模型类中,但是不用同步数据库,也不会存在数据表中

来到统计模块utils中

新建获取周热门数据方法

get_hot_weekly_data():
    # 获取当前时间
    today = timezone.now().date()
    # 算出7天前的时间
    week_ago = today - datetime.datedelta(days=7)
    
    blogs = Blog.object.filter(read_details__date__lt=today, read_details__date__gt=week_ago)\
                .values('id', 'title')\
                .annotate(read_num_sum=Sum('read_details__read_num'))\
                .order_by('-read_num_sum')
    return blogs[:2]

看到上方的一大坨可能有些懵逼,一一来解释

filter(read_details__date__lt=today, read_details__date__gt=week_ago)

我们是Blog进行操作的,read_details__date这个数据其实是统计表中ReadDetail类中的字段

那么再加上__lt就是小于的意思

通过这里,我们也能理解了GenericRelation

一句话就是我可以通过现在这个类,直接访问所关联到的另一个类

GenericRelation(ReadDetail)Blog中关联了ReadDetail,那么Blog的对象就可以直接访问ReadDetail类中的字段

values('id', 'title') 只取idtitle字段

类似于我们mysql

select id, title
from table_a

annotate(read_num_sum=Sum('read_details__read_num'))这一整部操作,类似sql中的分组并求和

按博客分组,并按read_details__read_num进行求和

iddateread_numobject_id
14-12103
24-11113

假设一个上方的数据表,这两条数据都是3号文章的访问记录

时间分别是4-12,4-11 都是在最近7天之内

annotate(read_num_sum=Sum('read_details__read_num'))做的操作就是,将这两条数据合并,并且求和read_num 如此就得到了这段时间这篇文章总的阅读量,这里我们给了read_num_sum用来保存求和之后的结果,也方便之后的排序操作

order_by('-read_num_sum') 最后再降序即可

视图层

# 简单调用即可
context['week_hots'] = get_hot_weekly_data()

模板层

<div class="col-md-4">
    <div class="panel panel-default">
        <div class="panel-heading">本周热门</div>
        <div class="panel-body">
            <ul class="list-group">
                {% for week_hot in week_hots %}
                <li class="list-group-item">
                    <a href="{% url 'blog_detail' week_hot.id %}">{{ week_hot.title }}({{ week_hot.read_num_sum }})</a>
                </li>
                {% endfor %}
            </ul>
        </div>
    </div>
</div>

week_hot.id 直接使用id

week_hot.title直接使用title

week_hot直接使用read_num_sum

这些都是在Blog模型实现的,所以直接调用对应字段即可

数据缓存

现在,每一个用户的每一次请求的每一个网页都需要我们服务器完成计算才能返回

但是有些数据很少变动一次,每次请求都是得到的重复数据,但还是每次请求都会进行数据库等操作

对于这样变动很少的数据,可以使用缓存

将固定数据保存至缓存内,下一次请求的时候,直接从缓存中取出来返回去,这样就不用每次都去数据库查询了

视图文件

# 导入缓存模块
from django.core.cache import cache

请求过来的时候,我们先去缓存里看,有没有对应的响应数据

有,直接返回

无,再继续其他操作,并将响应内容存入缓存

以获取周热门数据为例

    # 缓存中获取
    hot_weekly_data = cache.get('hot_weekly_data')
    # 判断有无
    if not hot_weekly_data:
        # 没有就执行就去数据库里面查询
        hot_weekly_data = get_hot_weekly_data()
        # 查询之后,设置缓存
        cache.set('hot_weekly_data', hot_weekly_data, 10)
        print("not cache")
    else:
        print('use cache')

cache的set方法有三个参数,分别是keyvalue,缓存时间(单位:秒)

为了测试看效果,就设置的10秒

我们第一次去请求:无缓存

UTOOLS1588065735667.png

10秒中之内,再次请求,输出使用了缓存

UTOOLS1588065770756.png

10秒过去,再次没有使用缓存

UTOOLS1588065817102.png

更多关于缓存的使用

https://docs.djangoproject.com/zh-hans/3.0/topics/cache/

Last modification:April 28th, 2020 at 05:26 pm