数据库

Django正式支持以下数据库:

还有一些 database backends provided by third parties .

Django尝试在所有数据库后端支持尽可能多的功能。然而,并非所有的数据库后端都是相同的,我们必须对哪些特性需要支持以及哪些假设可以安全地进行设计决策。

这个文件描述了一些可能与Django使用相关的特性。它不打算取代服务器特定的文档或参考手册。

一般注释

持久连接

持久连接避免了在每个HTTP请求中重新建立到数据库的连接的开销。它们是由 CONN_MAX_AGE 参数,该参数定义连接的最长生存期。它可以为每个数据库单独设置。

默认值为 0 ,保留在每个请求结束时关闭数据库连接的历史行为。要启用永久连接,请设置 CONN_MAX_AGE 秒的正整数。对于无限制的持久连接,将其设置为 None .

连接管理

Django在首次进行数据库查询时打开与数据库的连接。它使这个连接保持打开状态,并在随后的请求中重用它。当连接超过 CONN_MAX_AGE 或者当它不再可用时。

详细地说,Django在需要数据库连接时自动打开到数据库的连接,但它还没有连接,这可能是因为这是第一个连接,也可能是因为前一个连接已关闭。

在每个请求的开始,Django会关闭连接(如果连接已达到其最大期限)。如果数据库在一段时间后终止空闲连接,则应设置 CONN_MAX_AGE 以使django不尝试使用已被数据库服务器终止的连接。(此问题可能只影响非常低的流量站点。)

在每个请求结束时,如果连接已达到其最大寿命或处于不可恢复的错误状态,Django将关闭连接。如果在处理请求时发生任何数据库错误,Django将检查连接是否仍在工作,如果连接不工作,则将其关闭。因此,数据库错误最多影响每个应用程序的工作线程一个请求;如果连接变得不可用,则下一个请求将获得新的连接。

设置 CONN_HEALTH_CHECKSTrue 可用于提高连接重用的健壮性,并在数据库服务器关闭连接时防止错误,数据库服务器现在已准备好接受和服务新连接,例如在数据库服务器重新启动之后。每个请求仅执行一次运行状况检查,并且仅当在处理请求期间访问数据库时执行。

告诫

因为每个线程都维护自己的连接,所以您的数据库必须至少支持与工作线程相同数量的同时连接。

有时大多数视图都无法访问数据库,例如,因为它是外部系统的数据库,或者由于缓存。在这种情况下,你应该 CONN_MAX_AGE 低值,甚至 0 ,因为维护不太可能重用的连接是没有意义的。这将有助于保持与此数据库的同时连接数较少。

开发服务器为它处理的每个请求创建一个新线程,从而消除持久连接的影响。在开发过程中不要启用它们。

当Django建立到数据库的连接时,它会根据所使用的后端设置适当的参数。如果启用持久连接,则不再重复每个请求。如果修改连接的隔离级别或时区等参数,则应在每个请求结束时恢复django的默认值,在每个请求开始时强制使用适当的值,或者禁用持久连接。

如果在Django的请求-响应周期之外的长期运行流程中创建连接,则该连接将保持打开状态,直到显式关闭或发生超时。

编码

Django假设所有数据库都使用UTF-8编码。使用其他编码可能会导致意外行为,例如数据库中有效数据的“值太长”错误。有关如何正确设置数据库的信息,请参阅下面特定于数据库的说明。

PostgreSQL注释

Django支持PostgreSQL 13及更高版本。 psycopg 3.1.8+或 psycopg2 需要2.8.4以上版本,但最新版本 psycopg 建议使用3.1.8+。

备注

支持 psycopg2 很可能会在将来的某个时候被弃用和移除。

PostgreSQL连接设置

HOST 有关详细信息。

若要使用来自 connection service file 和来自 password file ,则必须在 OPTIONS 中的数据库配置的一部分 DATABASES

settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "OPTIONS": {
            "service": "my_service",
            "passfile": ".my_pgpass",
        },
    }
}
.pg_service.conf
[my_service]
host=localhost
user=USER
dbname=NAME
port=5432
.my_pgpass
localhost:5432:NAME:USER:PASSWORD

PostgreSQL后端将 OPTIONS 作为连接构造函数的关键字参数,允许对驱动程序行为进行更高级的控制。全部可用 parameters 在PostgreSQL文档中进行了详细描述。

警告

不支持将服务名称用于测试目的。这 may be implemented later

优化PostgreSQL配置

Django的数据库连接需要以下参数:

  • client_encoding'UTF8'

  • default_transaction_isolation'read committed' 默认情况下,或在连接选项中设置的值(见下文)。

  • timezone
    • 什么时候? USE_TZTrue'UTC' 默认情况下,或 TIME_ZONE 连接的值设置,

    • 什么时候? USE_TZFalse ,全球价值观 TIME_ZONE 设置。

如果这些参数已经有了正确的值,Django不会为每个新连接设置它们,这会稍微提高性能。您可以直接在中配置它们 postgresql.conf 或更方便每个数据库用户使用 ALTER ROLE .

没有这种优化,Django就可以正常工作,但是每个新连接都会执行一些额外的查询来设置这些参数。

隔离级别

就像PostgreSQL本身一样,Django默认为 READ COMMITTED isolation level . 如果您需要更高的隔离级别,例如 REPEATABLE READSERIALIZABLE 把它设置在 OPTIONS 数据库配置的一部分 DATABASES ::

from django.db.backends.postgresql.psycopg_any import IsolationLevel

DATABASES = {
    # ...
    "OPTIONS": {
        "isolation_level": IsolationLevel.SERIALIZABLE,
    },
}

备注

在较高的隔离级别下,应用程序应该准备好处理在序列化失败时引发的异常。此选项设计用于高级用途。

角色

如果需要为数据库连接使用与用于建立连接的角色不同的角色,请在 OPTIONS 中的数据库配置的一部分 DATABASES **

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # ...
        "OPTIONS": {
            "assume_role": "my_application_role",
        },
    },
}

Server-side parameters binding

使用 psycopg 3.1.8+,Django默认为 client-side binding cursors 。如果要使用 server-side binding 将其设置在 OPTIONS 中的数据库配置的一部分 DATABASES **

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # ...
        "OPTIONS": {
            "server_side_binding": True,
        },
    },
}

使用时将忽略此选项 psycopg2

指标 varchartext

指定时 db_index=True 在模型字段上,Django通常输出一个 CREATE INDEX 语句。但是,如果字段的数据库类型为 varchartext (例如,由 CharFieldFileFieldTextField ,然后django将创建一个使用适当的 PostgreSQL operator class 对于列。额外的索引对于正确执行使用 LIKE 其SQL中的运算符,与 containsstartswith 查找类型。

添加扩展的迁移操作

如果需要添加PostgreSQL扩展(如 hstorepostgis 等)使用迁移,使用 CreateExtension 操作。

伺服器端游标

使用时 QuerySet.iterator() ,Django打开了一个 server-side cursor 。默认情况下,PostgreSQL假定只提取游标查询结果的前10%。查询规划器计划查询所花费的时间更少,并开始更快地返回结果,但如果检索到超过10%的结果,则可能会降低性能。PostgreSQL对游标查询检索的行数的假设由 cursor_tuple_fraction 选择。

事务池和服务器端游标

在事务池模式下使用连接池(例如 PgBouncer )需要为该连接禁用服务器端游标。

服务器端游标是连接的本地游标,当 AUTOCOMMITTrue . 后续事务可能会尝试从服务器端光标获取更多结果。在事务池模式下,不能保证后续事务将使用相同的连接。如果使用不同的连接,则在事务引用服务器端光标时会引发错误,因为服务器端光标只能在创建它们的连接中访问。

一种解决方案是在 DATABASES 通过设置 DISABLE_SERVER_SIDE_CURSORSTrue .

为了从事务池模式的服务器端游标中获益,可以设置 another connection to the database 以便执行使用服务器端游标的查询。在会话池模式下,此连接需要直接连接到数据库或连接池。

另一种选择是包装每一个 QuerySetatomic() 阻止,因为它禁用 autocommit 在交易期间。这样,服务器端光标将只在事务期间活动。

手动指定自动递增主键的值

Django使用PostgreSQL的标识列来存储自动递增的主键。标识列中的值填充 sequence 它跟踪下一个可用值。手动为自动递增的字段赋值不会更新该字段的顺序,这可能会在以后导致冲突。例如:

>>> from django.contrib.auth.models import User
>>> User.objects.create(username="alice", pk=1)
<User: alice>
>>> # The sequence hasn't been updated; its next value is 1.
>>> User.objects.create(username="bob")
IntegrityError: duplicate key value violates unique constraint
"auth_user_pkey" DETAIL:  Key (id)=(1) already exists.

如果需要指定这样的值,请在之后重置序列,以避免重用表中已有的值。这个 sqlsequencereset 管理命令会生成执行此操作的SQL语句。

测试数据库模板

你可以使用 TEST['TEMPLATE'] 设置以指定 template (例如) 'template0' )从中创建测试数据库。

使用非持久设置加速测试执行

您可以通过 configuring PostgreSQL to be non-durable .

警告

这很危险:在服务器崩溃或断电的情况下,它会使数据库更容易受到数据丢失或损坏的影响。只在开发机器上使用它,在那里您可以轻松地恢复集群中所有数据库的全部内容。

MariaDB注释

Django支持MariaDB 10.5及更高版本。

要使用MariaDB,请使用MySQL后端,这是两者共享的。见 MySQL notes 了解更多详细信息。

MySQL注释

版本支持

Django支持MySQL 8.0.11及更高版本。

Django inspectdb 功能使用 information_schema 数据库,其中包含所有数据库架构的详细数据。

Django希望数据库支持Unicode(UTF-8编码),并将强制执行事务和引用完整性的任务委托给它。在使用myisam存储引擎时,必须意识到后两个引擎实际上不是由mysql强制执行的,请参见下一节。

存储引擎

MySQL有几个 storage engines . 可以在服务器配置中更改默认存储引擎。

MySQL的默认存储引擎是 InnoDB. 此引擎是完全事务性的,支持外键引用。这是推荐的选择。但是,innodb autoincrement计数器在MySQL重新启动时丢失,因为它不记得 AUTO_INCREMENT 值,而不是将其重新创建为“max(id)+1”。这可能会导致 AutoField 价值观。

主要缺点是 MyISAM 它不支持事务或强制使用外键约束。

MySQL DB API驱动程序

MySQL有两个驱动程序来实现中描述的python数据库API。 PEP 249

  • mysqlclient 是一名本地司机。它是 the recommended choice

  • MySQL Connector/Python 是来自Oracle的纯python驱动程序,它不需要mysql客户机库或标准库之外的任何python模块。

这些驱动程序是线程安全的,并提供连接池。

除了DBAPI驱动程序之外,Django还需要一个适配器来从其ORM访问数据库驱动程序。Django为mysqlclient提供了一个适配器,而mysql connector/python包括 its own .

MySQL客户端

姜戈要求 mysqlclient 1.4.3或更高版本。

mysql连接器/python

mysql connector/python可从 download page . Django适配器在1.1.x及更高版本中提供。它可能不支持Django的最新版本。

时区定义

如果你打算用 Django 的 timezone support 使用 mysql_tzinfo_to_sql 将时区表加载到MySQL数据库中。这只需要为您的MySQL服务器完成一次,而不是每个数据库。

正在创建数据库

你可以的 create your database 使用命令行工具和以下SQL:

CREATE DATABASE <dbname> CHARACTER SET utf8;

这样可以确保所有表和列在默认情况下都使用UTF-8。

排序规则设置

列的排序规则设置控制数据的排序顺序以及哪些字符串比较为相等。您可以指定 db_collation 参数设置列的排序规则名称 CharFieldTextField .

排序规则也可以在数据库范围内的每个表上设置。这是 documented thoroughly 在MySQL文档中。在这种情况下,必须通过直接操作数据库设置或表来设置排序规则。Django不提供API来更改它们。

默认情况下,对于utf-8数据库,mysql将使用 utf8_general_ci 校对。这将导致在 case-insensitive 态度。也就是说, "Fred""freD" 在数据库级别被认为是相等的。如果字段上有唯一约束,则尝试同时插入这两个约束是非法的。 "aa""AA" 在同一列中,因为它们与默认排序规则比较为相等(因此也不唯一)。如果要对特定列或表进行区分大小写的比较,请将该列或表更改为使用 utf8_bin 校对。

请注意,根据 MySQL Unicode Character Sets ,比较 utf8_general_ci 排序规则比 utf8_unicode_ci . 如果您的申请可以接受,您应该使用 utf8_general_ci 因为它更快。如果这是不可接受的(例如,如果您需要德语字典顺序),请使用 utf8_unicode_ci 因为它更准确。

警告

模型表单集以区分大小写的方式验证唯一字段。因此,当使用不区分大小写的排序规则时,具有唯一字段值(仅因大小写而不同)的Formset将通过验证,但在调用 save() ,一个 IntegrityError 将被提升。

连接到数据库

参考 settings documentation .

连接设置的使用顺序如下:

  1. OPTIONS .

  2. NAME, USER, PASSWORD, HOST, PORT

  3. MySQL选项文件。

换句话说,如果在 OPTIONS ,这将优先于 NAME ,它将覆盖 MySQL option file .

下面是一个使用mysql选项文件的配置示例:

# settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "OPTIONS": {
            "read_default_file": "/path/to/my.cnf",
        },
    }
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

其他几个 MySQLdb connection options 可能有用,例如 sslinit_commandsql_mode .

设置 sql_mode

的缺省值 sql_mode 选项包含 STRICT_TRANS_TABLES 。当数据在插入时被截断时,该选项会将警告升级为错误,因此Django强烈建议激活 strict mode 对于MySQL,为了防止数据丢失( STRICT_TRANS_TABLESSTRICT_ALL_TABLES )。

如果需要自定义SQL模式,可以设置 sql_mode 变量和其他MySQL选项一样:要么在配置文件中,要么在条目中 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"OPTIONS 数据库配置的一部分 DATABASES .

隔离级别

在运行并发加载时,来自不同会话(例如,处理不同请求的独立线程)的数据库事务可能会相互交互。这些交互受每个会话的影响 transaction isolation level . 可以使用 'isolation_level' 进入 OPTIONS 数据库配置的一部分 DATABASES . 此项的有效值是四个标准隔离级别:

  • 'read uncommitted'

  • 'read committed'

  • 'repeatable read'

  • 'serializable'

None 使用服务器配置的隔离级别。但是,django最适合并默认为read committed,而不是mysql的默认可重复读取。通过可重复读取可能会丢失数据。特别是,您可能会看到 get_or_create() 将提高 IntegrityError 但是这个物体不会出现在后面 get() 打电话。

创建表格

当Django生成模式时,它没有指定存储引擎,因此将使用数据库服务器配置的默认存储引擎创建表。最简单的解决方案是将数据库服务器的默认存储引擎设置为所需的引擎。

如果您使用的是托管服务,并且无法更改服务器的默认存储引擎,那么您有几个选项。

  • 在创建表之后,执行 ALTER TABLE 将表转换为新存储引擎(如InnoDB)的语句:

    ALTER TABLE <tablename> ENGINE=INNODB;
    

    如果你有很多表格,这会很乏味。

  • 另一种选择是使用 init_command 创建表之前mysqldb的选项:

    "OPTIONS": {
        "init_command": "SET default_storage_engine=INNODB",
    }
    

    这将在连接到数据库时设置默认的存储引擎。创建表后,应删除此选项,因为它将只在表创建期间需要的查询添加到每个数据库连接中。

表名

known issues 甚至在MySQL的最新版本中,当某些SQL语句在某些条件下执行时,也可能导致表名的情况发生更改。建议您尽可能使用小写表名,以避免此行为可能引起的任何问题。Django在从模型自动生成表名时使用小写表名,因此,如果要通过 db_table 参数。

保存点

django orm和mysql(使用innodb时 storage engine )支持数据库 savepoints .

如果使用myisam存储引擎,请注意,如果尝试使用 savepoint-related methods of the transactions API . 原因是,检测MySQL数据库/表的存储引擎是一项昂贵的操作,因此,根据检测结果,在no op中动态转换这些方法是不值得的。

特定字段注释

字符字段

与一起存储的任何字段 VARCHAR 列类型可能具有 max_length 如果正在使用,则限制为255个字符 unique=True 为了田野。这种影响 CharFieldSlugField . 见 the MySQL documentation 了解更多详细信息。

TextField 局限性

MySQL只能索引 BLOBTEXT 列。自从 TextField 没有定义的长度,不能将其标记为 unique=True . MySQL将报告:“在没有密钥长度的密钥规范中使用了blob/text列'<db_column>”。

时间和日期时间字段的分数秒支持

MySQL可以存储小数秒,前提是列定义中包含一个小数表示(例如。 DATETIME(6)

如果数据库服务器支持,Django将不会升级现有列以包含小数秒。如果要在现有数据库上启用它们,则由您决定是否手动更新目标数据库上的列,方法是执行如下命令:

ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)

或使用 RunSQL A中的操作 data migration .

TIMESTAMP

如果使用的是包含 TIMESTAMP 列,必须设置 USE_TZ = False 以避免数据损坏。 inspectdb 将这些列映射到 DateTimeField 如果启用时区支持,MySQL和Django都将尝试将值从UTC转换为本地时间。

行锁定方式 QuerySet.select_for_update()

MySQL和MariaDB不支持 SELECT ... FOR UPDATE 语句。如果 select_for_update() 与不受支持的选项一起使用,则 NotSupportedError 提高了。

期权

玛丽亚德

MySQL

SKIP LOCKED

X(≥10.6)

X

NOWAIT

X

X

OF

X

NO KEY

使用时 select_for_update() 在MySQL上,请确保至少根据Unique约束中包含的一组字段或仅根据索引覆盖的字段来筛选查询集。否则,将在事务持续时间内获取整个表上的独占写锁。

自动排版可能导致意外结果

当对字符串类型执行查询时,但使用整数值时,MySQL将强制表中所有值的类型为整数,然后再执行比较。如果表中包含值 'abc''def' 然后你查询 WHERE mycolumn=0 ,两行都匹配。同样地, WHERE mycolumn=1 将匹配值 'abc1' . 因此,django中包含的字符串类型字段在查询中使用该值之前,将始终将该值强制转换为字符串。

如果实现从继承的自定义模型字段 Field 直接,是压倒性的 get_prep_value() 或使用 RawSQLextra()raw() ,您应该确保执行适当的类型转换。

SQLite注释

Django支持SQLite 3.27.0及更高版本。

SQLite 为主要是只读的或需要更小的安装占用空间的应用程序提供了一个极好的开发替代方案。但是,与所有数据库服务器一样,您应该注意到特定于sqlite的一些差异。

子串匹配和区分大小写

对于所有的sqlite版本,在尝试匹配某些类型的字符串时,都有一些稍微有点违反直觉的行为。当使用 iexactcontains 查询集中的筛选器。这种行为分为两种情况:

1。对于子字符串匹配,所有匹配都是不敏感的。这是一个过滤器,例如 filter(name__contains="aa") 将匹配的名称 "Aabb" .

2。对于包含ASCII范围之外的字符的字符串,即使将不区分大小写的选项传递到查询中,也会区分大小写执行所有精确的字符串匹配。所以 iexact 筛选器的行为将与 exact 在这些情况下过滤。

一些可能的解决办法是 documented at sqlite.org 但是Django中的默认sqlite后端没有使用它们,因为合并它们将非常困难。因此,Django公开默认的sqlite行为,在执行不区分大小写或子字符串筛选时,应该注意这一点。

十进制处理

SQLite没有真正的decimal内部类型。十进制值在内部转换为 REAL 数据类型(8字节IEEE浮点数),如 `SQLite datatypes documentation`_ _,因此它们不支持正确舍入的十进制浮点运算。

“数据库被锁定”错误

sqlite是一个轻量级数据库,因此不能支持高级别的并发性。 OperationalError: database is locked 错误表明应用程序的并发性比 sqlite 可以在默认配置中处理。此错误意味着一个线程或进程在数据库连接上具有独占锁,另一个线程在等待释放锁时超时。

python的sqlite包装器有一个默认超时值,该值确定允许第二个线程在锁超时之前等待多长时间,并引发 OperationalError: database is locked 错误。

如果出现此错误,可以通过以下方法解决:

  • 切换到另一个数据库后端。在某一点上,对于真实的应用程序来说,sqlite变得过于“lite”,并且这些并发错误表明您已经达到了这个程度。

  • 重写代码以减少并发性并确保数据库事务是短期的。

  • 通过设置 timeout 数据库选项:

    "OPTIONS": {
        # ...
        "timeout": 20,
        # ...
    }
    

    这将使SQLite在抛出“databaseislocked”错误之前等待一段时间;它不会真正解决这些错误。

QuerySet.select_for_update() 不支持

sqlite不支持 SELECT ... FOR UPDATE 语法。叫它不会有任何效果。

使用时隔离 QuerySet.iterator()

中描述了一些特殊注意事项。 Isolation In SQLite 在对表进行迭代时使用 QuerySet.iterator() . 如果在循环中添加、更改或删除了一行,那么该行可能会出现,也可能不会出现,或者可能会出现两次,出现在从迭代器获取的后续结果中。您的代码必须处理这个问题。

在SQLite上启用JSON1扩展

使用 JSONField 在SQLite上,您需要启用 JSON1 extension 关于Python的 sqlite3 类库。如果安装时未启用扩展,则系统错误 (fields.E180 )将被提高。

要启用JSON1扩展,可以按照 the wiki page .

备注

默认情况下,在SQLite 3.38+上启用JSON1扩展。

甲骨文笔记

Django支持 Oracle Database Server 版本19c及更高版本。1.3.2版或更高版本的 oracledb 需要使用Python驱动程序。

自 5.0 版本弃用: 支持 cx_Oracle 已弃用。

为了 python manage.py migrate 命令要运行,您的Oracle数据库用户必须具有运行以下命令的权限:

  • 创建表

  • 创建序列

  • 创建过程

  • 创建触发器

要运行项目的测试套件,用户通常需要这些 额外的 特权:

  • 创建用户

  • 更改用户

  • 放弃用户

  • 创建表空间

  • 删除表空间

  • 使用管理选项创建会话

  • 使用管理选项创建表

  • 使用管理选项创建序列

  • 使用管理选项创建过程

  • 使用管理选项创建触发器

RESOURCE 角色具有必需的 CREATE TABLECREATE SEQUENCECREATE PROCEDURECREATE TRIGGER 权限和授予的用户 RESOURCE WITH ADMIN OPTION 可以授予 RESOURCE ,这样的用户不能授予个人特权(例如 CREATE TABLERESOURCE WITH ADMIN OPTION 通常不足以运行测试。

一些测试套件还创建视图或物化视图;要运行这些视图,用户还需要 CREATE VIEW WITH ADMIN OPTIONCREATE MATERIALIZED VIEW WITH ADMIN OPTION 特权。特别是,这对于Django自己的测试套件是必需的。

所有这些特权都包含在dba角色中,该角色适用于私有开发人员的数据库。

Oracle数据库后端使用 SYS.DBMS_LOBSYS.DBMS_RANDOM 程序包,因此您的用户需要对其具有执行权限。默认情况下,所有用户都可以访问它,但如果不是,则需要授予如下权限:

GRANT EXECUTE ON SYS.DBMS_LOB TO user;
GRANT EXECUTE ON SYS.DBMS_RANDOM TO user;

连接到数据库

要使用Oracle数据库的服务名称进行连接,请 settings.py 文件应如下所示:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        "NAME": "xe",
        "USER": "a_user",
        "PASSWORD": "a_password",
        "HOST": "",
        "PORT": "",
    }
}

在这种情况下,你应该同时离开 HOSTPORT 空的。但是,如果不使用 tnsnames.ora 文件或类似的命名方法,并希望使用sid(本例中的“xe”)进行连接,然后填写这两者 HOSTPORT 像这样::

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        "NAME": "xe",
        "USER": "a_user",
        "PASSWORD": "a_password",
        "HOST": "dbprod01ned.mycompany.com",
        "PORT": "1540",
    }
}

你应该两者都提供 HOSTPORT 或将两者都保留为空字符串。Django将根据选择使用不同的连接描述符。

完整的DSN和轻松的连接

完整的DSN或轻松连接字符串可用于 NAME 如果两者 HOSTPORT 是空的。使用rac或可插拔数据库时,如果没有 tnsnames.ora 例如。

轻松连接字符串示例:

"NAME": "localhost:1521/orclpdb1"

完整DSN字符串示例:

"NAME": (
    "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
    "(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)

线程选项

如果计划在多线程环境中运行Django(例如,在任何现代操作系统上使用默认MPM模块的Apache),那么 must 设置 threaded Oracle数据库配置选项 True ::

"OPTIONS": {
    "threaded": True,
}

不这样做可能会导致崩溃和其他奇怪的行为。

插入…回归

默认情况下,Oracle后端使用 RETURNING INTO 子句有效地检索 AutoField 插入新行时。这种行为可能导致 DatabaseError 在某些不寻常的设置中,例如当插入到远程表或具有 INSTEAD OF 触发。这个 RETURNING INTO 通过设置 use_returning_into 数据库配置选项 False ::

"OPTIONS": {
    "use_returning_into": False,
}

在这种情况下,Oracle后端将使用单独的 SELECT 要检索的查询 AutoField 价值观。

命名问题

Oracle规定名称长度限制为30个字符。为了适应这种情况,后端将截断数据库标识符以适应,将截断名称的最后四个字符替换为可重复的MD5哈希值。此外,后端将数据库标识符全部转换为大写。

为了防止这些转换(通常只有在处理遗留数据库或访问属于其他用户的表时才需要这样做),请使用带引号的名称作为 db_table ::

class LegacyModel(models.Model):
    class Meta:
        db_table = '"name_left_in_lowercase"'


class ForeignModel(models.Model):
    class Meta:
        db_table = '"OTHER_USER"."NAME_ONLY_SEEMS_OVER_30"'

带引号的名称也可以与Django支持的其他数据库后端一起使用;但是,除了Oracle之外,这些引号没有任何效果。

运行时 migrate ,一个 ORA-06552 如果某些Oracle关键字用作模型字段的名称或 db_column 选择权。Django引用查询中使用的所有标识符,以避免大多数此类问题,但当Oracle数据类型用作列名时,仍然可能发生此错误。尤其要注意避免使用这些名称 datetimestampnumberfloat 作为字段名。

空字符串

Django通常喜欢使用空字符串 ('' )而不是 NULL 但甲骨文对这两者的处理是相同的。为了解决这个问题,Oracle后端会忽略 null 选项,用于将空字符串作为可能值并生成DDL的字段 null=True . 从数据库提取时,假定 NULL 其中一个字段中的值实际上意味着空字符串,数据将被静默转换以反映此假设。

TextField 局限性

Oracle后端存储 TextFields 作为 NCLOB 柱。Oracle通常会对此类LOB列的使用施加一些限制:

  • LOB列不能用作主键。

  • 在索引中不能使用LOB列。

  • LOB列不能用于 SELECT DISTINCT 名单。这意味着尝试使用 QuerySet.distinct 模型上的方法,其中包括 TextField 列将导致 ORA-00932 对Oracle运行时出错。作为解决方案,使用 QuerySet.defer 方法与 distinct() 预防 TextField 列中包含的列 SELECT DISTINCT 名单。

子类化内置数据库后端

Django带有内置的数据库后端。您可以将现有数据库后端子类化以修改其行为、特性或配置。

例如,假设您需要更改单个数据库功能。首先,您必须创建一个具有 base 模块在里面。例如:

mysite/
    ...
    mydbengine/
        __init__.py
        base.py

这个 base.py 模块必须包含名为 DatabaseWrapper 它从 django.db.backends 模块。下面是一个PostgreSQL引擎子类化以更改功能类的示例 allows_group_by_selected_pks_on_model

mysite/mydbengine/base.py
from django.db.backends.postgresql import base, features


class DatabaseFeatures(features.DatabaseFeatures):
    def allows_group_by_selected_pks_on_model(self, model):
        return True


class DatabaseWrapper(base.DatabaseWrapper):
    features_class = DatabaseFeatures

最后,必须指定 DATABASE-ENGINE 在你 settings.py 文件::

DATABASES = {
    "default": {
        "ENGINE": "mydbengine",
        # ...
    },
}

您可以通过查看 django/db/backends .

使用第三方数据库后端

除了官方支持的数据库外,还有第三方提供的后端,允许您与Django一起使用其他数据库:

这些非官方后端支持的Django版本和ORM功能差异很大。有关这些非官方后端的特定功能的查询,以及任何支持查询,应指向每个第三方项目提供的支持渠道。