在GitHub中,您会注意到,当您要引用现有问题或在项目下标记问题时,GitHub会聪明地向您显示您最近第一次访问的最新项目。
以上次访问的顺序显示最近的项目的示例
我正在使用django来构建网络应用程序,并且我希望合并相同的功能。
我有两个想法,但还没有实现:
1。一张巨大的桌子,存储着个人用户的所有访问次数
我应该有一个巨型表来存储所有用户访问的所有项目吗?如果是这样,我该如何将其与我要搜索的主表结合起来以正确产生排序?
2。在各个主表中添加一个visited
列
我显然不能在主表中添加新的日期时间列“ visited”,因为这将意味着没有个性化。
我在理解方面缺少什么?
还可以公平地假设我需要限制每个用户存储的最新商品的数量吗?
意思是,使用GitHub示例,每个用户最多只能存储5个最新项目或问题。
答案 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,并且应该直接避免重复(取决于在这种情况下如何创建项目)。