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

use*_*778 1 django django-models

我有两张这样的表:

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

class Image(models.Model):
    name = models.CharField()
    image = models.ImageField()
    collection = models.ForeignKey(Collection)
Run Code Online (Sandbox Code Playgroud)

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

image_list = Image.objects.order_by('collection.id').distinct('collection.id')
Run Code Online (Sandbox Code Playgroud)

但它并没有像我预期的那样工作:(

有任何想法吗?谢谢。

Ian*_*and 7

不要使用点来分隔 Django 中跨越关系的字段;改为使用双下划线约定——它的意思是“按照这个关系到达这个领域”

这是更正确的:

image_list = Image.objects.order_by('collection__id').distinct('collection__id')
Run Code Online (Sandbox Code Playgroud)

但是,它可能不会执行您想要的操作。

“第一”的概念并不总是像您使用它的方式那样适用于关系数据库。对于图像表中具有相同集合 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
]
Run Code Online (Sandbox Code Playgroud)

如果要将订单应用于图像,以定义哪个是“第一个”,然后像这样修改它:

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
]
Run Code Online (Sandbox Code Playgroud)

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

Image.objects.raw("SELECT image.* FROM app_image GROUP BY collection_id")
Run Code Online (Sandbox Code Playgroud)

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