Django Annotate Count with MySQL在左外部联接上创建计数,结果错误

Django Annotate Count with MySQL在左外部联接上创建计数,结果错误,mysql,sql,django,annotations,count,Mysql,Sql,Django,Annotations,Count,在使用MyISAM在MySQL上运行的Django中,queryset上的my Count注释返回了不正确的结果。我查看了SQL语句,无法确定这是MySQL还是Django代码的问题 Django模型: class Resource(models.Model): ... voters = models.ManyToManyField(User, related_name="resources") 代码: SQL打印: 大意是 SELECT ..., COUNT(`app_res

在使用MyISAM在MySQL上运行的Django中,queryset上的my Count注释返回了不正确的结果。我查看了SQL语句,无法确定这是MySQL还是Django代码的问题

Django模型:

class Resource(models.Model):
    ...
    voters = models.ManyToManyField(User, related_name="resources")
代码:

SQL打印: 大意是

SELECT
...,
COUNT(`app_resource_voters`.`user_id`) AS `votes`
FROM `app_resource`
...
LEFT OUTER JOIN `app_resource_voters`
ON `app_resource`.`id` = `app_resource_voters`.`resource_id`
...

在phpMyAdmin中测试查询会返回错误的投票值。它实际上将投票者数量乘以ForeignKey关联的数量返回到资源上存在的其他属性,这些属性非常混乱。Django和SQL看起来正确吗?这是否意味着这是MySQL的问题?您是否建议切换到MyISAM以外的其他版本或切换到PostgreSQL?

您还可以使用另外两种方法作为解决方案

第一种方法比较简单,但效率较低:在资源模型上创建方法或属性

第二是使用:


Django文档使用与上述m2m关系中相同的方法计算项目。他们也错了吗?嗯,你是对的。我不知道。我将不得不编辑我的答案。在这种情况下,SQL中应该有一个GROUPBY app_resource.id子句。额外的工作。实际生成的queryset很大,因此我避免使用@property方法。为了稍微扩展代码,有一些方法可以通过model.\u meta.db\u table自动生成表名,但我不确定如何为m2m表获取这些数据@DrTyrsa,在我添加了一些额外的过滤器之前,文档的工作方式一直有效,然后它突然停止了。通过这个额外的子句修复了它。也许你可以发布你所做的其他过滤器?许多其他过滤器…并且计数对大多数过滤器都有效。最近的编辑是添加一个过滤器,检查m2m字段是否存在于集合中。示例:对于资源中带有m2m字段的模型GroupA,例如group_a,我们执行Resource.objects.filtergroup_a_in=group_a_set,其中group_a_set是要过滤的一组资源。只是最近的变化。
SELECT
...,
COUNT(`app_resource_voters`.`user_id`) AS `votes`
FROM `app_resource`
...
LEFT OUTER JOIN `app_resource_voters`
ON `app_resource`.`id` = `app_resource_voters`.`resource_id`
...
class Resource(models.Model):
    ...

    @property    # or @django.utils.functional.cached_property
    def votes(self):
        return self.voters.count()
resources = Resource.objects.filter(
    ...
).extra(
    select={
        'votes': 'SELECT COUNT(*) FROM app_resource_voters WHERE app_resource.id = app_resource_voters.resource_id'
    },
).order_by('-votes')