django模型对象过滤

7 投票
3 回答
61207 浏览
提问于 2025-04-17 20:18

我有两个表,一个叫做 'has_location',另一个叫做 'locations'。'has_location' 表里有 user_haslocation_id 这两个字段,还有一个 id 字段,这个 id 是 Django 自动生成的。

'locations' 表里有更多的列。

现在我想获取某个特定用户的所有位置。我做的操作是……(用户的 id 是已知的):

users_locations_id = has_location.objects.filter(user_has__exact=user.id)
locations = Location.objects.filter(id__in=users_locations_id)
print len(locations)

但是我通过这个 print 得到的结果是 0。数据库里确实有数据,但我感觉 __in 这个操作可能不接受模型的 id,对吗?

谢谢。

3 个回答

1

你的模型长什么样子?

关于你的疑问,__in 确实可以接受 过滤后的ID。

对于你现在的代码,解决方案是:

locations = Location.objects.filter(id__in=has_location.objects.filter(user=user).values('location_id'))
# if you just want the length of the locations, evaluate locations.count()
locations.count()
# if you want to iterate locations to access items afterwards
len(locations)
11

在Django中,使用__in来进行这种查询是一种常见的反模式。虽然它看起来简单,但在大多数数据库中,这种方法的扩展性很差。你可以参考Christophe Pettus的这份演示文稿的第66页及之后的内容

用户和地点之间存在多对多的关系,这种关系通过has_location表来表示。通常,你会用一个ManyToManyField和一个through表来描述这个关系,像这样:

class Location(models.Model):
    # ...

class User(models.Model):
    locations = models.ManyToManyField(Location, through = 'LocationUser')
    # ...

class LocationUser(models.Model):
    location = models.ForeignKey(Location)
    user = models.ForeignKey(User)
    class Meta:
         db_table = 'has_location'

然后你可以这样获取某个用户的地点:

user.locations.all()

你可以在过滤操作中查询地点:

User.objects.filter(locations__name = 'Barcelona')

而且你可以使用prefetch_related()方法高效地请求用户相关的地点,这样可以更快地获取数据。

7

你现在是用has_location的自己的ID来筛选位置。其实你应该用location_id来筛选位置:

user_haslocations = has_location.objects.filter(user_has=user)
locations = Location.objects.filter(id__in=user_haslocations.values('location_id'))

你也可以通过反向关系直接筛选位置:

location = Location.objects.filter(has_location__user_has=user.id)

撰写回答