【问题标题】:Django: Multiple COUNTs from two models awayDjango:来自两个模型的多个计数
【发布时间】:2011-01-09 00:48:24
【问题描述】:

我正在尝试创建一个个人资料页面,显示分配给每个相应职业的矮人数量。我有 4 个职业,每个职业都有 2 个工作,当然还有很多矮人,每个人都有一份工作。我如何计算每个职业中的矮人数量?我的解决方案是在 HTML 中对职业名称进行硬核化,并对每个职业进行查询,但这似乎是过多的查询。

这是我“想”看到的:

Unassigned: 3
Construction: 2
Farming: 0
Gathering: 1

这是我的模型。我没有将职业直接连接到我的 Dwarves 模型(他们通过工作连接),从而增加了一些复杂性。

from django.contrib.auth.models import User
from django.db import models

class Career(models.Model):
    name = models.CharField(max_length = 64)

    def __unicode__(self):
        return self.name

class Job(models.Model):
    career = models.ForeignKey(Career)
    name = models.CharField(max_length = 64)
    career_increment = models.DecimalField(max_digits = 4, decimal_places = 2)
    job_increment = models.DecimalField(max_digits = 4, decimal_places = 2)

    def __unicode__(self):
        return self.name

class Dwarf(models.Model):
    job = models.ForeignKey(Job)
    user = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
    name = models.CharField(max_length = 64)

    class Meta:
        verbose_name_plural = 'dwarves'

    def __unicode__(self):
        return self.name

编辑 1 我的观点看起来像:

def fortress(request):
    careers = Career.objects.annotate(Count('dwarf_set'))
    return render_to_response('ragna_base/fortress.html', {'careers': careers})

和模板:

{% for career in careers %}
    <li>{{ career.dwarf_set__count }}</li>
{% endfor %}

错误是:

Cannot resolve keyword 'dwarf_set' into field. Choices are: id, job, name

解决方案

查看:

def fortress(request):
    careers = Career.objects.all().annotate(dwarfs_in_career = Count('job__dwarf'))
    return render_to_response('ragna_base/fortress.html', {'careers': careers})

模板:

{% for career in careers reversed %}
    <li>{{ career.name }}: {{ career.dwarves_in_career }}</li>
{% endfor %}

更好的解决方案

careers = Career.objects.filter(Q(job__dwarf__user = 1) | Q(job__dwarf__user__isnull = True)) \
    .annotate(dwarves_in_career = Count('job__dwarf'))

别忘了from django.db.models import Count, Q

我喜欢上述解决方案的地方在于,它不仅返回了有矮人工作的职业,甚至还返回了没有工作的职业,这是我遇到的下一个问题。这是我对完整性的看法:

<ul>
{% for career in careers %}
    <li>{{ career.name }}: {{ career.dwarves_in_career }}</li>
{% endfor %}
</ul>

【问题讨论】:

    标签: sql django postgresql django-models


    【解决方案1】:

    这是你想要的吗?

    from django.db.models import Count
    Career.objects.annotate(Count('dwarf'))
    

    现在每个career 对象都应该有一个dwarf__count 属性。

    【讨论】:

    • 不错!我确实继续收到错误:无法将关键字“dwarf_set”解析为字段。选项有:id、job、name 但我正在尝试不同的东西。
    • 我觉得如果我的 Dwarf 模型与我的职业模型直接相关,这会起作用,但我选择通过我的工作模型将两者联系起来以允许改变职业。
    【解决方案2】:

    Django 的 ORM 不会让这个超级简单。简单的方法是执行以下操作:

    在 Career.objects.all() 中的职业生涯: career.dwarf_set.all().count()

    这将为每个作业执行 1 个查询(O(n) 复杂度)。

    您可以尝试使用Django's Aggregation feature 来加快速度,但我不完全确定它是否能满足您的需求。你得看看。

    第三个选项是使用自定义 SQL,这绝对可以完成工作。您只需要编写它,并在您的应用程序增长和变化时对其进行维护......

    【讨论】:

      【解决方案3】:

      你不能按职业分组吗?如果您还需要返回零行,请执行外连接。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-27
        • 1970-01-01
        相关资源
        最近更新 更多