【问题标题】:How can i add filter to all querysets at the end of sql-query?如何在 sql-query 末尾向所有查询集添加过滤器?
【发布时间】:2019-04-28 04:17:36
【问题描述】:

如果我在管理器中添加过滤器,对数据库的 sql 查询将太长,因为我的过滤器将在 sql-query 的开头。

在应用所有其他过滤器和更改后,我需要在最后运行此过滤器。

当前查询集:

links = Link.objects.all().filter_deleted()
links = links.filter(linkname='linkname', left_uuid__in=all_uuids)
links = links.filter(left_type='type')
links = links.values_list('left_uuid', 'right_uuid', 'right_type')

编译完queruset后的SQL查询:

SELECT "baseobj_link"."left_uuid", "baseobj_link"."right_uuid", "baseobj_link"."right_type_id"
FROM "baseobj_link"
WHERE (
    "baseobj_link"."id" IN (
        SELECT DISTINCT ON (U0."linkname", U0."left_uuid", U0."right_uuid") U0."id" AS Col1
        FROM "baseobj_link" U0
        WHERE U0."config_id" IN (2848)
        ORDER BY U0."linkname" ASC, U0."left_uuid" ASC, U0."right_uuid" ASC, U0."domain_level" ASC, U0."config_id" DESC, U0."is_deleted" DESC
    ) AND
    "baseobj_link"."is_deleted" = false AND
    "baseobj_link"."linkname" = 'linkname' AND
    "baseobj_link"."left_uuid" IN (
        SELECT V0."uuid" AS Col1
        FROM "structure_cgw" V0
        WHERE (
            V0."id" IN (
                SELECT DISTINCT ON (U0."uuid") U0."id" AS Col1
                FROM "structure_cgw" U0
                WHERE U0."config_id" IN (2848)
                ORDER BY U0."uuid" ASC, U0."domain_level" DESC, U0."config_id" DESC
            ) AND
            V0."is_deleted" = false
        )
    ) AND
    "baseobj_link"."left_type_id" = 6
);
args=(2848, False, 'linkname', 2848, False, 6)

filter_deleted()生成的部分:

"baseobj_link"."id" IN (
    SELECT DISTINCT ON (U0."linkname", U0."left_uuid", U0."right_uuid") U0."id" AS Col1
    FROM "baseobj_link" U0
    WHERE U0."config_id" IN (2848)
    ORDER BY U0."linkname" ASC, U0."left_uuid" ASC, U0."right_uuid" ASC, U0."domain_level" ASC, U0."config_id" DESC, U0."is_deleted" DESC
)

需要将此代码添加到此模型的所有查询的末尾,因此这不是一项简单的任务。

如何最有效地解决这个问题?

【问题讨论】:

  • 您好,请详细说明您的问题并添加一些您想要实现的代码

标签: django database orm django-queryset


【解决方案1】:

听起来您正在尝试对子查询运行过滤器。因此,将您希望首先运行的所有代码放入子查询中。然后在最后一个过滤器中完成该查询后运行您希望应用的过滤器。

看起来像这样:

SELECT *
FROM    (
        SELECT "baseobj_link"."left_uuid", "baseobj_link"."right_uuid", "baseobj_link"."right_type_id"
        FROM "baseobj_link"
        WHERE
            "baseobj_link"."is_deleted" = false AND
            "baseobj_link"."linkname" = 'cgw_vhost' AND
            "baseobj_link"."left_uuid" IN (
                SELECT V0."uuid" AS Col1
                FROM "structure_cgw" V0
                WHERE (
                    V0."id" IN (
                        SELECT DISTINCT ON (U0."uuid") U0."id" AS Col1
                        FROM "structure_cgw" U0
                        WHERE U0."config_id" IN (2848)
                        ORDER BY U0."uuid" ASC, U0."domain_level" DESC, U0."config_id" DESC
                    ) AND
                    V0."is_deleted" = false
                )
            AND "baseobj_link"."left_type_id" = 6
        ) AS t1
WHERE t1.id IN (
    SELECT DISTINCT ON (U0."linkname", U0."left_uuid", U0."right_uuid") U0."id" AS Col1
    FROM "baseobj_link" U0
    WHERE U0."config_id" IN (2848)
    ORDER BY U0."linkname" ASC, U0."left_uuid" ASC, U0."right_uuid" ASC, U0."domain_level" ASC, U0."config_id" DESC, U0."is_deleted" DESC
)

来自派生表上的 MYSQL documentation

派生表是在查询 FROM 子句范围内生成表的表达式。例如,SELECT 语句 FROM 子句中的子查询是派生表:

SELECT ... FROM (subquery) [AS] tbl_name ...

让我知道这是怎么回事。

【讨论】:

  • 这不是一个简单的案例,我需要为模型的所有查询添加过滤器。将这个过滤器添加到代码中的每个查询是错误的,因为代码中有很多地方可以构建对模型的查询。
【解决方案2】:

Всвоей модели queryset'а дополнительно храним queryset без filter_deleted и переопределяем метод _filter_or_exclude, чтобы тот вызывал _filter_or_exclude у хранимог queryset Также храним флаг фильтрации, чтобы знать когда нужно вызывать базовый _filter_or_exclude, когда filter_deleted。

【讨论】:

    猜你喜欢
    • 2012-08-26
    • 2018-02-17
    • 1970-01-01
    • 2016-01-18
    • 2018-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多