Django:在显示文章列表时,根据用户显示每篇文章的收藏状态



我有要按日期显示的文章列表。每个用户都可以将任何文章标记为他的收藏夹。

如果用户已登录,那么他应该能够看到该文章是否已被标记为他最喜欢的一些指示。

以下是我的模型:

class Favourite(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
article = models.ForeignKey(Article, null=True,on_delete=models.CASCADE)
class Meta:
unique_together = ('user', 'article')
class Article(models.Model):
title = models.CharField(max_length=256)
intro_image = models.ImageField(null=True, blank=True, upload_to=doc_hash)
description = models.TextField(null=True, blank=True)

我在想每篇文章都要获取将文章标记为收藏夹的所有用户ID,然后在前端与当前用户一起检查它。

但是,如果某篇文章被 1000 个用户标记为最喜欢的文章,那么不必要地我将不得不获取 1000 个用户的数据以及该文章,这太多了。

有没有办法,如果我传递用户,我可以只获得每篇文章的该用户最喜欢的数据,这样我就可以保存查询和要传递到前端的数据量。

在视图的上下文中执行此操作,或作为自定义模板标记执行此操作。

下面的示例是干编码的,因此它们可能有愚蠢的错误。

在视图中(假设基于类的视图(:

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['is_favourite'] = Favourite.objects.filter(user=self.request.user, article=self.object).exists()
return context

用法:

{% if is_favourite %}Yay, you like it!{% endif %}

或模板标签:

@register.simple_tag(takes_context=True)
def is_favourite(context, article):
request = context['request']
return Favourite.objects.filter(user=request.user, article=article).exists()

用法:

{% is_favourite article as fav %}
{% if fav %}Yay, you like it!{% endif %}

编辑

对于ListView,您可以执行以下操作

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['favourited_ids'] = set(Favourite.objects.filter(user=self.request.user, article__in=context['object_list']).values_list('article_id', flat=True))
return context

并使用它

{% if article.id in favourited_ids %}Yay, you like this article!{% endif %}

我假设你需要一个标志来说明用户是否已经将文章标记为收藏夹,假设有 100 篇文章,其中用户已将 40 篇文章标记为收藏夹,然后发送 100 篇文章数据,其中 40 篇文章的标志为读取 TRUE,其余为 FALSE。

以下是SQL等效项,您可以根据需要将其转换为Django ORM。"xyz">是您需要显示文章的用户 ID

SELECT article.*, 
CASE  
WHEN read.article_id IS NOT NULL then TRUE
ELSE FALSE
as read_flag 
from Article as article
left join
(select article_id from Favourite where user_id = 'xyz') as read 
on article.id = read.article_id

我从以下位置找到了以下答案:https://stackoverflow.com/a/51889455/2897115。使用批注和子查询。Django 使用我从中读取的注释和子查询可以更快。https://medium.com/@hansonkd/the-dramatic-benefits-of-django-subqueries-and-annotations-4195e0dafb16

我把给出的解决方案放在 https://stackoverflow.com/a/51889455/2897115。使用批注

qs = Post.objects.all()
sub = Like.objects.filter(post__id=OuterRef('pk'), user=request.user)
values = qs.annotate(
date=Func(F('date'), function='db_specific_date_formatting_func'),
current_user_like=Exists(sub)
).values('text, 'date', 'current_user_like')

最新更新