gpt4 book ai didi

python - Django 反向 m2m 查询

转载 作者:太空宇宙 更新时间:2023-11-03 15:41:11 25 4
gpt4 key购买 nike

使用来自 https://docs.djangoproject.com/en/dev/topics/db/queries/#making-queries 的模型稍作修改:

from django.db import models

class Blog(models.Model):
name = models.CharField(max_length=100)

class Author(models.Model):
name = models.CharField(max_length=200)
joined = models.DateField()

def __str__(self):
return self.name

class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
authors = models.ManyToManyField(Author)
rating = models.IntegerField()

我想创建一个从作者到条目的字典,作者今年加入,条目的评级为 4 或更高。结果字典的结构应该是这样的:

author_entries = {author1: [set of entries], author2: [set of entries], etc.}

访问数据库的次数少于 3 次(或者至少与作者或条目的数量不成比例)。

我的第一次尝试(数据库命中 == 作者数量,100 个作者 100 个数据库命中):

    res = {}
authors = Author.objects.filter(joined__year=date.today().year)

for author in authors:
res[author] = set(author.entry_set.filter(rating__gte=4))

第二次尝试,尝试一次读取条目:

    res = {}
authors = Author.objects.filter(joined__year=date.today().year)
entries = Entry.objects.select_related().filter(rating__gte=4, authors__in=authors)

for author in authors:
res[author] = {e for e in entries if e.authors.filter(pk=author.pk)}

这个更糟,100 位作者,198 次 db-hits(最初的第二次尝试使用 {e for e in entries if author in e.authors},但 Django 没有.

我发现的唯一方法涉及 raw-sql(4 db-hits):

    res = {}
_authors = Author.objects.filter(joined__year=date.today().year)
_entries = Entry.objects.select_related().filter(rating__gte=4, authors__in=_authors)
authors = {a.id: a for a in _authors}
entries = {e.id: e for e in _entries}
c = connection.cursor()
c.execute("""
select entry_id, author_id
from sampleapp_entry_authors
where author_id in (%s)
""" % ','.join(str(v) for v in authors.keys()))

res = {a: set() for a in _authors}
for eid, aid in c.fetchall():
if eid in entries:
res[authors[aid]].add(entries[eid])

(很抱歉在 c.execute(..) 调用中使用了字符串替换——我找不到 where in ? 调用所需的语法 sqlite ).

是否有更像 Djangoesque 的方式来做到这一点?

我已经用我正在使用的代码 ( https://github.com/thebjorn/revm2m ) 创建了一个 git 仓库,测试在 https://github.com/thebjorn/revm2m/blob/master/revm2m/sampleapp/tests.py

最佳答案

您可以使用 Prefetch-object [Django-doc]为此:

from django.db.models import <b>Prefetch</b>

good_ratings = <b>Prefetch</b>(
'entry_set',
queryset=Entry.objects.filter(rating__gte=4),
to_attr='good_ratings'
)

authors = Author.objects.filter(
joined__year=date.today().year
).prefetch_related(
good_ratings
)

现在 authors 中的 Author 对象将有一个额外的属性 good_ratings(to_attr 的值Prefetch 对象)是一个预加载的 QuerySet,其中包含评级大于或等于 4 的 Entry

因此您可以像这样对这些进行后处理:

res = {
author: set(author.good_ratings)
for author in authors
}

虽然因为 Author 对象(来自这个 QuerySet,不是一般的),已经携带了属性,所以可能没什么用处。

关于python - Django 反向 m2m 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52427855/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com