2

因此,我正在尝试整理一个网页,但我目前无法在我整理的 Web 应用程序中为每个用户整理一个结果页面。

这是我的模型的样子:

class Fault(models.Model):
    name = models.CharField(max_length=255)
    severity = models.PositiveSmallIntegerField(default=0)
    description = models.CharField(max_length=1024, null=False, blank=False)
    recommendation = models.CharField(max_length=1024, null=False, blank=False)
    date_added = models.DateTimeField(_('date added'), default=timezone.now)
    ...


class FaultInstance(models.Model):
    auto = models.ForeignKey(Auto)
    fault = models.ForeignKey(Fault)
    date_added = models.DateTimeField(_('date added'), default=timezone.now)

    objects = FaultInstanceManager()
    ...

class Auto(models.Model):
    label = models.CharField(max_length=255)
    model = models.CharField(max_length=255)
    make = models.CharField(max_length=255)
    year = models.IntegerField(max_length=4)
    user = models.ForeignKey(AUTH_USER_MODEL)
    ...

我不知道我的模特关系是否理想,但我觉得这很有意义。因此,每个用户都可以有多个与之关联的Auto对象。并且每个Auto可以有多个与之关联的FaultInstance对象。

在结果页面中,我想列出用户在其Autos中拥有的所有FaultInstances。在每个列出的FaultInstance下,我将列出用户拥有的所有有故障的汽车及其信息(这就是我的想法)。

按严重性排序的所有FaultInstance列表(从大到小)

FaultInstance:
   FaultDescription:
   FaultRecommendation:
   ListofAutosWithFault:
       AutoLabel AutoModel AutoYear ...
       AutoLabel AutoModel AutoYear ...

显然,以正确的方式做事意味着我想在 Python/Django 方面做尽可能多的列表创建,并避免在模板中做任何逻辑或处理。我可以使用模型管理器为每个严重性创建一个列表,如下所示:

class FaultInstanceManager(models.Manager):
    def get_faults_by_user_severity(self, user, severity):
        faults = defaultdict(list)
        qs_faultinst = self.model.objects.select_related().filter(
                auto__user=user, fault__severity=severity
            ).order_by('auto__make')
        for result in qs_faultinst:
            faults[result.fault].append(result)

        faults.default_factory = None
        return faults

我仍然需要指定每个严重性,但我想如果我只有 5 个严重性级别,我可以为每个严重性级别创建一个列表并将每个单独的级别传递给模板。对此的任何建议表示赞赏。然而,那不是我的问题。我现在的停止点是,我想在他们的报告顶部创建一个汇总表,它可以为用户提供每个品牌|型号|年份的故障实例细分。我想不出传递给模板的正确查询或数据结构。

摘要(具有以下列标题 的所有FaultInstances表):

FaultInstance    Make|Model|Year    NumberOfAutosAffected

这将让我知道品牌或型号或年份的指标(在下面的示例中,它根据型号分离故障)。我列出FaultInstances是因为我只列出了连接到用户的故障。

例如

Bad Starter     Nissan     1
Bad Tailight    Honda      2
Bad Tailight    Nissan     1

我是一个完美主义者,我想在优化数据库查询的同时做到这一点。如果我可以在我的原始查询中创建一个可以在模板中轻松解析的数据结构,并且仍然在我的报告中获得这两个部分(可能是 defaultdict(list) 的 defaultdict),这就是我想要做的。感谢您的帮助,希望我的问题是彻底且有意义的。

4

1 回答 1

2

使用相关名称是有意义的,因为它简化了您的查询。像这样:

class FaultInstance(models.Model):
    auto = models.ForeignKey(Auto, related_name='fault_instances')
    fault = models.ForeignKey(Fault, related_name='fault_instances')
    ...

class Auto(models.Model):
    user = models.ForeignKey(AUTH_USER_MODEL, related_name='autos')

在这种情况下,您可以使用:

qs_faultinst = user.fault_instances.filter(fault__severity=severity).order_by('auto__make')

代替:

qs_faultinst = self.model.objects.select_related().filter(
                auto__user=user, fault__severity=severity
            ).order_by('auto__make')

我无法弄清楚您的汇总表,可能是您的意思:

Fault    Make|Model|Year    NumberOfAutosAffected

在这种情况下,您可以使用聚合。但是,如果您有足够的数据,它(分组)仍然会很慢。一个简单的解决方案是通过创建额外的模型来非规范化数据并创建一些信号来更新它,或者您可以使用缓存。

如果您有一组预定义的严重性,请考虑以下问题:

class Fault(models.Model):

    SEVERITY_LOW = 0
    SEVERITY_MIDDLE = 1
    SEVERITY_HIGH = 2
    ...
    SEVERITY_CHOICES = (
        (SEVERITY_LOW, 'Low'),
        (SEVERITY_MIDDLE, 'Middle'),
        (SEVERITY_HIGH, 'High'),
        ...
    )
    ...
    severity = models.PositiveSmallIntegerField(default=SEVERITY_LOW,
                                                choices=SEVERITY_CHOICES)
    ...

在您的模板中,您只需遍历 Fault.SEVERITY_CHOICES。

更新:

改变你的模型:

模型分配到一个单独的模型中:

class AutoModel(models.Model):
    name = models.CharField(max_length=255)

更改模型 Auto 的字段模型:

class Auto(models.Model):
    ...
    auto_model = models.ForeignKey(AutoModel, related_name='cars')
    ...

添加模型:

class MyDenormalizedModelForReport(models.Model):

    fault = models.ForeignKey(Fault, related_name='reports')
    auto_model = models.ForeignKey(AutoModel, related_name='reports')
    year = models.IntegerField(max_length=4)
    number_of_auto_affected = models.IntegerField(default=0)

添加信号:

def update_denormalized_model(sender, instance, created, **kwargs):
    if created:
        rep, dummy_created = MyDenormalizedModelForReport.objects.get_or_create(fault=instance.fault, auto_model=instance.auto.auto_model, year=instance.auto.year)
        rep.number_of_auto_affected += 1
        rep.save()

post_save.connect(update_denormalized_model, sender=FaultInstance)
于 2013-06-27T17:59:51.443 回答