如果第二个表中存在已过滤的行,则注释django查询

时间:2015-05-20 02:47:05

标签: django postgresql

我有两张桌子(类似于下面的表格):

class Piece(models.Model):
    cost = models.IntegerField(default=50)
    piece = models.CharField(max_length=256)

class User_Piece (models.Model):
    user = models.ForeignKey(User)
    piece = models.ForeignKey(Piece)

我想执行一个返回Piece中所有项目的查询,但是使用登录用户是否拥有该项目来注释每一行(因此User_Piece中存在一行,其中用户是登录用户)。

我试过了:

pieces = Piece.objects.annotate(owned=Count('user_piece__id'))

但它会计算> 0表示任何用户拥有的任何作品。我不确定user_piece必须拥有我想要的指定用户的条件。如果我在user__piece__user=user上过滤,那么我就不会从Piece获得所有行,只有那些拥有的行。

3 个答案:

答案 0 :(得分:0)

简单方法,小心表现:

pk_pices = ( User_Piece
            .objects
            .filter(user=user)
            .distinct()
            .values_list( 'id', flat=True)
           )
pieces = pieces.objects.filter( id__in = pk_pieces )

另外,请注意您有一个n:m relation ship,您可以将模型重写为:

class Piece(models.Model):
    cost = models.IntegerField(default=50)
    piece = models.CharField(max_length=256)
    users = models.ManyToManyField(User, through='User_Piece',  #<- HERE!
                                   related_name='Pieces')       #<- HERE!

并获得用户作品:

pieces = currentLoggedUser.pieces.all()

答案 1 :(得分:0)

您可以使用Exist子查询包装器:

from django.db.models import Exists, OuterRef

subquery = User_Piece.objects.filter(user=user, piece=OuterRef('pk'))
Piece.objects.annotate(owned=Exists(subquery))

https://docs.djangoproject.com/en/dev/ref/models/expressions/#exists-subqueries

答案 2 :(得分:0)

在较新版本的Django中,您可以执行以下操作:

from django.db.models import Exists, OuterRef

pieces = Piece.objects.annotate(
   owned=Exists(UserPiece.objects.filter(piece=OuterRef('id'), user=request.user))
)

for piece in pieces:
    print(piece.owned) # prints True or False

当然,您可以将名称owned替换为所需的任何名称。