Django queryset-添加约束
我已经使用Django好几年了,但今天我正在努力为Django queryset-添加约束,django,group-by,sum,django-queryset,having,Django,Group By,Sum,Django Queryset,Having,我已经使用Django好几年了,但今天我正在努力为组添加约束 我的查询集如下所示: crm_models.Contact.objects\ .filter(dealercontact__dealer__pk__in=(265,), dealercontact__activity='gardening', date_data_collected__gte=datetime.date(2012,10,1), date_data_collected
组添加约束
我的查询集如下所示:
crm_models.Contact.objects\
.filter(dealercontact__dealer__pk__in=(265,),
dealercontact__activity='gardening',
date_data_collected__gte=datetime.date(2012,10,1),
date_data_collected__lt=datetime.date(2013,10,1))\
.annotate(nb_rels=Count('dealercontact'))
这给了我以下MySQL查询:
SELECT *
FROM `contact`
LEFT OUTER JOIN `dealer_contact` ON (`contact`.`id_contact` = `dealer_contact`.`id_contact`)
WHERE (`dealer_contact`.`active` = True
AND `dealer_contact`.`activity` = 'gardening'
AND `contact`.`date_data_collected` >= '2012-10-01'
AND `contact`.`date_data_collected` < '2013-10-01'
AND `dealer_contact`.`id_dealer` IN (265))
GROUP BY `contact`.`id_contact`
ORDER BY NULL;
我如何用Django Queryset修复这个问题?在这种情况下,我需要一个查询集
在这里,我使用annotate只是为了在contact.id\u contact
上获取groupby
编辑:我的目标是获得在dealercontact中没有“客户”关系但有“参考”关系的联系人(当然根据WHERE子句)
模型
我的目标是让那些与公司没有“客户”关系的联系人参与进来
dealercontact但具有“参考”关系(根据WHERE
条款(当然)
此简单查询满足此要求:
Contact.objects.filter(dealercontact__type="ref").exclude(dealercontact__type="customer")
这足够了吗,还是你需要它来做更多的事情
更新:如果您的要求是
具有“参考”关系但没有“客户”关系的联系人
与同一经销商的关系
您可以这样做:
from django.db.models import Q
Contact.objects.filter(Q(dealercontact__type="ref") & ~Q(dealercontact__type="customer"))
您是否仅仅因为需要orm对象而使用原始查询?使用Contact.objects.raw()
生成类似的实例过滤器
。请参阅以获取更多帮助。我通过在DealerContact
中添加两个二进制字段解决了这个问题:是ref
和是customer
如果type='ref'
则为\u ref=1
且为\u customer=0
。
否则,如果type='customer'
则为\u ref=0
且为\u customer=1
因此,我现在可以使用注释(nb_customers=Sum('is_customer'))
然后使用过滤器(nb_customers=0)
最终查询集包括:
Contact.objects.filter(dealercontact__dealer__pk__in=(265,),
dealercontact__activity='gardening',
date_data_collected__gte=datetime.date(2012,10,1),
date_data_collected__lt=datetime.date(2013,10,1))\
.annotate(nb_customers=Sum('dealercontact__is_customer'))\
.filter(nb_customers=0)
实际上,如果需要,可以添加自己的自定义HAVING
和groupby
子句
请谨慎使用我的示例-如果Django ORM代码/路径在未来的Django版本中发生更改,您也必须更新代码
图像您有图书和版本模型,其中每本书可以有多个版本,并且您希望在图书查询集中选择第一个美国版本日期
在Django 1.5+中添加具有
和
分组依据子句的自定义:
from django.db.models import Min
from django.db.models.sql.where import ExtraWhere, AND
qs = Book.objects.all()
# Standard annotate
qs = qs.annotate(first_edition_date=Min("edition__date"))
# Custom HAVING clause, to limit annotation by US country only
qs.query.having.add(ExtraWhere(['"app_edition"."country"=%s'], ["US"]), AND)
# Custom GROUP BY clause will be needed too
qs.query.group_by.append(("app_edition", "country"))
ExtraWhere
不仅可以包含字段,还可以包含任何原始sql条件和函数。我不确定这一点,但可能.extra()在这里很有用,我尝试过,但注释+extra给了我以下错误:DatabaseError:(1111,“组函数的使用无效”)。查询集将“SUM(…)”添加到SELECT子句和GROUPBY子句中,我对此感到奇怪。也许我可以在没有注释的情况下使用extra,并且仍然保留get GROUP BY?当您使用Django ORM时,您不应该考虑SQL语句。这并不总是可能的,因此.extra()
和.raw()
,但是如果你明确地满足了你想要的效果,那么给你的问题一个好的答案就会容易得多。你能添加你的模型吗?我不尝试用SQL来思考,但我正在尝试适应Django Querysets的一个弱点,但我希望我能简单地做到,我错了。我首先从一个简单的Django Queryset中获得了上面的MySQL查询。我编辑了我的问题:我的目标是获得在dealercontact中没有“customer”关系但有“ref”关系的联系人。谢谢:)使用.raw()
应该是最后的选择。它首先违背了使用ORM的目的。不幸的是,没有。Django在排除时似乎没有考虑过滤器参数,因此排除了与其他经销商(例如与其他经销商有dealercontact type='customer'的联系人)。我在这里得不到我需要的东西。我很难理解你的要求。这正是我理解他们的方式。这将返回与任何人都没有单一“客户”关系的联系人,以及与某人至少有一个“参考”关系的联系人。如果这不是您想要的,请澄清。是“与同一经销商有“参考”关系但没有“客户”关系的联系人”吗?是的,事实上,对于过滤器中给出的其他参数,没有与给定经销商的客户关系。恐怕我仍然无法理解您的目标,所以我帮不了你。抱歉。它只是给出了一个错误:“Query”对象没有“having”属性
Contact.objects.filter(dealercontact__dealer__pk__in=(265,),
dealercontact__activity='gardening',
date_data_collected__gte=datetime.date(2012,10,1),
date_data_collected__lt=datetime.date(2013,10,1))\
.annotate(nb_customers=Sum('dealercontact__is_customer'))\
.filter(nb_customers=0)
from django.db.models import Min
from django.db.models.sql.where import ExtraWhere, AND
qs = Book.objects.all()
# Standard annotate
qs = qs.annotate(first_edition_date=Min("edition__date"))
# Custom HAVING clause, to limit annotation by US country only
qs.query.having.add(ExtraWhere(['"app_edition"."country"=%s'], ["US"]), AND)
# Custom GROUP BY clause will be needed too
qs.query.group_by.append(("app_edition", "country"))