Django模型:检索唯一的外键实例

时间:2012-01-09 21:03:00

标签: django django-models

我有两张桌子:

class Collection(models.Model):
name = models.CharField()

class Image(models.Model):
name = models.CharField()
image = models.ImageField();
collection = models.ForeignKey(Collection)

我想从每个集合中检索第一张图片。我试过了:

image_list = Image.objects.order_by('collection.id').distinct('collection.id')

但它没有达到预期的效果:(

有什么想法吗? 感谢。

4 个答案:

答案 0 :(得分:3)

不要使用点来分隔跨越Django中关系的字段;相反,使用双下划线约定 - 它意味着“遵循此关系来到达此字段”

这更正确:

image_list = Image.objects.order_by('collection__id').distinct('collection__id')

然而,它可能不会做你想要的。

“第一”的概念并不总是以您似乎使用它的方式应用于关系数据库。对于具有相同集合ID的图像表中的所有记录,没有“第一”或“最后”的记录 - 它们都只是记录。您可以在该表上放置另一个字段来定义特定订单,或者您可以按ID排序,或按字母顺序按名称排序,但默认情况下不会发生这些。

最适合您的方法是使用一个查询获取集合列表,然后在单独的查询中获取每个集合的单个项目:

collection_ids = Image.objects.values_list('collection', flat=True).distinct()
image_list = [
    Image.objects.filter(collection__id=c)[0] for c in collection_ids
]

如果要对图像应用订单,要定义哪个是“第一个”,请按以下方式修改:

collection_ids = Image.objects.values_list('collection', flat=True).distinct()
image_list = [
    Image.objects.filter(collection__id=c).order_by('-id')[0] for c in collection_ids
]

您还可以编写原始SQL - MySQL聚合具有一个有趣的属性,即未聚合的字段仍然可以出现在最终输出中,并且基本上从匹配记录集中获取随机值。这样的事情可能有用:

Image.objects.raw("SELECT image.* FROM app_image GROUP BY collection_id")

此查询应该从每个集合中获取一个图像,但您无法控制返回哪个图像。

答案 1 :(得分:0)

正如我在评论中所写,您不能在MySQL下使用distinct的特定字段。但是,您可以通过以下方式获得相同的结果:

from itertools import groupby

all_images = Image.objects.order_by('collection__id')
images_by_collection = groupby(all_images, lambda image: image.collection_id)
image_list = sum([group for key, group in images_by_collection], [])

不幸的是,这会导致对DB的“更大”查询(检索所有图像)。

答案 2 :(得分:0)

dict([(c.id, c.image_set.all()[0]) for c in Collection.objects.all()])

这将在每个集合中创建第一个图像的字典(默认排序),由集合的id键入。但请注意,这将生成1 + N个查询,其中N是集合对象的总数。

要解决这个问题,您需要等待Django 1.4和prefetch_related或使用类似django-batch-select的内容。

答案 3 :(得分:-1)

<块引用>

首先得到不同的结果,然后进行过滤。

<块引用>

我觉得你应该试试这个。

image_list = Image.objects.distinct()
image_list = image_list.order_by('collection__id')