繁体   English   中英

django查询具有不同的ForeignKey

[英]django query with distinct ForeignKey

我有两个型号:

class Gallery(models.Model):
    site = models.ForeignKey(Site, related_name='galleries', on_delete=models.CASCADE)
    created = models.DateTimeField(_('created'), auto_now_add=True)

class Photo(models.Model):
    image = ImageField(verbose_name=_('image'), upload_to=upload_path)
    gallery = models.ForeignKey(Gallery, related_name='photos', on_delete=models.CASCADE)
    created = models.DateTimeField(_('created'), auto_now_add=True,)

我想最后添加三张照片。 每张照片都应分配到不同的图库。

这个解决方案有效,但也很慢。 我可以让它更快地运作吗?

limit = 3
photos = Photo.objects.annotate(
    max_gallery_created=Max('gallery__photos__created'),
).filter(
    gallery__site=site,
    created=F('max_gallery_created'),
).order_by(
    '-max_gallery_created',
)[:limit]

如果我从最后创建的三个画廊中获取最后一张照片,我也会感到满意。 我试着这样做:

galleries = Gallery.objects.filter(site=site).order_by('-created').values_list('id')[:limit]
photos = Photo.objects.filter(id__in=galleries)

但它并没有阻止画廊重新出现。 我想过以某种方式使用distinct(),但我不知道怎么做。

Django 1.11。

编辑:

我想我应该为我期望的结果提供一些例子。

- Gallery1 (created 10.01.2019)
    - PhotoA (created: 15.01.2019 at 12:00)
    - PhotoB (created: 15.01.2019 at 11:00)
    - PhotoC (created: 13.01.2019 at 11:00)
- Gallery2 (created 09.01.2019)
    - PhotoD (created: 13.01.2019 at 10:00)
    - PhotoE (created: 12.01.2019 at 10:00)
    - PhotoF (created: 10.01.2019 at 10:00)
- Gallery3 (created 08.01.2019)
    - PhotoG (created: 14.01.2019 at 11:00)
    - PhotoH (created: 14.01.2019 at 11:00)
    - PhotoI (created: 14.01.2019 at 11:00)
- Gallery4 (created 07.01.2019)
    - PhotoJ (created: 14.01.2019 at 12:00)
    - PhotoK (created: 12.01.2019 at 10:00)
    - PhotoL (created: 12.01.2019 at 10:00)

在这种情况下

我现在得到的: PhotoA, PhotoB, PhotoJ

我想得到的: PhotoA, PhotoJ, PhotoG

如果我得到PhotoA, PhotoD, PhotoG我也会很满意: PhotoA, PhotoD, PhotoG

从Django 1.11开始,你应该可以使用Subquery表达式prefetch_related()

from django.db.models import OuterRef, Subquery, Prefetch

subquery = Subquery(
    Photo.objects.filter(
        gallery_id=OuterRef('gallery_id')
    ).order_by('-created').values_list('id', flat=True)[:3])

galleries = Gallery.objects.order_by('-created').prefetch_related(
    Prefetch('photos',
        queryset=Photo.objects.filter(id__in=subquery).order_by('-created')))

for gallery in galleries:
    for photo in gallery.photos.all(): # should now be the latest 3
        print(photo)

如果你想最新的照片取到不同的属性比photos ,你可以使用to_attr中的参数Prefetch

如果您正在使用PostgreSQL,则可以使用一个嵌套查询从不同的库中获取最新的三张照片。 应将任何进一步的过滤器添加到内部查询中以提高效率:

photos = (Photo.objects    
    .filter(id__in=Photo.objects.filter(gallery__site=site)
                                .order_by('gallery', '-created')
                                .distinct('gallery').values('id'))
    .order_by('-created')[:3]
)

使用其他后端,您可以使用Bernhard提出的预取子查询,尽管他的解决方案将为您提供按库日期排序的所有图库,每个图库中最新的三张照片。

使用按照照片日期而不是图库日期对画廊进行排序和限制的附加过滤器,您可以获得与上面相同的结果:最新的3张照片,每个图库仅限一张照片:

prefetch = Prefetch('photos', queryset=Photo.objects.filter(id__in=
    Subquery(Photo.objects.filter(
        gallery_id=OuterRef('gallery_id')
    ).order_by('-created').values_list('id', flat=True)[:1])))


galleries = (Gallery.objects
    .filter(id__in=Gallery.objects
                    .order_by('-photos__created')
                    .distinct()[:3]
            )
    .order_by('-created')
    .prefetch_related(prefetch)
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM