django模型对象过滤器

时间:2013-03-26 11:57:38

标签: python database django django-forms

我有名为'has_location'和'locations'的表。 'has_location'有user_haslocation_id及其自己的id,由django本身提供。

'locations'有更多列。

现在我想获得某些用户的所有位置。我做的是..(user.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)

但是我0获得了print。我在db中有数据。但我觉得__in不接受模型ID,是吗?

谢谢

3 个答案:

答案 0 :(得分:8)

使用__in进行此类查询是Django中常见的反模式:由于其简单性,它很诱人,但在大多数数据库中它的扩展性很差。请参阅this presentation by Christophe Pettus中的幻灯片66ff。

用户和位置之间存在多对多关系,由has_location表表示。你通常会使用带有through表的ManyToManyField向Django描述这个,如下所示:

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()方法请求有效获取用户的相关位置。

答案 1 :(得分:4)

您正在使用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)

答案 2 :(得分:1)

你的模特是什么样的?

如有疑问,__in does accept过滤了ids。

对于您当前的代码,解决方案:

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)