如何在网络应用程序中显示近期项目以进行个性化设置?

时间:2018-12-07 10:33:51

标签: django github django-models django-queryset personalization

在GitHub中,您会注意到,当您要引用现有问题或在项目下标记问题时,GitHub会聪明地向您显示您最近第一次访问的最新项目。

以上次访问的顺序显示最近的项目的示例

enter image description here

按上次访问顺序显示最近问题的示例 enter image description here

我正在使用django来构建网络应用程序,并且我希望合并相同的功能。

我有两个想法,但还没有实现:

1。一张巨大的桌子,存储着个人用户的所有访问次数

我应该有一个巨型表来存储所有用户访问的所有项目吗?如果是这样,我该如何将其与我要搜索的主表结合起来以正确产生排序?

2。在各个主表中添加一个visited

我显然不能在主表中添加新的日期时间列“ visited”,因为这将意味着没有个性化。

我在理解方面缺少什么?

还可以公平地假设我需要限制每个用户存储的最新商品的数量吗?

意思是,使用GitHub示例,每个用户最多只能存储5个最新项目或问题。

3 个答案:

答案 0 :(得分:1)

是否有一个包含用户FK,最后访问的URL和日期时间的表不起作用? 然后创建一个API(drf)为该用户返回最新的5:

visits.objects.filter(user=request.user).order_by('-datetime_visited')[:5]

它会变得很大,也许您可​​以限制为每个用户只保留5个,并在插入时删除。 在每个页面的每个获取请求中,您可以:

last = visits.objects.filter(user=request.user).order_by('datetime_visited').first()
last.delete()
visits.objects.create(user=request.user, url=page_url, datetime_visited=datetime.datetime.now())

在其中放置自定义代码也是一个好主意: Limit the number of records in a Model that can have a value per user

答案 1 :(得分:0)

  

1。一张巨大的桌子,存储着个人用户的所有访问次数

这就是我要实现的方式:

class Visit(models.Model):
    user = ForeignKey(User, related_name="recent_visits")
    item = ForeignKey(Item, related_name="visitors")
    last_visited = DateTimeField()

然后,在User序列化程序中,您可以有一个SerializerMethodField来匹配一定数量的最近访问的项目,例如:

class VisitSerializer(models.Model):
    item = YourItemSerializer()

    class Meta:
        model = Visit
        fields = ['item', 'last_visited']


class UserSerializer(serializers.ModelSerializer):
    recent_visits = serializers.SerializerMethodField()

    def get_items(self, obj):
        # you could also get the value of 5 from a constant or your settings or 
        # even the API itself
        items = Item.recent_visits.filter(user=obj)[:5]
        serializer = VisitSerializer(instance=items, many=True)
        return serializer.data

但是,如果您只想保留一小部分最近访问过的商品,并且不希望基于用户的扩展访问历史记录有任何逻辑,则这可能是一个过大的选择。

在用户模型中保留商品信息

如果您只想显示有关商品的某些信息(例如ID,名称等),则可以将该信息保存在用户模型内的JSONField中,并且仅在用户需要其详细信息时才访问该商品。您可以通过这种方式保存数据库查询,但是当用户访问或重新访问项目时,将不得不纠缠一些JSON。

此方法还取决于要在Item模型中保存的User字段的更改频率,或者项目是否被完全删除。

答案 2 :(得分:0)

我认为使用Visit作为单独模型是保持分离的好选择。

在DRF api中仅限制返回结果(例如 User.recent_visits.all()[:5] )很好。

下面的解决方案确保 User.recent_visits.all()将返回最近的5次访问而不进行切片,并且避免使用庞大的列表。

我过去成功使用的“模式”可以大致转换为以下上下文:

class VisitQuerySet(models.QuerySet):
    MAX_LRV = 5 # Max Last Recent Visits

    def add_item(self, user, item):
        with transaction.atomic():
            # to avoid duplicate items
            lrv, created = self.get_or_create(user=user, item=item)

            if not created:
                lrv.save()  # update timestamp
                return lrv

            self.prune_lrv(user)
        return lrv

    def prune_lrv(self, user):
        # One example of how to clean up the recent visits
        qs = self.filter(user=user)
        if qs.count() > self.MAX_LRV:
            pending_delete = qs[self.MAX_LRV:]
            self.filter(user=user, pk__in=pending_delete).delete()


class Visit(models.Model):
    class Meta:
        ordering = ('-last_visited',) # ordering important

    user = ForeignKey(User, related_name="recent_visits")
    item = ForeignKey(Item, related_name="visitors")
    last_visited = DateTimeField(auto_now=True)

    objects = VisitQuerySet.as_manager()


 # Adding a item
 Visit.objects.add_item(user, item)

 #Get last 5 recent visits
 request.user.recent_visits.all()

该列表在添加新项目时得到维护,它是 易于更改MAX_LRV,并且应该直接避免重复(取决于在这种情况下如何创建项目)。