【问题标题】:Track the number of "page views" or "hits" of an object?跟踪对象的“页面查看次数”或“点击次数”?
【发布时间】:2023-03-05 15:48:01
【问题描述】:

我确信有人有一个与此类似的可插拔应用程序(或教程),但我很难找到它:我希望能够跟踪特定对象的“视图”数量(就像stackoverflow 上的一个问题有一个“视图计数”)。

如果用户没有登录,我不介意尝试放置一个cookie(或记录一个IP),这样他们就不会因为刷新页面而无意中增加了查看次数;如果用户已登录,则只允许他们跨会话/浏览器/IP 地址进行一次“查看”。我认为我不需要比这更花哨的了。

我认为最好的方法是使用与我想要跟踪的各种模型分离并使用 F 表达式(各种)的中间件——StackOverflow 上的其他问题已经暗示了这一点(1), (2), (3)。

但我想知道这段代码是否已经存在于野外——因为我不是最精明的编码器,我相信有人可以做得更好。微笑。

你见过吗?

【问题讨论】:

    标签: django view


    【解决方案1】:

    我不确定是否最好回答我自己的问题,但经过一番努力,我整理了一个认真解决问题的应用程序:django-hitcount

    您可以在the documentation page阅读有关如何使用它的信息。

    django-hitcount 的想法来自我的两个原始答案 (Teebes -and- vikingosegundo),这真的让我开始思考整个事情。

    这是我第一次尝试与社区分享一个可插拔的应用程序,希望其他人觉得它有用。谢谢!

    【讨论】:

    • Hitcount 对于这项任务来说似乎过于复杂。尤其是使用模型来计算命中数可能非常繁重。我会推荐(就像我在我的项目中所做的那样)使用 Cache 代替。智能缓存名称+超时可以很好地处理问题,而且速度非常快。
    • 很棒的应用程序,谢谢!它会自动过滤掉搜索引擎的点击吗?
    • @DenisGolomazov - 好吧,它使用 Javascript 来跟踪命中,通常搜索引擎不会执行 javascript(我认为)......所以是的:它应该忽略搜索引擎由于搜索引擎没有执行页面上的 javascript。
    • @thornomad 文档页面似乎已关闭。在 git-hub 上只有安装指南,但我想使用它,但我不知道在哪里可以找到文档。谢谢!
    • @cor - 它现在应该已经启动并运行,对此感到抱歉。
    【解决方案2】:

    你应该使用 django 内置的会话框架,它已经为你做了很多。我通过一个问答应用程序通过以下方式实现了这一点,我想在其中跟踪视图:

    在models.py中:

    class QuestionView(models.Model):
        question = models.ForeignKey(Question, related_name='questionviews')
        ip = models.CharField(max_length=40)
        session = models.CharField(max_length=40)
        created = models.DateTimeField(default=datetime.datetime.now())
    

    在views.py中:

    def record_view(request, question_id):
    
        question = get_object_or_404(Question, pk=question_id)
    
        if not QuestionView.objects.filter(
                        question=question,
                        session=request.session.session_key):
            view = QuestionView(question=question,
                                ip=request.META['REMOTE_ADDR'],
                                created=datetime.datetime.now(),
                                session=request.session.session_key)
            view.save()
    
        return HttpResponse(u"%s" % QuestionView.objects.filter(question=question).count())
    

    Vikingosegundo 可能是对的,尽管使用内容类型可能是更可重用的解决方案,但绝对不要在跟踪会话方面重新发明轮子,Django 已经这样做了!

    最后,您可能应该通过 Ajax 或 css 链接调用记录点击的视图,这样搜索引擎就不会增加您的计数。

    希望有帮助!

    【讨论】:

    • 这确实有帮助 - 你如何使用会话信息,一切都会很有用。我也喜欢 vikingosegundo 的方法——它更通用。如果我找不到其他任何东西,我可以将两者结合起来。而且,必须牢记搜索引擎——我没有想到这一点。但它们可能包含某个标题,可以检查...不是吗?
    • 您绝对可以检查标题。这个先前的问题stackoverflow.com/questions/45824/… 有一些非常好的信息(非 django 特定的)。
    • 统计一个页面的浏览量对我来说很有意义。
    【解决方案3】:

    你可以创建一个通用的 Hit 模型

    class Hit(models.Model):
        date = models.DateTimeField(auto_now=True)
        content_type = models.ForeignKey(ContentType)
        object_id = models.PositiveIntegerField()
        content_object = generic.GenericForeignKey('content_type', 'object_id')
    

    在你的 view.py 中你写了这个函数:

    def render_to_response_hit_count(request,template_path,keys,response):
        for  key in keys:
            for i in response[key]:
                 Hit(content_object=i).save()
        return render_to_response(template_path, response)
    

    以及您感兴趣的视图返回

    return render_to_response_hit_count(request,   'map/list.html',['list',],
            {
                'list': l,
            })
    

    这种方法让您不仅可以计算点击次数,还可以按时间、内容类型等过滤点击历史记录...

    由于命中表可能会快速增长,您应该考虑删除策略。

    【讨论】:

    • 是的 - 我确实看到了你的代码,它确实引起了我的注意!微笑。但是,希望应用程序中已有的东西可以导入然后使用......但是,我可能会尝试将您的 Hit 模型(和通用方面)与@Teebes 的会话建议结合起来。谢谢。
    • 当然,你应该把它们结合起来。通过会话,您可以获得有关单个用户的信息。并且通过我的方法,您可以控制要触发的视图,而无需一遍又一遍地编写相同的代码。把它带到你的解决方案中。
    • 错字:DateTimeFiles 应该读作 DateTimeField,不是吗?
    • 感谢@vikingsegundo 这个有用的答案。您应该为 Django v2/v3 更新它。此外,您可以添加示例模板代码。
    • @Angeles89 你听起来要求很高。我已经好几年没用过 django 了。不太可能我会更新这个。但是猜猜看:您可以自己添加这些更改。
    【解决方案4】:

    我知道这个问题是个老问题,而且thornomad 已经发布了一个应用程序来解决问题并用我的解决方案启发我。我想分享这个解决方案,因为我没有找到关于这个主题的太多信息,它可能对其他人有帮助。 我的方法是根据视图路径(url)制作一个通用模型可以与任何视图一起使用。

    models.py

    class UrlHit(models.Model):
        url     = models.URLField()
        hits    = models.PositiveIntegerField(default=0)
    
        def __str__(self):
            return str(self.url)
    
        def increase(self):
            self.hits += 1
            self.save()
    
    
    class HitCount(models.Model):
        url_hit = models.ForeignKey(UrlHit, editable=False, on_delete=models.CASCADE)
        ip      = models.CharField(max_length=40)
        session = models.CharField(max_length=40)
        date    = models.DateTimeField(auto_now=True)
    

    views.py

    def get_client_ip(request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def hit_count(request):
        if not request.session.session_key:
            request.session.save()
        s_key = request.session.session_key
        ip = get_client_ip(request)
        url, url_created = UrlHit.objects.get_or_create(url=request.path)
    
        if url_created:
            track, created = HitCount.objects.get_or_create(url_hit=url, ip=ip, session=s_key)
            if created:
                url.increase()
                request.session[ip] = ip
                request.session[request.path] = request.path
        else:
            if ip and request.path not in request.session:
                track, created = HitCount.objects.get_or_create(url_hit=url, ip=ip, session=s_key)
                if created:
                    url.increase()
                    request.session[ip] = ip
                    request.session[request.path] = request.path
        return url.hits
    

    【讨论】:

    • 谢谢,我喜欢你的方法。请您进一步详细说明如何在有人访问页面时增加视图,即您能否提供 urls.py 的代码
    • 该函数可以在需要统计其访问次数的视图内调用,由于该函数返回命中数,因此可以将其添加到上下文数据中并在模板中使用。但是,我已经将此函数转换为装饰器here
    • 谢谢Radico。我在我的网站上使用了你的方法,效果非常好。我在基于类的视图中使用它:)
    • 观众人数不会是唯一的吧?我们将收到同一用户的重复计数,因为它的访问计数
    【解决方案5】:

    我通过创建一个模型 PageViews 并在其中创建一个“Hits”列来做到这一点。每次点击主页网址时。我增加Hit 列的第一行也是唯一一行并将其渲染到模板。这是它的样子。

    Views.py

    def Home(request):
    
        if(PageView.objects.count()<=0):
            x=PageView.objects.create()
            x.save()
        else:
            x=PageView.objects.all()[0]
            x.hits=x.hits+1
            x.save()
        context={'page':x.hits}
        return  render(request,'home.html',context=context)
    

    Models.py

    class PageView(models.Model):
        hits=models.IntegerField(default=0)
    

    【讨论】:

    • 您不应在不使用 SESSIONS 和 IP 的情况下添加页面点击功能。
    • 嘿,用这种方法我得到这个错误``` OperationalError at / no such table: home_pageview ``
    • @ManishShah:您可能需要迁移和迁移您的数据库
    【解决方案6】:

    我是使用 cookie 完成的。不知道这样做是否是个好主意。以下代码首先查找已设置的 cookie,如果存在则增加 total_view 计数器,如果不存在则增加 total_views 和 unique_views。 total_views 和 unique_views 都是 Django 模型的字段。

    def view(request):
        ...
        cookie_state = request.COOKIES.get('viewed_post_%s' % post_name_slug)
        response = render_to_response('community/post.html',context_instance=RequestContext(request, context_dict))
        if cookie_state:
            Post.objects.filter(id=post.id).update(total_views=F('total_views') + 1)
        else:
            Post.objects.filter(id=post.id).update(unique_views=F('unique_views') + 1)
            Post.objects.filter(id=post.id).update(total_views=F('total_views') + 1)
                            response.set_cookie('viewed_post_%s' % post_name_slug , True, max_age=2678400)
        return response
    

    【讨论】:

    • 嗨@MuditJain,我不明白cookie_state = request.COOKIES.get('viewed_post_%s' % post_name_slug) 如何获取我的网址的cookie,例如:re_path('gigs/(?P&lt;id&gt;[0-9]+)/$', views.gig_detail, name='gig-detail')
    猜你喜欢
    • 2013-06-29
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多