数据库

Django试图尽可能多的支持所有数据库后端的特性。 然而,并不是所有数据库都一样,所以我们必须在支持哪些特性和做出哪些安全的假定上做出设计决策。

本文描述了一些Django使用数据库的有关特性。 当然,它并不想成为各服务器指定的文档或者参考手册的替代品。

一般说明

持久连接

持续连接的特性避免了每一次重新建立与数据库的连接的请求中所增加的压力。 这些连接通过 CONN_MAX_AGE 参数(控制一个连接的最长存活时间)来控制。 它可以被单独的设置在每一个数据库中。

参数的默认值为 0 ,对每次请求结束时终止数据库连接的历史行为提供保护。 当启用持续连接时,设置 CONN_MAX_AGE 的值(正数,单位为秒)为每个连接的最大存活时间。 对于无限制的连接,请设置为 None

连接管理

Django在它第一次建立数据库查询的时候打开与数据库的连接。 它保持着连接的通畅使得在随后的请求中可以再利用。 一旦这个连接超过参数 CONN_MAX_AGE 的最长存活时间的限制或者不能更长久的存活时,Django就会终止连接。

详细地说,当Django需要的时或者当前不存在数据库连接时,它会自动的与数据库之间建立连接————要么是因为这是第一次连接,要么是因为先前连接被关闭。

在每个请求开始时后,如果连接到了设置的最长存活时间时,Django就会关闭它。 如果你的数据库在之后一段时间终止了闲置的连接,你应该设置CONN_MAX_AGE 为一个更低的值,以至于Django不会尝试去连接数据库服务器上已经终止的连接。 (这个问题可能仅仅影响流量比较低的站点。)

在每个请求结束,如果它已经到达了最长存活时间或者它处在一个不可恢复的错误状态时,Django就会关闭连接。 在处理请求中如果有任何数据库错误产生,Django就会检查是否连接仍然工作,不工作就关闭它。 因此,数据库错误最多影响一个请求;如果连接变得不可用,下一个请求将获得新的连接。

警告¶ T0>

因为每个线程都保持着自己的连接,你的数据库至少必须在你的工作线程中支持尽可能多的并发线程。

有的时候数据库并不会在你的视图中有太多的访问,例如,因为数据库是一个外部系统,或者因为缓存的作用。 在这种情况下,你应该设置CONN_MAX_AGE为一个低的值或者为0,因为这对保持一个连接并没有意义,而且连接不太可能被重复调用。 这会有助于保持数据库的并发性连接数为一个小的值。

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

当Django建立与数据库的连接时,它会设置相应的参数,这取决于后台的使用情况。 如果你启用了持续性连接,那么程序将不再重复每个请求。 如果你修改了参数,例如连接的隔离级别或者是时区,你也应该恢复Django原有的默认值在每个请求结束时,强制使用一个合适的值在每个请求开始时,或者禁用持续性连接。

编码¶ T0>

Django假定所有的数据库使用UTF-8编码。 使用其他的编码有可能会导致不可预知的行为发生,例如在Django中你的数据库里有效的数据可能会出现“value too long”的错误。 在下面的信息中你可以查看数据库的具体说明来正确的设置你的数据库。

PostgreSQL注释

Django支持PostgreSQL 9.3及更高版本。 psycopg2需要2.5.4或更高版本,尽管推荐使用最新版本。

PostgreSQL连接设置

参考HOST来了解详细信息。

优化PostgreSQL的配置

Django规定它的数据库连接需要下列参数:

  • client_encoding'UTF8'
  • default_transaction_isolation: 'read committed'为默认值,或者是连接选项中设置的值(参见下文),
  • timezone'UTC'USE_TZTrue时,TIME_ZONE的值。

如果这些参数已经有了正确的值,Django将不会为每一个新的连接设置它们,这略微提高了性能。 你可以直接在postgresql.conf中配置它们或者更方便的使用ALTER ROLE来为每一个database user(...设置?).

没有这个优化,Django也会工作得很好,但每一个新的连接会做一些额外的查询来设置这些参数。

隔离级别

像 PostgreSQL 本身,Django默认READ COMMITTED 隔离级别isolation level. 如果你需要一个更高的隔离级别,例如 REPEATABLE READ 或者 SERIALIZABLE, 在 DATABASES OPTIONS 设置部分的数据库配置 :

import psycopg2.extensions

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

在较高的隔离级别中,你的application应该做好准备去处理序列化失败中引发的异常(?不确定)。 这个选项被设计为高级的用法。

varchartext列的索引

当你在你的模块字段中指定了db_index=True, Django通常会输出一个单一的CREATE INDEX语句。 但是,如果数据库类型对应的字段是varchar或者text (e.g., used by TextField, FileField, and CharField), 针对该列,Django会使用适当的PostgreSQL operator class 创建一个additional index. 使用LIKE操作在SQL中,额外的索引是执行正确的查找所必需的,即用contains and startswith查找类型。

添加扩展名的迁移操作

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

服务器端光标

Django中的新功能1.11。

当使用QuerySet.iterator()时,Django会打开server-side cursor 默认情况下,PostgreSQL假定仅获取游标查询结果的前10%。 查询计划员花费更少的时间来计划查询并开始更快地返回结果,但是如果检索到超过10%的结果,则可能会降低性能。 使用cursor_tuple_fraction选项来控制PostgreSQL对游标查询检索行数的假设。

事务池和服务器端游标

Django中的新功能1.11.1。

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

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

一个解决方案是通过将DISABLE_SERVER_SIDE_CURSORS设置为True来禁用DATABASES中的连接的服务器端游标。

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

另一个选项是使用atomic()块中的服务器端游标来包装每个QuerySet,因为它在事务期间禁用autocommit 这样,服务器端游标只能在事务期间生效。

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

Django使用PostgreSQL的SERIAL数据类型来存储自动递增主键。 一个SERIAL列填充有序列的值,它们跟踪下一个可用值。 手动将值分配给自动递增字段不会更新字段的序列,这可能会导致冲突。 像这样:

>>> 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语句。

测试数据库模板

Django中的新功能1.11。

您可以使用TEST['TEMPLATE']设置指定要创建测试数据库的模板(例如'template0')。

加快测试执行与非持久设置

您可以通过将PostgreSQL配置为不耐用的加速测试执行时间

警告

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

MySQL注释

版本支持

Django 支持MySQL 5.5 和更高版本。

Django的inspectdb功能使用了information_schema database,它在所有的database schemas包含了详细的数据。

Django希望数据库支持Unicode (UTF-8编码),并且代理它去执transactions and referential integrity的任务。 当你使用MyISAM储存引擎时,一个你需要注意到的事情是在MYSQL,后两个实际上是不去执行的,请参阅下一节。

存储引擎

MySQL有数种存储引擎. 你可以改变默认的存储引擎在不同的配置中。

直到MySQL 5.5.4版本, 默认存数引擎是MyISAM [1]. MyISAM数据的主要缺点是,它不支持transactions或者执行foreign-key约束。 从好的方面来看,直到MySQL 5.6.4,它是唯一一个支持全文索引和搜索的引擎。

自从MySQL 5.5.5,默认的储存引擎变为了 InnoDB. 这个引擎是全事务和支持foreign key引用的。 这可能是目前最好的选择。 但是,请注意由于它不能够记取AUTO_INCREMENT的值,而不是重新创建像 “max(id)+1”这样,导致InnoDB的autoincrement counter在MySQL中丢失了。 这可能导致一个无意重用的AutoField

如果将现有项目升级到MySQL5.5.5,随后添加一些表,确保您的表可以使用相同的存储引擎(如MyISAM数据与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的Database API 被描述为PEP 249. MySQL拥有三种很棒的能够实现API的驱动:

  • MySQLdb是一个由Andy Dustman开发,已经发展并支持十多年的一个本地驱动。
  • mysqlclientMySQLdb的一个分支,它与python3有着特别好的契合并且可以作为MySQLdb的直接替代。 在书写这篇的时候,这是在Django使用MySQL的推荐的选择
  • MySQL Connector/Python是一个来自Oracle的纯python驱动,它不需要MySQL client库或在标准库之外的任何Python模块。

所有这些驱动都是线程安全的,并提供连接池。 MySQLdb是当前唯一一个不支持python3的。

除了一个DB API驱动,Django需要一个适配器来通过它的ORM访问数据库驱动。 Django对 MySQLdb/mysqlclient提供了适配器直到MySQL Connector/Python包含了its own

MySQLdb的¶ T0>

Django需要MySQLdb版本1.2.3或更高版本。

在写文档的时候,最新版本MySQLdb、(1.2.5)还没有支持python3 为了在Python 3使用MySQLdb, 你需要安装mysqlclient来替代它 。

关于将date strings转化为 datetime objects,MySQLdb有已经存在的问题。 具体来说,值为0000-00-00的date strings对于MySQL是有效的,但是会被MySQLdb转换成None

这意味着当你在列中使用值可能为Noneloaddatadumpdata时,你需要注意,因为它们会被转换为0000-00-00

mysqlclient ¶ T0>

Django需要mysqlclient 1.3.3或更高版本。 mysqlclient应该与MySQLdb的行为大致相同。

MySQL连接器/ Python

MySQL Connector/Python可从download page下载。 Django适配器在1.1.X或更高版本可用。 它可能不支持最新的Django的版本。

时区定义

如果您打算使用Django的timezone support,请使用mysql_tzinfo_to_sql将时区表加载到MySQL数据库中。 这需要在你的MySQL服务器部署一次就好,而不是在每个数据库上。

创建数据库

你可以使用命令行工具运行这条SQL语句来create your database:

CREATE DATABASE <dbname> CHARACTER SET utf8;

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

整理设置

一列的排序规则设置控制了数据排序的顺序,以及字符串的比较。 它可以被设置在数据库的水平,也可以在每一个表和每一列 这个是在MySQL文档中详细记载的 在所有情况下,通过直接操作数据库表来设置排序规则; Django不提供一种在模型定义上设置此方法的方法。

默认情况下,在一个UTF8编码的数据库中,MySQL将会使用utf8_general_ci排序规则。 这会导致所有的字符串比较是否相等的结果是以不区分大小写 的方式完成的。 就像这样,"Fred" and "freD" 被认为是相等的在数据库级别上。 如果你在字段里有一个特殊的约束,如果试图将 "aa""AA"插入到同一列会是非法的,因为他们在默认的排序(and, hence, non-unique) 中比较相等。 如果要对特定列或表进行区分大小写比较,请更改列或表以使用utf8_bin归类。

请注意,根据 MySQL Unicode字符集, 比较下utf8_unicode_ci排序规则更加快速,但是与utf8_general_ci比较明显正确率略低。 如果在你的应用中这是可接受的,你应该使用utf8_general_ci因为它更快。 如果这是不能接受的 (例如,如果您需要德国字典顺序), 使用utf8_unicode_ci ,因为它更准确。

警告

模块层组以区分大小写的方式验证唯一的字段。 因此当使用一个不区分大小写的序列,一个带有唯一字段值的层组,只有通过不同层组(?)才可通过验证,但是依据调用save()IntegrityError错误将会被指出。

连接到数据库

请参阅 settings documentation.

连接设置将被用在这些命令上:

  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

设置sql_mode

从MySQL 5.7起,在MySQL 5.6的全新安装中,sql_mode选项的默认值包含STRICT_TRANS_TABLES 当数据在插入时被截断时,该选项会将警告升级为错误,因此Django强烈建议为MySQL启用严格模式以防止数据丢失(STRICT_TRANS_TABLESSTRICT_ALL_TABLES)

如果您需要自定义SQL模式,则可以像其他MySQL选项一样设置sql_mode变量​​:在配置文件中或与条目 'init_command': “SET sql_mode = 'STRICT_TRANS_TABLES'” 在数据库配置DATABASESOPTIONS

隔离级别

Django中的新功能1.11。

当运行并发负载时,来自不同会话的数据库事务(例如,处理不同请求的单独线程)可能会相互交互。 这些交互受每个会话的事务隔离级别的影响。 您可以在DATABASES中的数据库配置的OPTIONS部分中使用'isolation_level'条目设置连接的隔离级别。 此条目的有效值是四个标准隔离级别:

  • 'read uncommitted'
  • 'read committed'
  • 'repeatable read'
  • 'serializable'

None来使用服务器配置的隔离级别。 然而,Django最好使用read committed而不是MySQL的默认值,repeatable read。 repeatable read可能导致数据丢失。

创建表

当Django生成数据库的schema(数据库对象的集合)时,它没有指定一个储存引擎,所以你的表将被创建成你服务器配置的默认储存引擎。 最简单的解决方案是设置你的数据库服务器的默认存储引擎为你所需求的引擎。

如果你使用托管服务,并且不能改变你的服务器的默认存储引擎,你有两种选择。

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

    ALTER TABLE <tablename> ENGINE=INNODB;
    

    如果你有很多表,这会很繁琐。

  • 另一个选择是对于MySQLdb使用init_command选项在你创建表之前。

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

    这设置默认的储存引擎在连接数据库之上。 创建了表之后,您应该删除这个选项,因为它增加了一个只需要在每个表创建数据库连接时的查询。

表名

甚至在最新版本的MySQL中,这里存在已知的问题导致当某些SQL语句在一定条件下被执行下,表的名称可以被改变。 建议您使用小写的表名,如果可能的话,避免任何可能从这个行为产生的问题。 当Django从模型中自动生成表名时,它使用小写的表名,这主要考虑到如果你不顾问题让表名通过db_table参数。

保存点¶ T0>

Django ORM和MySQL (当使用InnoDBstorage engine) 支持数据库savepoints

如果你使用MyISAM存储引擎请注意,你将会收到数据库生成的错误如果你尝试去使用savepoint-related methods of the transactions API 这个原因是检测一个MySQL数据库或表的存储引擎是一项expensive operation,所以它认定为在这些操作结果中无操作的情况下,它不值得去动态转换这些方法。

关于具体字段的注释

字符字段

任何字段都被存储在 VARCHAR列类型的max_length ,它被限制在255个字符之内,如果您对这些字段使用unique=True的话。 这个影响到CharField, SlugFieldCommaSeparatedIntegerField

TextField限制

MySQL只能索引BLOBTEXT列的前N个字符。 由于TextField不具有定义的长度,因此您不能将其标记为unique=True MySQL will report: “BLOB/TEXT column ‘<db_column>’ used in key specification without a key length”.

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

MySQL 5.6.4和更高版本可以存储小数秒,只需要列定义包含一个小数指示 (例如DATETIME(6)).。 早期版本不支持它们。 此外,MySQLdb的1.2.5以上版本存在一个bug,它会阻止MySQL使用小数秒。

如果数据库服务器支持的话,Django不会升级现有的列去包含小数秒。 如果你想确保它们在一个当前的数据库中,这决定由你自己在目标数据库中手动去升级列,通过执行这样的一个命令:

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

或者在data migration中使用RunSQL 选项。

TIMESTAMP

如果你使用了包含TIMESTAMP 列的遗留数据库,你必须设置USE_TZ = False来避免数据丢失。 inspectdb 映射这些列在DateTimeField并且如果你启用时区支持,MySQL和Django将尝试从UTC的值转换为本地时间。

行锁定与QuerySet.select_for_update()

MySQL不支持NOWAITSKIP LOCKED选项 选择 ... 对于 UPDATE 声明。 如果select_for_update()nowait=Trueskip_locked=True一起使用,则将引发DatabaseError

自动类型转换可能导致意外的结果

当你执行一个字符串类型的查询时,存在整型值时,MySQL会强制转换表里的所有值变为整型在你进行比较之前。 如果你的表里包含'abc', 'def'和你查询WHERE mycolumn=0, 两行相匹配。 同样, WHERE mycolumn=1 将会匹配'abc1'.。 因此,Django中的字符串类型将会总是转换这个值为一个字符串当你查询中使用它之前。

If you implement custom model fields that inherit from Field directly, are overriding get_prep_value(), or use RawSQL, extra(), or raw(), you should ensure that you perform appropriate typecasting.

SQLite注释

SQLite 提供了一个极好的开发替代品对于主要为只读或者安装一个小的程序的应用程序。 你应该知道的是,如同所有的数据库服务一样,SQLLite有一些不同于其他数据库的差异。

子串匹配和区分大小写

对于所有的SQLite版本,存在一些细微的违反语感的行为当你试图匹配某些类型的字符串。 当你在Querysets中使用 iexact或者 contains 过滤器,这些行为会被触发。 这种行为分为两个情况:

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

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

一些可能的解决办法在 documented at sqlite.org,但是他们不能利用默认的SQLite后端在Django中,强行将他们合并将会非常的困难。 因此,Django显示默认的SQLite行为,当你使用不区分大小写或者子串过滤操作时你应该意识到这点。

旧SQLite和CASE表达式

SQLite 3.6.23.1和更老版本包含了一个bug 当handling query parameters 在一个 ELSE表达式中包含了一个CASE和算法。

2010年3月SQLite 3.6.23.1发布,目前大多数不同平台的二进制发行版包括一个新版本的SQLite,值得注意的是python 2.7 安装在windows平台上。

在撰写本文时,Windows - Python 2.7.10的最新版本包含SQLite 3.6.21。 您可以从安装pysqlite2或替换sqlite3.dll(默认情况下安装在C:\Python27\DLLs) https://www.sqlite.org/来解决这个问题。

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

Django将会使用一个pysqlite2模块优先于附带的sqlite3如果你发现一个是可用的在Python的标准库中。

这能够升级 DB-API 2.0接口或SQLite 3本身比那些包含在您的特定版本Python二进制发行版更新,如果你需要的话。

“数据库被锁定”错误

SQLite是一个轻量级的数据库,因此不能支持一个高水平的并发性。 OperationalError: 数据库 锁定 错误表明,您的应用程序正在经历比sqlite在默认配置中处理更多的并发。 这个错误意味着一个线程或进程在数据库连接上存在一个交互型锁,另一个超时线程等待独自锁被释放。

Python的SQLite包装器有一个默认的超时值,它决定了第二个线程在超时之前被允许等待多长时间,并引发 OperationalError: 数据库 锁定 错误。

如果你出现了这个错误,你可以这样解决:

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

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

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

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

    这将简单地使SQLite在抛出“数据库被锁定”错误之前等待一会儿;它不会真的做任何事情来解决它们。

QuerySet.select_for_update()不支持

SQLite不支持 选择 ... 对于 UPDATE 句法。 它将没有影响。

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

对于大多数的数据库后端, 原始查询(Manager.raw()或者cursor.execute()) 可以使用 “pyformat”参数风格,在查询中placeholders作为 '%(name)s'并且被传递的参数是一个字典而不是列表。 SQLite 不支持这个。

Oracle注释

Django支持Oracle数据库服务器 11.2及更高版本。 需要版本5.2或更高版本的cx_Oracle Python驱动程序。

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

  • 创建表
  • 创建序列
  • 创建过程
  • 创建触发器

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

  • 创建用户
  • ALTER用户
  • 删除用户
  • 创建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 role,这适合使用在一个私人开发人员的数据库。

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': '',
    }
}

在这种情况下, 你应该让 HOST and PORT 置空。 然而,如果你不是使用一个 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',
    }
}

你应该同时填写 HOST and PORT, 或者全部置空。 Django将会取决你的选择使用一个不同的连接描述符。

线程选项

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

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

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

INSERT ... RETURNING INTO

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

'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的keywords被使用作为模型字段名称或一个db_column选项的值时。 Django引用在查询使用的所有的标示符来防止大多数这样的问你,但是这个错误仍然可以发生当Oracle数据类型被用为一个列名。 特别是,避免使用这样的名称date, timestamp, float or number 作为一个字段名。

NULL和空字符串

Django通常更喜欢使用空字符串(“”)而不是NULL,但是Oracle将两个相同对待。 为了解决这个问题,Oracle后端忽略了字段中一个explict的null选项,让空字符串作为一个可能的值并生成DDL就像null=True 当从数据库获取时,它假定一个NULL值在这些字段之一意味一个空字符串,并且数据默认转换去反映这种假设。

TextField限制

The Oracle后端存储 TextFieldsNCLOB 列.。 通常使用LOB列时,Oracle 强加了一些限制:

  • LOB 列不被像主键一样使用。
  • LOB列不得用于索引。
  • LOB列不被使用在一个SELECT DISTINCT 列表。 这意味着在包含TextField列的模型上尝试使用QuerySet.distinct方法会导致运行时出现ORA-00932错误甲骨文。 一个解决方案是, 使用 QuerySet.defer方法连同distinct()来防止将要包含在 SELECT DISTINCT列表中的 TextField列。

使用第三方数据库后端

除了官方支持的数据库,这些第三方提供的后端也允许您在Django中使用其他数据库:

Django版本和ORM特性被支持通过这些非官方的后端相当大的变化。 查询这些非官方的后端有关的特定功能,以及任何支持的查询,应该针对每个第三方项目提供的支持项目。