【问题标题】:Annotate QuerySet using raw SQL使用原始 SQL 注释 QuerySet
【发布时间】:2020-01-03 23:53:34
【问题描述】:

如果我问错了问题,让我首先说明最终目标:我需要允许用户通过不在主要模型 (Salesleadquote) 中的字段过滤 ListView,而是该字段来自模型(Salesleadbusinessgroup) 与相关模型 (Saleslead) 的 FK。 我试图解决这个问题的方法是在 Salesleadquote 上注释一个字段。

模型:

class Salesleadquote(models.Model):
    salesleadquoteid = models.AutoField(db_column='SalesLeadQuoteId', primary_key=True) 
    salesleadid = models.ForeignKey(Saleslead, models.DO_NOTHING, db_column='SalesLeadId')
    ...
class Saleslead(models.Model):
    salesleadid = models.AutoField(db_column='SalesLeadId', primary_key=True)
    ...
class Salesleadbusinessgroup(models.Model):
    salesleadbusinessgroupid = models.AutoField(db_column='SalesLeadBusinessGroupId', primary_key=True) 
    salesleadid = models.ForeignKey(Saleslead, models.DO_NOTHING, db_column='SalesLeadId')
    businessgroupid = models.ForeignKey(Businessgroup, models.DO_NOTHING, db_column='BusinessGroupId') 

所需的结果(查询集),在 SQL 中:

SELECT slq.*, slbg.BusinessGroupId FROM crm.SalesLeadQuote slq
LEFT JOIN
(SELECT SalesLeadId, BusinessGroupId
FROM crm.SalesLeadBusinessGroup ) slbg
ON slbg.SalesLeadId = slq.SalesLeadId
WHERE slbg.BusinessGroupId IN (5,21)

我知道我可以通过执行类似的操作来获得 RawQuerySet

 Salesleadquote.objects.raw("SELECT salesleadquote.*, \
                salesleadbusinessgroup.businessgroupid \
                FROM salesleadquote \
                LEFT JOIN salesleadbusinessgroup \
                ON salesleadquote.salesleadid = salesleadbusinessgroup.salesleadid \
                WHERE salesleadbusinessgroup.businessgroupid IN (5,21)")

但我需要 QuerySet 的功能,所以我的想法是在 Salesleadquote 中注释所需的字段(businessgroupid),但我一直在努力解决如何实现这一点。

【问题讨论】:

    标签: django


    【解决方案1】:

    我实施了一种解决方法,它不能解决我原来的问题,但适用于我的用例。我使用我发布的 SQL 在数据库级别创建了一个视图(称为 SalesLeadQuoteBG),然后将其绑定到一个模型以与 Django 的 ORM 一起使用。

    class Salesleadquotebg(models.Model):
        """
        This model represents a database view that extends the Salesleadquote table with a business group id column.
        There can be multiple business groups per quote, resulting in duplicate quotes, but this is handled at the view and template layer
        via filtering (users are required to select a business group).
        """
        salesleadquoteid = models.IntegerField(db_column='SalesLeadQuoteId', primary_key=True)  # Field name made lowercase.
        salesleadid = models.ForeignKey(Saleslead, models.DO_NOTHING, db_column='SalesLeadId')  # Field name made lowercase.
        ...
        businessgroupid = models.ForeignKey(Businessgroup, models.DO_NOTHING, db_column='BusinessGroupId')
    

    我正在使用 django-filters 进行过滤。

    filters.py:

    BG_CHOICES = (
                    (5, 'Machine Vision'),
                    (21, 'Process Systems'),
                 )
    class BGFilter(django_filters.FilterSet):
        businessgroupid = django_filters.ChoiceFilter(choices=BG_CHOICES)
        class Meta:
            model = Salesleadquotebg
            fields = ['businessgroupid', ]
    

    【讨论】:

      【解决方案2】:

      这可以用纯 Django ORM 来完成。关系可以向后跟踪(过滤salesleadbusinessgroup),双下划线语法可以用来查询相关模型的属性,也可以跟踪更多的关系

      Salesleadquote.objects.filter(
          salesleadbusinessgroup__businessgroupid__in=(5,21)
      )
      

      【讨论】:

        猜你喜欢
        • 2017-11-03
        • 1970-01-01
        • 2019-08-05
        • 2019-04-03
        • 1970-01-01
        • 2016-09-07
        • 2015-02-16
        • 2011-08-17
        • 2016-01-07
        相关资源
        最近更新 更多