假设我有一个Book
模型:
class Book(models.Model)
title = models.Charfield(...)
likes = models.ManyToMany(User, related_name="books_liked")
我需要为当前登录的用户注释一个带有is_liked
字段的查询集。
我有这个在视图中,但它不工作:
user = self.request.user
qs = Book.objects.all().annotate(is_liked=Exists(user.books_liked.all()))
return qs
所以我可以在模板中使用这样的内容
{% for book in books %}
{% if book.is_liked %}
...
{% endif %}
{% endfor %}
我正在检查这个文档部分,但我不太确定如何进行,或者如果是正确的方法。
https://docs.djangoproject.com/en/3.1/ref/models/expressions/exists-subqueries
我该怎么做?谢谢。
这有点晚了,但是。可以通过使用没有显式模型的SQL逻辑来解决这个问题。
from django.db.models import Case, When, Value
user_id = self.request.user.id
qs = Book.objects.annotate(is_liked=Case(
When(likes__id=user_id, then=Value(True)),
default=False
)
其余的工作正常。
文档:案例
当超过1个用户喜欢同一本书时,这会导致一些奇怪的行为。因此,使用Q被证明是更有用的。但是,如果用户没有登录,则会抛出错误。所以用一个尝试,除了块它工作。修复方法如下:
from django.db.models import Q
try:
liked_id = self.request.user.books_liked.values("id")
except AttributeError:
qs = Book.objects.all()
else:
qs = Book.objects.annotate(is_liked=Q(id__in=liked_id))
为了使它工作,我必须创建一个显式的Like模型:
class Like(models.Model):
book = models.ForeignKey(
Book, on_delete=models.CASCADE,
)
user = models.ForeignKey(
User, on_delete=models.CASCADE,
)
去除ManyToMany
对Book
的影响
然后在视图this:
qs = super().get_queryset()
user_likes = Like.objects.filter(
book=OuterRef("pk"),
user=self.request.user
)
return Book.objects.annotate(
is_liked=Exists(user_likes)
)