为什么Django不重置SQLite3中的序列?

2024-09-29 21:39:24 发布

您现在位置:Python中文网/ 问答频道 /正文

为什么Django允许您重置postgres和其他DBMS上的sequences(AutoID)字段,而不允许SQLite3?在

查看django/db/backends/sqlite3/base.pysql_flush方法的源代码,有一条注释说:

Note: No requirement for reset of auto-incremented indices (cf. other sql_flush() implementations). Just return SQL at this point

我在一些测试中加载了依赖于绝对主键id的fixture文件。因为Django没有重置SQLite的autoid字段,所以这些fixture不能正确加载。在

在sqlite中重置auto-id列似乎有点简单:How can I reset a autoincrement sequence number in sqlite


Tags: djangoidautosqlitesqlpostgresfixturesqlite3
2条回答

您可以按如下方式对sql_flush进行monkey-patch,以重置SQLite序列:

from django.db.backends.sqlite3.operations import DatabaseOperations
from django.db import connection


def _monkey_patch_sqlite_sql_flush_with_sequence_reset():
    original_sql_flush = DatabaseOperations.sql_flush

    def sql_flush_with_sequence_reset(self, style, tables, sequences, allow_cascade=False):
        sql_statement_list = original_sql_flush(self, style, tables, sequences, allow_cascade)
        if tables:
            # DELETE FROM sqlite_sequence WHERE name IN ($tables)
            sql = '%s %s %s %s %s %s (%s);' % (
                style.SQL_KEYWORD('DELETE'),
                style.SQL_KEYWORD('FROM'),
                style.SQL_TABLE(self.quote_name('sqlite_sequence')),
                style.SQL_KEYWORD('WHERE'),
                style.SQL_FIELD(self.quote_name('name')),
                style.SQL_KEYWORD('IN'),
                ', '.join(style.SQL_FIELD(f"'{table}'") for table in tables)
            )
            sql_statement_list.append(sql)
        return sql_statement_list

    DatabaseOperations.sql_flush = sql_flush_with_sequence_reset

例如在TransactionTestCase中使用它:

^{pr2}$

这可以确保依赖于固定主键的测试同时适用于SQLite和其他数据库后端(如PostgreSQL)。但是,有关reset_sequences的注意事项,请参见Django documentation。一方面,它使测试变慢。在

也许这个片段可以帮助:

import os

from django.core.management import call_command
from django.db import connection
from django.utils.six import StringIO


def reset_sequences(app_name):
    os.environ['DJANGO_COLORS'] = 'nocolor'
    buf = StringIO()
    call_command('sqlsequencereset', app_name, stdout=buf)
    buf.seek(0)

    sql = "".join(buf.readlines())

    with connection.cursor() as cursor:
        cursor.execute(sql)

    print("Sequences for app '{}' reset".format(app_name))

相关问题 更多 >

    热门问题