【问题标题】:LEFT JOIN with other param in ON Django ORM在 Django ORM 中与其他参数 LEFT JOIN
【发布时间】:2021-07-14 20:54:54
【问题描述】:

我有以下型号:

class Customer(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField(max_length = 255, default='example@example.com')
    authorized_credit = models.IntegerField(default=0)
    balance = models.IntegerField(default=0)


class Transaction(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
    payment_amount = models.IntegerField(default=0) #can be 0 or have value
    exit_amount = models.IntegerField(default=0) #can be 0 or have value
    transaction_date = models.DateField()

我想查询获取所有客户信息和最后付款日期。

我在 postgres 中有这个查询是正确的,只是我需要:

 select e.*, max(l.transaction_date) as last_date_payment
 from app_customer as e
 left join app_transaction as l
 on e.id = l.customer_id and l.payment_amount != 0
 group by e.id
 order by e.id

但我需要在 django 中使用此查询作为序列化程序。我尝试这样做,但返回其他查询

In Python:
print(Customer.objects.filter(transaction__isnull=True).order_by('id').query)
>>> SELECT app_customer.id, app_customer.name, app_customer.email, app_customer.balance FROM app_customer 
LEFT OUTER JOIN app_transaction 
ON (app_customer.id = app_transaction.customer_id) 
WHERE app_transaction.id IS NULL 
ORDER BY app_customer.id ASC

但我需要的是这一行

example

【问题讨论】:

  • 嗨,欢迎来到堆栈溢出。我会尽力解决你的问题。

标签: python python-3.x django django-models django-rest-framework


【解决方案1】:

无论您是否使用序列化程序,您都可以为这两个任务重用相同的视图/函数。

首先要获取当前客户对象的交易详细信息,您必须知道related_name.related_name 具有默认值,但您可以提及一些独特 以便您记住。

改变你的模型:

class Transaction(models.Model):
    customer = models.ForeignKey(Customer, related_name="transac_set",on_delete=models.CASCADE)

related_names 是 django 中创建从 CustomerTransaction 的反向关系的一种方式,这样您就可以执行 Customer cus.transac_set.all() 并且它将获取 cus 对象的所有事务。 由于您可能有多个客户为您获取交易详细信息,因此您可以在查询时使用select_related(),这将最少访问数据库的次数并为您获取所有数据。

创建函数定义,获取客户所有交易的数据:

def get_cus_transac(cus_id_list):
    #here cus_id_list is the list of ids you need to fetch
    cus_transac_list = Transaction.objects.select_related(customer).filter(id__in = cus_id_list)
    return cus_transac_list

出于您的目的,您需要使用另一种方式,这就是您需要 related_nameprefetch_related() 的原因。

创建一个函数定义来获取客户最新交易的数据:***警告:我在睡觉前输入了这个答案,所以这里无法获取最新的交易价值.我稍后会添加它,但您可以使用类似的条件并以这种方式完成。

def get_latest_transac(cus_id_list):
    #here cus_id_list is the list of ids you need to fetch
    latest_transac_list = Customer.objects.filter(id__in = cus_id_list).prefetch_related('transac_set')
    return latest_transac_list

现在来到序列化器,您需要有 3 个序列化器(实际上您只需要 2 个,但第三个可以序列化客户数据 + 您需要的最新交易)...一个用于交易,另一个用于客户,然后是第三个序列化器组合他们。

代码中可能有一些错误,或者我可能遗漏了一些细节。因为我没有检查过它。我假设你知道如何制作相同的序列化器和视图。

【讨论】:

    【解决方案2】:

    一种方法是使用subqueries:

    transaction_subquery = Transaction.objects.filter(
        customer=OuterRef('pk'), payment_amount__gt=0,
    ).order_by('-transaction_date')
    
    Customer.objects.annotate(
        last_date_payment=Subquery(
            transaction_subquery.values('transaction_date')[:1]
        )
    )
    

    这将在一个查询中获取所有客户数据,并使用其最后一个支付金额为非零的交易日期进行注释。

    【讨论】:

      【解决方案3】:

      解决您的问题:

      我想查询获取所有客户信息和最后付款日期。

      您可以尝试将order bydistinct 结合使用:

      Customer.objects.prefetch_related('transaction_set').values('id', 'name', 'email', 'authorized_credit', 'balance', 'transaction__transaction_date').order_by('-transaction__transaction_date').distinct('transaction__transaction_date')
      

      注意:

      仅当distinct 后跟参数时才适用于PostgreSQL。 distinct的用法:https://docs.djangoproject.com/en/3.2/ref/models/querysets/#distinct

      【讨论】:

        猜你喜欢
        • 2015-08-21
        • 1970-01-01
        • 2015-08-21
        • 2010-09-29
        • 1970-01-01
        • 2018-06-03
        • 2013-07-02
        • 2019-08-03
        相关资源
        最近更新 更多