简体   繁体   English

我需要将原始MySQL查询转换为Django ORM查询

[英]I need to convert raw MySQL query to Django ORM query

I have models.py that represent below: 我有表示以下内容的models.py:

from django.db import models
from django.db.models.signals import post_save

# Create your models here.
from django.http import request


class Task(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    description = models.CharField(max_length=512)
    cost = models.DecimalField(decimal_places=2, max_digits=8)

    def __str__(self):
        return self.description + "-" + str(self.cost)


class TaskStatus(models.Model):
    STATUS = (
        (0, 'Created'),
        (1, 'Taken'),
        (2, 'Reissued'),
        (3, 'On approve'),
        (4, 'Done'),
    )
    task_id = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True)
    status = models.PositiveSmallIntegerField(choices=STATUS, default=0)

    def __str__(self):
        return str(self.task_id) + ' ' + str(self.status)

    def create_status(sender, instance, **kwargs):
        if kwargs['created']:
            task_status = TaskStatus.objects.create(task_id=instance.id)

    post_save.connect(create_status, sender=Task)

I have to translate that mysql query to django ORM query. 我必须将mysql查询转换为Django ORM查询。 I got stack on this for 2 days. 我在上面堆了2天。 And please suggest me some useful links to understand how to perform. 并请建议我一些有用的链接以了解如何执行。

SELECT t.created,
      t.description,
      (SELECT MAX(s.created)
       FROM task_statuses s
       WHERE s.task_id = t.id AND s.status_type = 3
       GROUP BY s.task_id) as task_on_approve
FROM task t
WHERE t.created BETWEEN '2019-04-01 00:00:00' AND '2019-04-30 23:59:59';

Take a look at the Django docs for Subquery . 看看Subquery的Django文档。 Link . 链接

In a nutshell, this is what you're looking for: 简而言之,这就是您想要的:

from django.db import models

Task.objects.filter(created__gte='2019-04-01', created__lt='2019-05-01').annotate(task_on_approve=models.Subquery(TaskStatus.objects.filter(task_id=models.OuterRef('id'), status_type=3).order_by('-created').values('created')[:1], output_field=models.DateTimeField())).values('created', 'description', 'task_on_approve')

Try this. 尝试这个。 I am tested this code 100% working. 我已对此代码进行了100%的测试。

from datetime import datetime
from datetime import timezone

from django.core.management.base import BaseCommand, CommandError
from django.db.models import Avg, Max, Min, Sum, DateTimeField
from django.db.models import OuterRef, Subquery

from app.models import Task, TaskStatus

class Command(BaseCommand):
    def handle(self, *args, **options):

        sub_query = TaskStatus.objects\
            .annotate(max_created_date=Max('created'))\
            .filter(\
                task_id=OuterRef('pk'),
                status=3
            )

        from_datetime = datetime.strptime('2019-04-01 00:00:00', '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
        to_datetime = datetime.strptime('2019-04-30 23:59:59', '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)

        query = Task.objects.annotate(
            task_on_approve=Subquery(
                sub_query.values('max_created_date')[:1],
                output_field=DateTimeField()
            )
        ).filter(
            created__range=[
                from_datetime,
                to_datetime
            ]
        )

        print(query.query)

        self.stdout.write('Done.')

Output 输出量

SELECT "app_task"."id", "app_task"."created", "app_task"."description", "app_task"."cost", (SELECT MAX(U0."created") AS "max_created_date" FROM "app_taskstatus" U0 WHERE (U0."status" = 3 AND U0."task_id" = ("app_task"."id")) GROUP BY U0."id", U0."task_id", U0."created", U0."status"  LIMIT 1) AS "task_on_approve" FROM "app_task" WHERE "app_task"."created" BETWEEN 2019-04-01 00:00:00 AND 2019-04-30 23:59:59

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM