如何创建临时表而不丢失 django 中的 ORM?

Posted

技术标签:

【中文标题】如何创建临时表而不丢失 django 中的 ORM?【英文标题】:How to create a temporary table and not lose the ORM in django? 【发布时间】:2013-12-06 22:53:11 【问题描述】:

我很好奇如何在 django 中创建一个临时表? (数据库是mysql,有客户要求)

CREATE TEMPORARY TABLE somewhat_like_a_cache AS
(SELECT * FROM expensive_query_with_multiple_joins);
SELECT * FROM somewhat_like_a_cache LIMIT 1000 OFFSET X;

这背后的原因: 结果集相当大,我必须对其进行迭代。昂贵的查询大约需要 30 秒。如果没有临时表,我会对数据库服务器施加几个小时的压力。使用临时表,昂贵的查询只执行一次,之后在切片中迭代临时表很便宜。

这不是重复的 How do I create a temporary table to sort the same column by two criteria using Django's ORM?。作者只是想按两列排序。

【问题讨论】:

视图不能代替这个吗?另外,关闭连接后它不会消失。 据我所知,它与初始查询一样慢。 您可能想查看查询集缓存,例如 johnny cache pythonhosted.org/johnny-cache 【参考方案1】:

我遇到了这个问题,我构建了一个将模型同步到数据库的函数(改编自管理脚本syncdb

您可以在代码中的任何位置编写临时模型,甚至可以在运行时生成模型,然后调用sync_models。并享受ORM

顺便说一下,它的数据库独立,可以与任何django支持的数据库后端一起使用

from django.db import connection
from django.test import TestCase
from django.core.management.color import no_style
from importlib import import_module


def sync_models(model_list):
    '''
    Create the database tables for given models.
    '''
    tables = connection.introspection.table_names()
    seen_models = connection.introspection.installed_models(tables)
    created_models = set()
    pending_references = 
    cursor = connection.cursor()
    for model in model_list:
        # Create the model's database table, if it doesn't already exist.
        sql, references = connection.creation.sql_create_model(model, no_style(), seen_models)
        seen_models.add(model)
        created_models.add(model)
        for refto, refs in references.items():
            pending_references.setdefault(refto, []).extend(refs)
            if refto in seen_models:
                sql.extend(connection.creation.sql_for_pending_references(refto, no_style(), pending_references))
        sql.extend(connection.creation.sql_for_pending_references(model, no_style(), pending_references))
        for statement in sql:
            cursor.execute(statement)
        tables.append(connection.introspection.table_name_converter(model._meta.db_table))

【讨论】:

【参考方案2】:

我在 Postgresql 中测试了以下(也很少使用),但我认为你不会有任何问题。

Django 还为您提供了一个使用 connection 执行自定义 SQL 查询(INSERT, UPDATE, CREATE, DROP 等)的 api。 Here is the documentation关于使用情况

from django.db import connection, transaction
cursor = connection.cursor() #  create the cursor

cursor.execute("CREATE TEMPORARY TABLE test_table (code char(5)  PRIMARY KEY,
                                                   title varchar(40) NOT NULL);")
cursor.execute("INSERT into test_table (code, title) values ('ABVCD', 'This is my Title');")
cursor.execute("select * from test_table;") #  now select all data in our table
print cursor.fetchall() # and fetch them all
cursor.close()  # if you wish to close it

这是我用 Postgresql 9.1 测试的示例代码,但如果执行适合您的 DBMS 版本的查询,则不会有任何问题。

使用TEMPORARY 表或创建普通表并在完成工作后执行 drop 语句取决于您。但在开始之前请阅读文档。

【讨论】:

我知道这个功能,但它把 ORM 抛在了脑后。 您打算如何同时使用 ORM 和Temporary 表?还有另一种选择 (docs.djangoproject.com/en/1.3/topics/db/sql/…),您可以在 django ORM 上使用自定义查询,但您必须创建模型并将它们 syncdb 到您的 DBMS,然后才能使用它们.因此,编写一个将创建应用程序的脚本,记下models.py 并将其添加到settings.py 的应用程序中,然后使用 ,syncdb` 并在使用后将其删除?对我来说,这看起来不是一个好方法。您可能需要的是创建一个模型并在那里插入/删除 应该可以在运行时生成模型。字段的类型可以从创建临时表的查询中导出。 这会很困难,因为当您定义一个扩展 django.db.models.Model 的类时,它会查找您的模型所在的应用程序标签以设置一些相关值(例如数据库表名称)。在这种情况下,您要么创建目录和文件并对其进行编辑,要么尝试找到一种解决方案来克服基于应用程序的错误。 raw 让您执行基于模型的查询,但 AFAIK 仅限于 SELECT 查询。 @FallenAngel - 是否可以使用它像克隆一样复制现有模型,也许?谢谢。

以上是关于如何创建临时表而不丢失 django 中的 ORM?的主要内容,如果未能解决你的问题,请参考以下文章

在一个命令中删除所有表而不删除 django dbshel​​l 中的 postgres 中的数据库?

如何在 PL/SQL 中连接两个表而不创建新表

我想在提交时创建一个表而不重定向到 php 中的任何其他页面

从 orc 文件创建配置单元表而不指定架构

SQL Server - 合并大表而不锁定数据

面试题:合并两个已排序的单链表而不创建新节点