Skip to main content

数据库

Django尝试在所有数据库后端支持尽可能多的功能。然而,并不是所有的数据库后端都是一样的,我们不得不在设计决策上支持哪些功能以及我们可以安全地做出哪些假设。

此文件描述了一些可能与Django使用相关的功能。当然,它不是为了替代服务器特定的文档或参考手册。

一般注意事项

持久连接

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

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

连接管理

Django在首次进行数据库查询时打开与数据库的连接。它保持此连接打开并在后续请求中重复使用。 Django在超过由 CONN_MAX_AGE 定义的最大年龄时,或者当它不再可用时关闭连接。

详细来说,当Django需要一个连接,并且没有一个连接时,它会自动打开一个连接,因为这是第一个连接,或者是因为前一个连接已经关闭。

在每个请求的开始,Django关闭连接,如果它已达到其最大年龄。如果您的数据库在一段时间后终止空闲连接,您应该将 CONN_MAX_AGE 设置为较低的值,以便Django不会尝试使用已由数据库服务器终止的连接。 (此问题可能只会影响非常低的流量网站。)

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

注意

由于每个线程都维护自己的连接,因此您的数据库必须至少支持与工作线程一样多的并发连接。

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

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

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

编码

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

PostgreSQL注释

Django支持PostgreSQL 9.2及更高版本。它需要使用 psycopg2 2.4.5或更高版本(如果要使用 django.contrib.postgres,则为2.5+)。

PostgreSQL连接设置

有关详细信息,请参阅 HOST

优化PostgreSQL的配置

Django需要以下参数用于其数据库连接:

  • client_encoding'UTF8'

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

  • timezoneUSE_TZTrue 时的 'UTC',否则为 TIME_ZONE

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

Django将工作正常没有这种优化,但每个新的连接将做一些额外的查询设置这些参数。

隔离级别

像PostgreSQL本身一样,Django默认为 READ COMMITTED isolation level。如果需要更高的隔离级别(如 REPEATABLE READSERIALIZABLE),请将其设置在 DATABASES 中数据库配置的 OPTIONS 部分中:

import psycopg2.extensions

DATABASES = {
    # ...
    'OPTIONS': {
        'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
    },
}

注解

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

varchartext 列的索引

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

添加扩展的迁移操作

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

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

您可以通过 将PostgreSQL配置为非持久性 加快测试执行时间。

警告

这是危险的:它将使您的数据库更容易受到数据丢失或损坏的情况下服务器崩溃或掉电。只能在开发机器上使用它,您可以轻松地还原集群中所有数据库的全部内容。

MySQL注释

版本支持

Django支持MySQL 5.5及更高版本。

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

Django希望数据库支持Unicode(UTF-8编码),并委托它来执行事务和引用完整性的任务。重要的是要知道,当使用MyISAM存储引擎时,后两个实际上并不由MySQL执行,请参阅下一节。

存储引擎

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

直到MySQL 5.5.4,默认引擎是 MyISAM [1]。 MyISAM的主要缺点是它不支持事务或强制外键约束。在更好的方面,它是唯一支持全文索引和搜索直到MySQL 5.6.4的引擎。

从MySQL 5.5.5开始,默认存储引擎是 InnoDB。这个引擎是完全事务性的,并支持外键引用。这可能是最好的选择。但是,请注意,InnoDB自动增量计数器在MySQL重新启动时会丢失,因为它不记住 AUTO_INCREMENT 值,而是将其重新创建为“max(id)+1”。这可能导致 AutoField 值的无意重用。

如果将现有项目升级到MySQL 5.5.5并随后添加一些表,请确保您的表使用相同的存储引擎(即MyISAM vs. InnoDB)。具体来说,如果表之间具有 ForeignKey 的表使用不同的存储引擎,则在运行 migrate 时可能会看到类似以下的错误:

_mysql_exceptions.OperationalError: (
    1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
)
[1]

除非你的MySQL包的包装器改变了。我们已经报告,Windows社区服务器安装程序设置InnoDB作为默认存储引擎,例如。

MySQL DB API驱动程序

Python数据库API在 PEP 249 中描述。 MySQL有三个突出的驱动程序实现这个API:

  • MySQLdb 是一个本地驱动程序,由Andy Dustman开发和支持十多年。

  • mysqlclientMySQLdb 的一个分支,它特别支持Python 3,可以作为MySQLdb的替代。在写这篇文章的时候,这是使用MySQL与Django的 推荐选择

  • MySQL Connector/Python 是Oracle的纯Python驱动程序,不需要MySQL客户端库或标准库外的任何Python模块。

所有这些驱动程序是线程安全的,并提供连接池。 MySQLdb 是目前唯一不支持Python 3的。

除了DB API驱动程序,Django需要一个适配器来从其ORM访问数据库驱动程序。 Django为MySQLdb/mysqlclient提供了一个适配器,而MySQL Connector/Python包括 its own

MySQLdb

Django需要MySQLdb版本1.2.1p2或更高版本。

在撰写本文时,最新版本的MySQLdb(1.2.5)不支持Python 3.为了在Python 3下使用MySQLdb,您必须安装 mysqlclient

注解

MySQLdb将日期字符串转换为datetime对象的方式有一些已知问题。具体来说,值为 0000-00-00 的日期字符串对MySQL有效,但将通过MySQLdb转换为 None

这意味着,在对具有 0000-00-00 值的行使用 loaddatadumpdata 时应该小心,因为它们将被转换为 None

mysqlclient

Django需要 mysqlclient 1.3.3或更高版本。注意,不支持Python 3.2。除了Python 3.3+支持,mysqlclient应该主要与MySQLDB行为相同。

MySQL连接器/Python

MySQL连接器/Python可从 download page 获得。 Django适配器的版本为1.1.X及更高版本。它可能不支持最新版本的Django。

时区定义

如果计划使用Django的 时区支持,请使用 mysql_tzinfo_to_sql 将时区表加载到MySQL数据库中。这需要为您的MySQL服务器只做一次,而不是每个数据库。

创建数据库

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

CREATE DATABASE <dbname> CHARACTER SET utf8;

这确保所有表和列默认使用UTF-8。

整理设置

列的排序规则设置控制数据排序的顺序以及字符串比较为相等的字符串。它可以在数据库范围级别以及每个表和每个列设置。这是MySQL文档中的 documented thoroughly。在所有情况下,您都可以通过直接操作数据库表来设置归类; Django不提供在模型定义上设置此方法。

默认情况下,对于UTF-8数据库,MySQL将使用 utf8_general_ci 归类。这导致以 case-insensitive 方式进行所有字符串等式比较。也就是说,"Fred""freD" 在数据库级别被认为是相等的。如果对字段有一个唯一约束,那么尝试将 "aa""AA" 插入同一列是非法的,因为它们与默认排序规则相等(因此,非唯一)。

在许多情况下,这个默认值不会是一个问题。但是,如果您确实希望对特定列或表进行区分大小写比较,则可以更改列或表以使用 utf8_bin 归类。在这种情况下要注意的主要事情是,如果您使用MySQLdb 1.2.2,Django中的数据库后端将返回从数据库接收的任何字符字段的bytestrings(而不是unicode字符串)。这是从Django的 always 返回unicode字符串的正常做法的一个强烈的变化。如果您将表配置为使用 utf8_bin 归类,那么由您,开发人员来决定您将接收bytestrings的事实。 Django本身应该能够顺利地使用这样的列(除了下面描述的 contrib.sessions Sessioncontrib.admin LogEntry 表),但是如果真的想使用一致的数据,你的代码必须准备调用 django.utils.encoding.smart_text() - Django不会这样做(数据库后端层和模型填充层在内部是分离的,所以数据库层不知道它需要在这个特殊情况下进行此转换)。

如果你使用MySQLdb 1.2.1p2,Django的标准 CharField 类将返回unicode字符串,即使有 utf8_bin 排序规则。但是,TextField 字段将作为 array.array 实例返回(从Python的标准 array 模块)。有没有很多Django可以做到的,因为,再次,从数据库读入数据时,进行必要的转换所需的信息不可用。这个问题是 fixed in MySQLdb 1.2.2,所以如果你想使用 TextFieldutf8_bin 排序规则,升级到版本1.2.2,然后处理如上所述的bytestrings(这不应该太难)是推荐的解决方案。

如果你决定对MySQLdb 1.2.1p2或1.2.2的一些表使用 utf8_bin 排序规则,你仍然应该使用 django.contrib.sessions.models.Session 表(通常称为 django_session)和 django.contrib.admin.models.LogEntry 表(通常称为 django_admin_log)的 utf8_general_ci (默认)排序规则, 。这是在内部使用 TextField 的两个标准表。

请注意,根据 MySQL Unicode Character Setsutf8_general_ci 比对的比较比 utf8_unicode_ci 的比较更快,但略差。如果这是你的应用程序可接受的,你应该使用 utf8_general_ci,因为它更快。如果这是不可接受的(例如,如果您需要德语字典顺序),请使用 utf8_unicode_ci,因为它更准确。

警告

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

连接到数据库

请参阅 设置文档

连接设置按此顺序使用:

  1. OPTIONS

  2. NAMEUSERPASSWORDHOSTPORT

  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连接选项可能很有用,例如 sslinit_commandsql_mode。有关详细信息,请咨询 MySQLdb documentation

设置 sql_mode

从MySQL 5.7起,以及对MySQL 5.6的全新安装,sql_mode 选项的默认值包含 STRICT_TRANS_TABLES。当插入时截断数据时,该选项将警告升级为错误,因此Django强烈建议激活用于MySQL的 strict mode 以防止数据丢失(STRICT_TRANS_TABLESSTRICT_ALL_TABLES)。

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

创建表

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

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

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

    ALTER TABLE <tablename> ENGINE=INNODB;
    

    如果你有很多表,这可能是乏味的。

  • 另一个选项是在创建表之前对MySQLdb使用 init_command 选项:

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

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

表名

即使在最新版本的MySQL中也有 known issues,在某些条件下执行某些SQL语句时,可能会导致更改表名。如果可能,建议您使用小写表名,以避免此行为可能导致的任何问题。 Django在从模型中自动生成表名时使用小写表名,因此如果您通过 db_table 参数覆盖表名,那么这主要是一个考虑因素。

保存点

Django ORM和MySQL(当使用InnoDB 存储引擎 时)支持数据库 保存点

如果您使用MyISAM存储引擎,请注意,如果您尝试使用 事务API的保存点相关方法,您将收到数据库生成的错误。这样做的原因是检测MySQL数据库/表的存储引擎是一种昂贵的操作,因此决定在这种检测的结果中基于无操作来动态地转换这些方法是不值得的。

有关特定字段的说明

字符字段

如果使用 unique=True 作为字段,则使用 VARCHAR 列类型存储的任何字段的 max_length 限制为255个字符。这影响 CharFieldSlugFieldCommaSeparatedIntegerField

TextField 限制

MySQL只能索引 BLOBTEXT 列的前N个字符。由于 TextField 没有定义的长度,您不能将其标记为 unique=True。 MySQL将报告:“BLOB/TEXT列’<db_column>’在密钥规范中使用而不包含密钥长度”。

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

MySQL 5.6.4和更高版本可以存储分数秒,只要列定义包括分数指示(例如 DATETIME(6))。早期版本根本不支持它们。此外,MySQLdb早于1.2.5的版本具有 a bug,这也防止与MySQL使用小数秒。

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

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

或在 数据迁移 中使用 RunSQL 操作。

TIMESTAMP

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

行锁定与 QuerySet.select_for_update()

MySQL不支持 SELECT ... FOR UPDATE 语句的 NOWAIT 选项。如果 select_for_update()nowait=True 一起使用,则将产生 DatabaseError

自动转印可能会导致意外的结果

当对字符串类型执行查询但是使用整数值时,MySQL将在执行比较之前将表中所有值的类型强制为整数。如果您的表包含值 'abc''def' 并且您查询 WHERE mycolumn=0,则两行都将匹配。类似地,WHERE mycolumn=1 将匹配值 'abc1'。因此,Django中包含的字符串类型字段在将其用于查询之前,将始终将该值转换为字符串。

如果实现直接继承 Field 的自定义模型字段,覆盖 get_prep_value(),或使用 RawSQLextra()raw(),则应确保执行适当的类型转换。

SQLite注释

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

子字符串匹配和区分大小写

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

1. For substring matching, all matches are done case-insensitively. That is a filter such as filter(name__contains="aa") will match a name of "Aabb".

2. For strings containing characters outside the ASCII range, all exact string matches are performed case-sensitively, even when the case-insensitive options are passed into the query. So the iexact filter will behave exactly the same as the exact filter in these cases.

一些可能的解决方法是 documented at sqlite.org,但它们不被Django中的默认SQLite后端使用,因为合并它们将是相当困难的。因此,Django暴露了默认的SQLite行为,在进行不区分大小写或子串过滤时,您应该注意到这一点。

老SQLite和 CASE 表达式

SQLite 3.6.23.1和更旧版本包含一个错误,当 handling query parameters 在包含 ELSE 和算术的 CASE 表达式中。

SQLite 3.6.23.1是在2010年3月发布的,大多数不同平台的最新二进制发行版都包括较新版本的SQLite,除了适用于Windows的Python 2.7安装程序之外。

在撰写本文时,最新版本的Windows - Python 2.7.10 - 包括SQLite 3.6.21。您可以安装 pysqlite2 或用 https://www.sqlite.org/ 的较新版本替换 sqlite3.dll (默认安装在 C:\Python27\DLLs 中)以解决此问题。

使用较新版本的SQLite DB-API 2.0驱动程序

Django将使用一个 pysqlite2 模块,优先于随着Python标准库提供的 sqlite3,如果它发现一个可用。

这提供了将DB-API 2.0接口或SQLite 3本身升级到比特定Python二进制分发版本更新的版本的能力,如果需要的话。

“数据库被锁定”错误

SQLite是一个轻量级的数据库,因此不能支持高水平的并发性。 OperationalError: database is locked 错误指示您的应用程序遇到的并发性比 sqlite 在默认配置中可以处理的更多。这个错误意味着一个线程或进程对数据库连接有一个独占锁,另一个线程超时等待锁被释放。

Python SQLite包装器有一个默认超时值,它决定第二个线程在超时之前允许等待锁的时间,并引发 OperationalError: database is locked 错误。

如果您收到此错误,您可以通过以下方式解决:

  • 切换到另一个数据库后端。在某一点上,SQLite对于现实世界的应用程序变得过于“轻”,这些并发错误表明你已经达到了这一点。

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

  • 通过设置 timeout 数据库选项来增加默认超时值:

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

    这将简单地使SQLite等待一段时间,然后抛出“数据库被锁定”的错误;它不会真正做任何事情来解决它们。

不支持 QuerySet.select_for_update()

SQLite不支持 SELECT ... FOR UPDATE 语法。调用它将没有效果。

不支持原始查询中的“pyformat”参数样式

对于大多数后端,原始查询(Manager.raw()cursor.execute())可以使用“pyformat”参数样式,其中查询中的占位符以 '%(name)s' 的形式给出,参数作为字典而不是列表传递。 SQLite不支持这个。

Oracle注释

Django支持 Oracle Database Server 版本11.2和更高版本。需要 cx_Oracle Python驱动程序的4.3.1或更高版本,但我们建议使用5.1.3或更高版本,因为这些版本支持Python 3。

注意,由于 cx_Oracle 5.0中的Unicode损坏错误,该版本的驱动程序应该与Django一起使用 cx_Oracle 5.0.1解决了这个问题,所以如果你想使用更新的 cx_Oracle,请使用5.0.1版本。

cx_Oracle 5.0.1或更高版本可以选择使用 WITH_UNICODE 环境变量编译。这是建议,但不是必需的。

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

  • 创建表

  • 创建序列

  • 创建过程

  • 创建触发器

要运行项目的测试套件,用户通常需要以下 additional 权限:

  • 创建用户

  • ALTER USER

  • 删除用户

  • 创建TABLESPACE

  • DROP TABLESPACE

  • 创建具有管理选项的会话

  • 创建表与管理选项

  • 使用管理选项创建序列

  • 使用管理选项创建过程

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

请注意,尽管RESOURCE角色具有必需的CREATE TABLE,CREATE SEQUENCE,CREATE PROCEDURE和CREATE TRIGGER权限,并且授予RESOURCE WITH ADMIN OPTION的用户可以授予RESOURCE,但此类用户无法授予单个权限(例如CREATE TABLE)因此RESOURCE WITH ADMIN OPTION通常不足以运行测试。

一些测试套件也创建视图;要运行这些,用户还需要具有CREATE 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将根据这个选择使用不同的连接描述符。

螺纹选项

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

'OPTIONS': {
    'threaded': True,
},

否则可能会导致崩溃和其他异常行为。

INSERT ... RETURNING INTO

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

'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 时,如果将某些Oracle关键字用作模型字段的名称或 db_column 选项的值,则可能会遇到 ORA-06552 错误。 Django引用查询中使用的所有标识符来防止大多数这样的问题,但是当Oracle数据类型用作列名时,仍然会发生此错误。特别地,注意避免使用名称 datetimestampnumberfloat 作为字段名称。

NULL和空字符串

Django通常更喜欢使用空字符串(’‘),而不是NULL,但Oracle对待它们是相同的。为了解决这个问题,Oracle后端会忽略在空字符串作为可能值的字段上显式 null 选项,并生成DDL,如同 null=True。当从数据库中获取时,假设这些字段之一中的 NULL 值实际上意味着空字符串,并且数据被静默地转换以反映这个假设。

TextField 限制

Oracle后端将 TextFields 存储为 NCLOB 列。 Oracle对这种LOB列的使用有一些限制:

  • LOB列不能用作主键。

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

  • LOB列不能在 SELECT DISTINCT 列表中使用。这意味着在包含 TextField 列的模型上尝试使用 QuerySet.distinct 方法将导致针对Oracle运行时出现 ORA-00932 错误。作为解决方法,使用 QuerySet.defer 方法与 distinct() 结合,以防止 TextField 列包含在 SELECT DISTINCT 列表中。

使用第三方数据库后端

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

这些非官方后端支持的Django版本和ORM功能差别很大。有关这些非正式后端的具体功能的查询以及任何支持查询,都应转到每个第三方项目提供的支持渠道。