4

Django 代码和参考 Django 错误报告

给定以下三个模型(为了演示而过度简化......实际上并不是相同的相关模型)

class derp(models.Model):
    ...
class derp_related_1(models.Model):
    fk = models.ForeignKey(derp)
    amount = models.DecimalField(max_digits=15, decimal_places=2)
class derp_related_2(models.Model):
    fk = models.ForeignKey(derp)
    amount = models.DecimalField(max_digits=15, decimal_places=2)

并在模型管理中覆盖查询集,如下所示。(由于这个 django 错误,它不起作用。)

class DerpAdmin(admin.ModelAdmin):
    ...
    list_display = ['derp_r1_sum', 'derp_r2_sum']
    ...
    def queryset(self, request):
        qs = super(DerpAdmin, self).queryset(request)
        qs = qs.annotate(derp_r1_sum=models.Sum('derp_r1__amount', distinct=True))
        qs = qs.annotate(derp_r2_sum=models.Sum('derp_r2__amount', distinct=True))
    def derp_r1_sum(self, obj):
        return u'%s' % obj.derp_r1_sum
    def derp_r2_sum(self, obj):
        return u'%s' % obj.derp_r2_sum

意外的数据库结果示例

单独运行注释会呈现类似(删除分组和总和)

+---------+--------+
| derp.id | r1_sum |
+---------+--------+
|       2 | 500.00 |
|       2 | 100.00 |
+---------+--------+
r1_sum would be 600.00
and
+---------+--------+
| derp.id | r1_sum |
+---------+--------+
|       2 | 100.00 |
|       2 | 250.00 |
+---------+--------+
r2_sum would be 350.00

如果您使用包含两个注释的 qs.query 并删除总和和分组,那么很明显问题出在哪里。在这种情况下,我们将所有内容计算两次。获得更多的关系,我们在两个总和列中都有越来越难看的增长。

+---------+--------+--------+
| derp.id | r1_sum | r2_sum |
+---------+--------+--------+
|       2 | 500.00 | 100.00 |
|       2 | 500.00 | 250.00 |
|       2 | 100.00 | 100.00 |
|       2 | 100.00 | 250.00 |
+---------+--------+--------+
r1_sum would incorrectly be 1200.00
r2_sum would incorrectly be 700.00

问题,除了自定义SQL,还有其他路由吗?

我可以很容易地自己编写查询,但是如果有人有一个建议可以避免编写自定义 SQL,那就太棒了。

谢谢您的帮助。

编辑:这是 Django 文档注释部分的链接。一位评论者提到了不同的选项。这不起作用,我相信这是关于 annotation 的django 文档中注释部分底部的警告。

Edit2:原始 SQL 的想法可能比我想象的更困难,因为 derp.objects.raw('sql here') 不会返回管理员使用它所需的查询集对象。有没有办法使用两个查询(真正的查询集加上一个自定义的查询集)并从两者填​​充列表视图?我发现的一个建议(我现在找不到了:S)建议创建一个映射到模型定义的视图,然后将其设置为由 django 非托管(用于 syncdb)。然后我可以编写我的自定义代码,并引用它以包含在原始查询中。这听起来很乱。想法?

4

2 回答 2

0

我发现返回正确结果的最佳方法是使用queryset.extra().

derp_r1_sum_select = """
    select sum(`derp_related_1`.`amount`)
    from `derp_related_1` 
    where `derp_related_1`.`fk` = `derp`.`pk`
    """
derp_r2_sum_select = """
    select sum(`derp_related_2`.`amount`)
    from `derp_related_2`
    where `derp_related_2`.`fk` = `derp`.`pk`"
    """

def queryset(self, request):
        qs = super(DerpAdmin, self).queryset(request)
        qs = qs.extra(select={'derp_r1_sum': derp_r1_sum_select,
                              'derp_r2_sum': derp_r2_sum_select})
        return qs
于 2014-06-19T17:18:48.810 回答
0

如果您想留在 Django 的查询集中,我会考虑创建一个模型超类,它共享相关和公共字段以及子类以进一步区分。否则,您需要编写自定义 SQL 或完全退出数据库 ORM 并在 python 中使用Queryset.values或操作您的数据Queryset.values_list

于 2013-08-23T17:38:42.240 回答