django模型对象过滤
我有两个表,一个叫做 'has_location',另一个叫做 'locations'。'has_location' 表里有 user_has
和 location_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)