gpt4 book ai didi

Django prefetch_related 中间表没有重复项

转载 作者:行者123 更新时间:2023-12-04 20:42:36 26 4
gpt4 key购买 nike

我有一个问题,我现在想解决一天。

随着模型

class Quote(models.Model):
text = models.TextField()
source = models.ForeignKey(Source)
tags = models.ManyToManyField(Tag)
...

class Source(models.Model):
title = models.CharField(max_length=100)
...

class Tag(models.Model):
name = models.CharField(max_length=30,unique=True)
slug = models.SlugField(max_length=40,unique=True)
...

我正在尝试模拟报价世界。有关系:一个 Source有很多 Quote s, 一 Quote有很多 Tag s。
问题是:
  • 我如何获得所有 Tag包含在 Source 中的 s (通过包含的 Quote s)?
  • 尽可能少的查询。
  • 以及它们包含在该源中的次数

  • 我已经尝试过没有预取相关的幼稚方法,使用模型方法
    def source_tags(self):
    tags = Tag.objects.filter(quote__source__id=self.id).distinct().annotate(usage_count=Count('quote'))
    return sorted(tags, key=lambda tag:-tag.usage_count)

    在模板中:
    {% for tag in source.source_tags|slice:":5" %}
    source.quote
    {% endfor %}

    我现在有
    sources = Source.objects.all().prefetch_related('quote_set__tags')

    在模板中,我不知道如何正确迭代以获得 Tag s 用于一个来源,以及我将如何计算它们而不是列出重复的标签。

    最佳答案

    这将在单个 SQL 查询中获得结果:

    # views.py
    from django.db.models import Count
    from .models import Source


    def get_tag_count():
    """
    Returns the count of tags associated with each source
    """
    sources = Source.objects.annotate(tag_count=Count('quote__tags')) \
    .values('title', 'quote__tags__name', 'tag_count') \
    .order_by('title')
    # Groupe the results as
    # {source: {tag: count}}
    grouped = {}
    for source in sources:
    title = source['title']
    tag = source['quote__tags__name']
    count = source['tag_count']
    if not title in grouped:
    grouped[title] = {}
    grouped[title][tag] = count
    return grouped



    # in template.html

    {% for source, tags in sources.items %}

    <h3>{{ source }}</h3>

    {% for tag, count in tags.items %}
    {% if tag %}
    <p>{{ tag }} : {{ count }}</p>
    {% endif %}
    {% endfor %}

    {% endfor %}

    补充测试:)
    # tests.py
    from django.test import TestCase
    from .models import Source, Tag, Quote
    from .views import get_tag_count


    class SourceTags(TestCase):

    def setUp(self):
    abc = Source.objects.create(title='ABC')
    xyz = Source.objects.create(title='XYZ')

    inspire = Tag.objects.create(name='Inspire', slug='inspire')
    lol = Tag.objects.create(name='lol', slug='lol')

    q1 = Quote.objects.create(text='I am inspired foo', source=abc)
    q2 = Quote.objects.create(text='I am inspired bar', source=abc)
    q3 = Quote.objects.create(text='I am lol bar', source=abc)
    q1.tags = [inspire]
    q2.tags = [inspire]
    q3.tags = [inspire, lol]
    q1.save(), q2.save(), q3.save()

    def test_count(self):
    # Ensure that only 1 SQL query is done
    with self.assertNumQueries(1):
    sources = get_tag_count()
    self.assertEqual(sources['ABC']['Inspire'], 3)
    self.assertEqual(sources['ABC']['lol'], 1)

    我基本用过 annotate values ORM 中的函数。它们非常强大,因为它们会自动执行连接。它们也非常高效,因为它们只访问数据库一次,并且只返回那些指定的字段。

    关于Django prefetch_related 中间表没有重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23405871/

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