Django使用所需的WHERE子句注释和LEFT OUTER JOIN

时间:2017-07-01 19:59:49

标签: django python-3.x django-models django-orm

Django 1.10.6

Asset.objects.annotate( 
    coupon_saved=Count( 
        Q(coupons__device_id='8ae83c6fa52765061360f5459025cb85e6dc8905') 
    ) 
).all().query 

会产生以下查询:

SELECT
   "assets_asset"."id",
   "assets_asset"."title",
   "assets_asset"."description",
   "assets_asset"."created",
   "assets_asset"."modified",
   "assets_asset"."uid",
   "assets_asset"."org_id",
   "assets_asset"."subtitle",
   "assets_asset"."is_active",
   "assets_asset"."is_generic",
   "assets_asset"."file_standalone",
   "assets_asset"."file_ios",
   "assets_asset"."file_android",
   "assets_asset"."file_preview",
   "assets_asset"."json_metadata",
   "assets_asset"."file_icon",
   "assets_asset"."file_image",
   "assets_asset"."video_mobile",
   "assets_asset"."video_standalone",
   "assets_asset"."file_coupon",
   "assets_asset"."where_to_buy",
   COUNT("games_coupon"."device_id" = 8ae83c6fa52765061360f5459025cb85e6dc8905) AS "coupon_saved" 
FROM
   "assets_asset" 
   LEFT OUTER JOIN
      "games_coupon" 
      ON ("assets_asset"."id" = "games_coupon"."asset_id") 
GROUP BY
   "assets_asset"."id"

我需要将device_id=X纳入 LEFT OUTER JOIN 定义。

如何实现?

1 个答案:

答案 0 :(得分:0)

<强> TL; DR: 条件应该在filter

qs = (
    Asset.objects
    .filter(coupons__device_id='8ae83c6fa52765061360f5459025cb85e6dc8905')
    .annotate(coupon_saved=Count('coupons'))
)

如果您只想count > 0,则可以对其进行过滤。

qs = qs.filter(coupon_saved__gt=0)

脚注:将一对多查询编译为LEFT OUTER JOIN,以便能够获得零子项的基础对象(资产)。 Django中的JOIN每次都在ForeignKey上基于主键,或类似地在OneToOne或ManyToMany上,其他条件被编译为WHERE。

注释中的条件(您使用过的)是可能的,例如作为Conditional Expressions的一部分,但正确使用和使用它会更复杂,例如如果您希望通过一个没有子查询的查询获得许多条件的聚合,并且可以接受完整扫描。这可能不是问题的主题。