繁体   English   中英

生成的django queryset有效,但是在django中运行失败

[英]Generated django queryset works, but running it in django fails

我尝试用“ myApp_Instructionssteptranslation”替换INNER_QUERY,并且也将其保留,但这只会带来其他错误。

那么,生成的查询在分开时如何正常工作,但是当我们想使用Django检索其结果时却失败了? 以及如何解决该问题,使其表现得也与我想要的一样?我们有一个模型InstructionsStep,该模型具有一个对Instructions的外键,该外键又与一个库相连。 InstructionsStep具有描述,但是由于可能存在多种语言,因此该描述存储在一个单独的模型中,该模型包含语言代码和以该语言翻译的描述。

但是出于性能原因,我们需要能够获得一个指令步骤的查询集,其中描述以默认语言(存储在库中)进行注释。 为了实现这一点并避免django对注解中的联接的限制,我们创建了一个自定义的Aggregate函数来检索该语言。 (DefaultInstructionsStepTranslationDescription)

class InstructionsStepTranslationQuerySet(models.query.QuerySet):
    def language(self, language):
        class DefaultInstructionsStepTranslationDescription(Aggregate):

            template = '''
                        (%(function)s %(distinct)s INNER_QUERY."%(expressions)s" FROM (
                            SELECT "myApp_Instructionssteptranslation"."description" AS "description", 
                                    MIN("myUser_library"."default_language") AS "default_language"
                            FROM "myApp_Instructionssteptranslation" 
                                    INNER JOIN "myApp_Instructionsstep" A_ST ON ("myApp_Instructionssteptranslation"."Instructions_step_id" = A_ST."id") 
                                    INNER JOIN "myApp_Instructions" ON (A_ST."Instructions_id" = "myApp_Instructions"."id") 
                                    LEFT OUTER JOIN "myUser_library" ON ("myApp_Instructions"."library_id" = "myUser_library"."id") 
                           WHERE "myApp_Instructionssteptranslation"."Instructions_step_id" = "myApp_Instructionsstep"."id"
                           and "myApp_Instructionssteptranslation"."language" = default_language 
                           GROUP BY "myApp_Instructionssteptranslation"."id" 
                      ) AS INNER_QUERY 
                      LIMIT 1
                      '''
            function = 'SELECT'

            def __init__(self, expression='', **extra):
                super(DefaultInstructionsStepTranslationDescription, self).__init__(
                    expression,
                    distinct='',
                    output_field=CharField(),
                    **extra
                )

        return self.annotate(
            t_description=
            Case(
                When(id__in = InstructionsStepTranslation.objects\
                                .annotate( default_language = Min(F("Instructions_step__Instructions__library__default_language")))\
                                .filter( language=F("default_language") )\
                                .values_list("Instructions_step_id"),
                     then=DefaultInstructionsStepTranslationDescription(Value("description"))
                ),
                default=Value("error"),
                output_field=CharField()
            )
        )

这将生成以下sql查询(该数据库是postgres数据库)

    SELECT "myApp_Instructionsstep"."id",
           "myApp_Instructionsstep"."original_id",
           "myApp_Instructionsstep"."number",
           "myApp_Instructionsstep"."Instructions_id",
           "myApp_Instructionsstep"."ccp",
           CASE
               WHEN "myApp_Instructionsstep"."id" IN
                      (SELECT U0."Instructions_step_id"
                       FROM "myApp_Instructionssteptranslation" U0
                       INNER JOIN "myApp_Instructionsstep" U1 ON (U0."Instructions_step_id" = U1."id")
                       INNER JOIN "myApp_Instructions" U2 ON (U1."Instructions_id" = U2."id")
                       LEFT OUTER JOIN "myUser_library" U3 ON (U2."library_id" = U3."id")
                       GROUP BY U0."id"
                       HAVING U0."language" = (MIN(U3."default_language"))) THEN
                      (SELECT INNER_QUERY."description"
                       FROM
                         (SELECT "myApp_Instructionssteptranslation"."description" AS "description",
                                 MIN("myUser_library"."default_language") AS "default_language"
                          FROM "myApp_Instructionssteptranslation"
                          INNER JOIN "myApp_Instructionsstep" A_ST ON ("myApp_Instructionssteptranslation"."Instructions_step_id" = A_ST."id")
                          INNER JOIN "myApp_Instructions" ON (A_ST."Instructions_id" = "myApp_Instructions"."id")
                          LEFT OUTER JOIN "myUser_library" ON ("myApp_Instructions"."library_id" = "myUser_library"."id")
                          WHERE "myApp_Instructionssteptranslation"."Instructions_step_id" = "myApp_Instructionsstep"."id"
                            and "myApp_Instructionssteptranslation"."language" = default_language
                          GROUP BY "myApp_Instructionssteptranslation"."id") AS INNER_QUERY
                       LIMIT 1)
               ELSE 'error'
           END AS "t_description"
    FROM "myApp_Instructionsstep"
    WHERE "myApp_Instructionsstep"."id" = 438
    GROUP BY "myApp_Instructionsstep"."id"
    ORDER BY "myApp_Instructionsstep"."number" ASC

在Postico中粘贴时可以正常工作。

但是,在django中运行它,

step_id = 438
# InstructionsStep.objectsobjects is overrided with a custom manager that uses the above defined custon queryset
step_queryset = InstructionsStep.objects.language('en').filter(id=step_id) 
retrieved_steps = step_queryset.all()

给出以下错误:

LINE 1: ...ge" = (MIN(U3."default_language"))) THEN (SELECT  INNER_QUER...
                                                         ^
HINT:  Perhaps you meant to reference the column "inner_query.description".

我尝试用“ myApp_Instructionssteptranslation”替换INNER_QUERY,并且也将其保留,但这只会带来其他错误。

那么,生成的查询在分开时如何正常工作,但是当我们想使用Django检索其结果时却失败了? 以及如何解决该问题,使其表现得也与我想要的一样?

同时,我发现带有.query属性的打印查询与实际执行的查询不同。

在这种情况下,它打印了SELECT INNER_QUERY."description" ,但是执行了SELECT INNER_QUERY."'description'" 之所以添加单引号,是因为为InstructionsStepTranslationQuerySet提供了Value(“ description”)表达式

最后,我通过传递id字段( F("id") )并使用它代替A_ST."id"解决了我的问题。 (遗憾的是,这是必需的,因为Aggregate不允许传递空表达式)

暂无
暂无

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

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