首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有不同ForeignKey的django查询

具有不同ForeignKey的django查询
EN

Stack Overflow用户
提问于 2019-04-05 12:56:31
回答 2查看 146关注 0票数 4

我有两个模特:

代码语言:javascript
复制
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,)

我想得到最后三张照片。每一张照片都应该分配到不同的画廊。

这个解决方案很有效,但也很慢。我能让它工作得更快吗?

代码语言:javascript
复制
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]

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

代码语言:javascript
复制
galleries = Gallery.objects.filter(site=site).order_by('-created').values_list('id')[:limit]
photos = Photo.objects.filter(id__in=galleries)

但这并不能阻止画廊再次发生。我考虑过以某种方式使用distinct(),但我不知道有多疯狂。

Django 1.11

编辑:

我想我应该为我所期望的结果树立一些榜样。

代码语言:javascript
复制
- 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,我也会感到满意

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-05 15:41:16

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

代码语言:javascript
复制
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张照片,每个图片库仅限一张照片:

代码语言:javascript
复制
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)
)
票数 1
EN

Stack Overflow用户

发布于 2019-04-05 13:53:58

从Django 1.11开始,您应该能够使用 Expressionsprefetch_related()的组合来完成这个任务。

代码语言:javascript
复制
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不同的属性,则可以使用 classto_attr参数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55535936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档