Django tente d’activer autant de fonctionnalités que possible sur tous les types de base de données. Cependant, tous les types de base de données ne sont pas semblables, et nous avons dû prendre des décisions de conception sur les fonctionnalités à activer et les hypothèses sur lesquelles nous pouvions nous baser en toute sécurité.
Ce fichier décrit quelques-unes des caractéristiques qui pourraient être pertinentes pour l’utilisation de Django. Bien sûr, il ne remplace pas la documentation ou les manuels de référence spécifiques aux différents serveurs de base de données.
Persistent connections avoid the overhead of re-establishing a connection to the database in each request. They’re controlled by the CONN_MAX_AGE parameter which defines the maximum lifetime of a connection. It can be set independently for each database.
The default value is 0, preserving the historical behavior of closing the database connection at the end of each request. To enable persistent connections, set CONN_MAX_AGE to a positive number of seconds. For unlimited persistent connections, set it to None.
Django opens a connection to the database when it first makes a database query. It keeps this connection open and reuses it in subsequent requests. Django closes the connection once it exceeds the maximum age defined by CONN_MAX_AGE or when it isn’t usable any longer.
In detail, Django automatically opens a connection to the database whenever it needs one and doesn’t have one already — either because this is the first connection, or because the previous connection was closed.
At the beginning of each request, Django closes the connection if it has reached its maximum age. If your database terminates idle connections after some time, you should set CONN_MAX_AGE to a lower value, so that Django doesn’t attempt to use a connection that has been terminated by the database server. (This problem may only affect very low traffic sites.)
At the end of each request, Django closes the connection if it has reached its maximum age or if it is in an unrecoverable error state. If any database errors have occurred while processing the requests, Django checks whether the connection still works, and closes it if it doesn’t. Thus, database errors affect at most one request; if the connection becomes unusable, the next request gets a fresh connection.
Since each thread maintains its own connection, your database must support at least as many simultaneous connections as you have worker threads.
Sometimes a database won’t be accessed by the majority of your views, for example because it’s the database of an external system, or thanks to caching. In such cases, you should set CONN_MAX_AGE to a low value or even 0, because it doesn’t make sense to maintain a connection that’s unlikely to be reused. This will help keep the number of simultaneous connections to this database small.
The development server creates a new thread for each request it handles, negating the effect of persistent connections. Don’t enable them during development.
When Django establishes a connection to the database, it sets up appropriate parameters, depending on the backend being used. If you enable persistent connections, this setup is no longer repeated every request. If you modify parameters such as the connection’s isolation level or time zone, you should either restore Django’s defaults at the end of each request, force an appropriate value at the beginning of each request, or disable persistent connections.
Django assumes that all databases use UTF-8 encoding. Using other encodings may result in unexpected behavior such as “value too long” errors from your database for data that is valid in Django. See the database specific notes below for information on how to set up your database correctly.
Django supports PostgreSQL 8.4 and higher.
Django a besoin des paramètres suivants pour se connecter aux bases de données :
timezone: 'UTC' quand USE_TZ vaut True, sinon indiquez la valeur de TIME_ZONE.
Si ces paramètres ont déjà les valeurs correctes, Django n’aura pas à les indiquer pour chaque nouvelle connexion, ce qui améliore légèrement les performances. Vous pouvez les configurer directement dans postgresql.conf ou plus commodément pour chaque utilisateur de base de données avec ALTER ROLE.
Django fonctionne très bien sans cette optimisation, mais chaque nouvelle connexion va faire quelques requêtes supplémentaires pour définir ces paramètres.
In previous versions of Django, database-level autocommit could be enabled by setting the autocommit key in the OPTIONS part of your database configuration in DATABASES:
DATABASES = {
# ...
'OPTIONS': {
'autocommit': True,
},
}
Since Django 1.6, autocommit is turned on by default. This configuration is ignored and can be safely removed.
Like PostgreSQL itself, Django defaults to the READ COMMITTED isolation level. If you need a higher isolation level such as REPEATABLE READ or SERIALIZABLE, set it in the OPTIONS part of your database configuration in DATABASES:
import psycopg2.extensions
DATABASES = {
# ...
'OPTIONS': {
'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
},
}
Note
Under higher isolation levels, your application should be prepared to handle exceptions raised on serialization failures. This option is designed for advanced uses.
Lorsque vous indiquez db_index=True sur vos champs de modèle, Django génère généralement un seul CREATE INDEX. Toutefois, si le type de champ de base de données est varchar ou text (par exemple, pour les champs de type CharField, FileField ou TextField), Django crée alors un index supplémentaire qui utilise une classe opérateur de PostgreSQL appropriée pour la colonne. Cet index supplémentaire est nécessaire pour le bon fonctionnement des recherches qui utilisent l’opérateur SQL LIKE, comme le font les recherches avec contains et startswith.
Django prend en charge les versions 5.0.3 et plus récentes de MySQL.
Django’s inspectdb feature uses the information_schema database, which contains detailed data on all database schemas.
The minimum version requirement of MySQL 5.0.3 was set in Django 1.5.
Django s’attend à ce que la base de données accepte l’Unicode (codage UTF-8) et lui délègue la charge de faire respecter les transactions et l’intégrité référentielle. Il est important d’être conscient du fait que ces deux derniers aspects ne sont pas réellement appliqués par MySQL lorsque le moteur de stockage MyISAM est utilisé, voir la section suivante.
MySQL has several storage engines. You can change the default storage engine in the server configuration.
Until MySQL 5.5.4, the default engine was MyISAM [1]. The main drawbacks of MyISAM are that it doesn’t support transactions or enforce foreign-key constraints. On the plus side, it was the only engine that supported full-text indexing and searching until MySQL 5.6.4.
Since MySQL 5.5.5, the default storage engine is InnoDB. This engine is fully transactional and supports foreign key references. It’s probably the best choice at this point. However, note that the the InnoDB autoincrement counter is lost on a MySQL restart because it does not remember the AUTO_INCREMENT value, instead recreating it as “max(id)+1”. This may result in an inadvertent reuse of AutoField values.
Si vous mettez à jour un projet existant vers MySQL 5.5.5 et que vous ajoutez ensuite quelques tables, assurez-vous que vos tables utilisent le même moteur de stockage (par ex. MyISAM ou InnoDB). Plus précisément, si les tables qui ont une clé étrangère ForeignKey entre elles utilisent des moteurs de stockage différents, vous pouvez voir une erreur comme celle-ci lors de l’exécution de syncdb:
_mysql_exceptions.OperationalError: (
1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
)
[1] | À moins que cela n’ait été modifié par le gestionnaire de votre paquet MySQL. Il nous a été rapporté que le programme d’installation de Windows Community Server définit InnoDB comme moteur de stockage par défaut, par exemple. |
MySQLdb est l’interface Python pour MySQL. La version 1.2.1p2 ou une version ultérieure est requise pour une compatibilité complète de MySQL dans Django.
Note
Si vous voyez ImportError: cannot import name ImmutableSet lorsque vous essayez d’utiliser Django, votre installation de MySQLdb peut contenir un fichier sets.py obsolète qui entre en conflit avec le module intégré du même nom à partir de Python 2.4. Pour résoudre ce problème, vérifiez que vous avez installé la version MySQLdb 1.2.1p2 ou une plus récente, puis supprimez un éventuel fichier sets.py dans le répertoire MySQLdb qui aurait été laissé par une version antérieure.
Note
There are known issues with the way MySQLdb converts date strings into datetime objects. Specifically, date strings with value 0000-00-00 are valid for MySQL but will be converted into None by MySQLdb.
This means you should be careful while using loaddata/dumpdata with rows that may have 0000-00-00 values, as they will be converted to None.
At the time of writing, the latest release of MySQLdb (1.2.4) doesn’t support Python 3. In order to use MySQL under Python 3, you’ll have to install an unofficial fork, such as MySQL-for-Python-3.
This port is still in alpha. In particular, it doesn’t support binary data, making it impossible to use django.db.models.BinaryField.
If you plan on using Django’s timezone support, use mysql_tzinfo_to_sql to load time zone tables into the MySQL database. This needs to be done just once for your MySQL server, not per database.
Vous pouvez créer une base de données_ à l’aide des outils de ligne de commande et de cette commande SQL :
CREATE DATABASE <dbname> CHARACTER SET utf8;
Cela garantit que toutes les tables et colonnes utilisent le codage UTF-8 par défaut.
La méthode de tri (« collation ») d’une colonne détermine l’ordre dans lequel les données sont triées ainsi que les comparaisons d’égalité entre les chaînes. Ce paramètre peut être défini à l’échelle de la base de données mais aussi par table et par colonne. Ceci est documenté complètement dans la documentation MySQL. Dans tous les cas, la méthode de tri est définie en modifiant directement les tables de la base de données ; Django ne fournit aucun moyen de faire cela au niveau de la définition du modèle.
By default, with a UTF-8 database, MySQL will use the utf8_general_ci collation. This results in all string equality comparisons being done in a case-insensitive manner. That is, "Fred" and "freD" are considered equal at the database level. If you have a unique constraint on a field, it would be illegal to try to insert both "aa" and "AA" into the same column, since they compare as equal (and, hence, non-unique) with the default collation.
Dans de nombreux cas, ce comportement par défaut ne sera pas un problème. Toutefois, si vous voulez vraiment que les comparaisons sur une colonne ou une table particulière soient sensibles à la casse, vous devez modifier la colonne ou la table pour qu’elle utilise le tri utf8_bin. Dans ce cas, la chose importante à savoir est que si vous utilisez MySQLdb 1.2.2, la base de données dans Django renvoie alors des chaînes d’octets (au lieu de chaînes Unicode) pour tous les champs de type caractère. Il s’agit d’une grosse modification par rapport à la pratique normale dans Django de toujours renvoyer des chaînes Unicode. C’est donc à vous, le développeur, de gérer le fait que vous recevrez des chaînes d’octets si vous configurez des tables pour utiliser la méthode de tri utf8_bin. Django lui-même devrait généralement fonctionner correctement avec ces colonnes (sauf pour les tables contrib.sessions Session et contrib.admin LogEntry décrites ci-dessous), mais votre code doit parfois ajouter un appel à django.utils.encoding.smart_text() si vous voulez vraiment travailler avec des données cohérentes – Django ne le fera pas pour vous (la couche principale de base de données et la couche des modèles sont séparées en interne de sorte que la couche de la base de données ne sait pas qu’il est nécessaire de faire cette conversion dans ce seul cas particulier).
Si vous utilisez MySQLdb 1.2.1p2, la classe standard CharField de Django renvoie des chaînes Unicode même avec un tri utf8_bin. Toutefois, les champs TextField sont renvoyés comme une instance d’un tableau de type array.array (du module Python array standard). Django ne peut pas faire grand chose à ce sujet, puisque, encore une fois, les informations pour savoir quelles sont les conversions nécessaires ne sont pas disponibles au moment où les données sont lues dans la base de données. Ce problème a été résolu dans MySQLdb 1.2.2, donc si vous souhaitez utiliser TextField avec utf8_bin, la solution recommandée est de mettre à jour vers la version 1.2.2, puis de traiter les chaînes d’octets comme décrit ci-dessus (ce qui ne devrait pas être trop difficile).
Should you decide to use utf8_bin collation for some of your tables with MySQLdb 1.2.1p2 or 1.2.2, you should still use utf8_general_ci (the default) collation for the django.contrib.sessions.models.Session table (usually called django_session) and the django.contrib.admin.models.LogEntry table (usually called django_admin_log). Those are the two standard tables that use TextField internally.
Please note that according to MySQL Unicode Character Sets, comparisons for the utf8_general_ci collation are faster, but slightly less correct, than comparisons for utf8_unicode_ci. If this is acceptable for your application, you should use utf8_general_ci because it is faster. If this is not acceptable (for example, if you require German dictionary order), use utf8_unicode_ci because it is more accurate.
Avertissement
Model formsets validate unique fields in a case-sensitive manner. Thus when using a case-insensitive collation, a formset with unique field values that differ only by case will pass validation, but upon calling save(), an IntegrityError will be raised.
Reportez-vous à la documentation des réglages.
Les paramètres de connexion sont utilisés dans cet ordre :
En d’autres termes, si vous définissez le nom de la base de données dans OPTIONS, cette définition a la priorité sur NAME, qui aurait lui-même la priorité sur n’importe quelle valeur d’un fichier d’options MySQL.
Voici un exemple de configuration qui utilise un fichier d’options 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
Several other MySQLdb connection options may be useful, such as ssl, init_command, and sql_mode. Consult the MySQLdb documentation for more details.
Lorsque Django génère le schéma, il ne précise pas de moteur de stockage, donc les tables seront créées avec le moteur de stockage par défaut de votre serveur de base de données. La solution la plus simple est de définir le moteur souhaité comme moteur de stockage par défaut pour votre serveur de base de données.
Si vous utilisez un service d’hébergement et que vous ne pouvez pas modifier le moteur de stockage par défaut sur votre serveur, vous avez plusieurs possibilités.
Après la création des tables, exécutez une commande SQL ALTER TABLE pour convertir une table vers un nouveau moteur de stockage (comme InnoDB) :
ALTER TABLE <tablename> ENGINE=INNODB;
Cela peut être fastidieux si vous avez beaucoup de tables.
Une autre possibilité est d’utiliser l’option init_command de MySQLdb avant de créer les tables :
'OPTIONS': {
'init_command': 'SET storage_engine=INNODB',
}
Ceci définit le moteur de stockage par défaut lors de la connexion à la base de données. Une fois que les tables ont été créées, vous devriez supprimer cette option car elle ajoute une requête lors de chaque connexion à la base de données, alors que c’est uniquement nécessaire lors de la création d’une table.
Une autre méthode pour modifier le moteur de stockage est décrite dans AlterModelOnSyncDB.
Certains problèmes connus, même dans les dernières versions de MySQL peuvent engendrer une modification d’un nom de table lorsque certaines instructions SQL sont exécutées sous certaines conditions. Il est recommandé d’utiliser des noms de table en minuscules, si possible, pour éviter les problèmes qui pourraient résulter de ce comportement. Django utilise des noms de tables en minuscules quand il génère automatiquement les noms de table à partir des modèles, c’est donc un élément à prendre en compte surtout si vous surchargez le nom de la table en utilisant le paramètre db_table.
Both the Django ORM and MySQL (when using the InnoDB storage engine) support database savepoints.
Si vous utilisez le moteur de stockage MyISAM, vous recevrez des erreurs générées par la base de données si vous essayez d’utiliser les méthodes de l’API des transactions liées aux points de sauvegarde. En effet, comme la détection du moteur de stockage d’une table ou d’une base de données MySQL est une opération très coûteuse en ressources, il a été décidé de ne pas convertir dynamiquement ces méthodes en méthodes neutres en se basant sur ce genre de détection.
Tous les champs qui sont stockés dans des types de colonnes VARCHAR ont leur taille maximale (max_length) limitée à 255 caractères si vous utilisez unique=True pour ce champ. Cela concerne les champs CharField, SlugField et CommaSeparatedIntegerField.
MySQL ne stocke pas les fractions de secondes. Les fractions de secondes sont donc tronquées à zéro quand une heure est stockée dans la base.
MySQL ne gère pas l’option NOWAIT de l’instruction SELECT ... FOR UPDATE. Si select_for_update() est utilisé avec nowait=True, une exception de type DatabaseError sera générée.
When performing a query on a string type, but with an integer value, MySQL will coerce the types of all values in the table to an integer before performing the comparison. If your table contains the values 'abc', 'def' and you query for WHERE mycolumn=0, both rows will match. Similarly, WHERE mycolumn=1 will match the value 'abc1'. Therefore, string type fields included in Django will always cast the value to a string before using it in a query.
If you implement custom model fields that inherit from Field directly, are overriding get_prep_value(), or use extra() or raw(), you should ensure that you perform the appropriate typecasting.
SQLite fournit une excellente alternative pour le développement d’applications qui sont essentiellement en lecture seule ou qui nécessitent une installation de plus petite taille. Comme avec tous les serveurs de base de données, cependant, il y a quelques différences spécifiques à SQLite à prendre en compte.
Pour toutes les versions de SQLite, il y a un comportement peu intuitif lorsque l’on essaie de faire correspondre certains types de chaînes. Ce comportement est déclenché lors de l’utilisation des filtres iexact ou contains dans des QuerySets. Le comportement se divise en deux cas :
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.
Some possible workarounds for this are documented at sqlite.org, but they aren’t utilised by the default SQLite backend in Django, as incorporating them would be fairly difficult to do robustly. Thus, Django exposes the default SQLite behavior and you should be aware of this when doing case-insensitive or substring filtering.
Versions of SQLite 3.3.5 and older contains the following bugs:
SQLite 3.3.6 was released in April 2006, so most current binary distributions for different platforms include newer version of SQLite usable from Python through either the pysqlite2 or the sqlite3 modules.
The Ubuntu “Intrepid Ibex” (8.10) SQLite 3.5.9-3 package contains a bug that causes problems with the evaluation of query expressions. If you are using Ubuntu “Intrepid Ibex”, you will need to update the package to version 3.5.9-3ubuntu1 or newer (recommended) or find an alternate source for SQLite packages, or install SQLite from source.
At one time, Debian Lenny shipped with the same malfunctioning SQLite 3.5.9-3 package. However the Debian project has subsequently issued updated versions of the SQLite package that correct these bugs. If you find you are getting unexpected results under Debian, ensure you have updated your SQLite package to 3.5.9-5 or later.
The problem does not appear to exist with other versions of SQLite packaged with other operating systems.
SQLite version 3.6.2 (released August 30, 2008) introduced a bug into SELECT DISTINCT handling that is triggered by, amongst other things, Django’s DateQuerySet (returned by the dates() method on a queryset).
You should avoid using this version of SQLite with Django. Either upgrade to 3.6.3 (released September 22, 2008) or later, or downgrade to an earlier version of SQLite.
For versions of Python 2.5 or newer that include sqlite3 in the standard library Django will now use a pysqlite2 interface in preference to sqlite3 if it finds one is available.
This provides the ability to upgrade both the DB-API 2.0 interface or SQLite 3 itself to versions newer than the ones included with your particular Python binary distribution, if needed.
SQLite is meant to be a lightweight database, and thus can’t support a high level of concurrency. OperationalError: database is locked errors indicate that your application is experiencing more concurrency than sqlite can handle in default configuration. This error means that one thread or process has an exclusive lock on the database connection and another thread timed out waiting for the lock the be released.
Python’s SQLite wrapper has a default timeout value that determines how long the second thread is allowed to wait on the lock before it times out and raises the OperationalError: database is locked error.
If you’re getting this error, you can solve it by:
Switching to another database backend. At a certain point SQLite becomes too “lite” for real-world applications, and these sorts of concurrency errors indicate you’ve reached that point.
Rewriting your code to reduce concurrency and ensure that database transactions are short-lived.
Increase the default timeout value by setting the timeout database option:
'OPTIONS': {
# ...
'timeout': 20,
# ...
}
This will simply make SQLite wait a bit longer before throwing “database is locked” errors; it won’t really do anything to solve them.
SQLite does not support the SELECT ... FOR UPDATE syntax. Calling it will have no effect.
For most backends, raw queries (Manager.raw() or cursor.execute()) can use the “pyformat” parameter style, where placeholders in the query are given as '%(name)s' and the parameters are passed as a dictionary rather than a list. SQLite does not support this.
sqlite3 does not provide a way to retrieve the SQL after quoting and substituting the parameters. Instead, the SQL in connection.queries is rebuilt with a simple string interpolation. It may be incorrect. Make sure you add quotes where necessary before copying a query into an SQLite shell.
Django supports Oracle Database Server versions 9i and higher. Oracle version 10g or later is required to use Django’s regex and iregex query operators. You will also need at least version 4.3.1 of the cx_Oracle Python driver.
Note that due to a Unicode-corruption bug in cx_Oracle 5.0, that version of the driver should not be used with Django; cx_Oracle 5.0.1 resolved this issue, so if you’d like to use a more recent cx_Oracle, use version 5.0.1.
cx_Oracle 5.0.1 or greater can optionally be compiled with the WITH_UNICODE environment variable. This is recommended but not required.
In order for the python manage.py syncdb command to work, your Oracle database user must have privileges to run the following commands:
To run Django’s test suite, the user needs these additional privileges:
The Oracle database backend uses the SYS.DBMS_LOB package, so your user will require execute permissions on it. It’s normally accessible to all users by default, but in case it is not, you’ll need to grant permissions like so:
GRANT EXECUTE ON SYS.DBMS_LOB TO user;
To connect using the service name of your Oracle database, your settings.py file should look something like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'xe',
'USER': 'a_user',
'PASSWORD': 'a_password',
'HOST': '',
'PORT': '',
}
}
In this case, you should leave both HOST and PORT empty. However, if you don’t use a tnsnames.ora file or a similar naming method and want to connect using the SID (“xe” in this example), then fill in both HOST and PORT like so:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'xe',
'USER': 'a_user',
'PASSWORD': 'a_password',
'HOST': 'dbprod01ned.mycompany.com',
'PORT': '1540',
}
}
You should either supply both HOST and PORT, or leave both as empty strings. Django will use a different connect descriptor depending on that choice.
If you plan to run Django in a multithreaded environment (e.g. Apache using the default MPM module on any modern operating system), then you must set the threaded option of your Oracle database configuration to True:
'OPTIONS': {
'threaded': True,
},
Failure to do this may result in crashes and other odd behavior.
By default, the Oracle backend uses a RETURNING INTO clause to efficiently retrieve the value of an AutoField when inserting new rows. This behavior may result in a DatabaseError in certain unusual setups, such as when inserting into a remote table, or into a view with an INSTEAD OF trigger. The RETURNING INTO clause can be disabled by setting the use_returning_into option of the database configuration to False:
'OPTIONS': {
'use_returning_into': False,
},
In this case, the Oracle backend will use a separate SELECT query to retrieve AutoField values.
Oracle imposes a name length limit of 30 characters. To accommodate this, the backend truncates database identifiers to fit, replacing the final four characters of the truncated name with a repeatable MD5 hash value. Additionally, the backend turns database identifiers to all-uppercase.
To prevent these transformations (this is usually required only when dealing with legacy databases or accessing tables which belong to other users), use a quoted name as the value for 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"'
Quoted names can also be used with Django’s other supported database backends; except for Oracle, however, the quotes have no effect.
When running syncdb, an ORA-06552 error may be encountered if certain Oracle keywords are used as the name of a model field or the value of a db_column option. Django quotes all identifiers used in queries to prevent most such problems, but this error can still occur when an Oracle datatype is used as a column name. In particular, take care to avoid using the names date, timestamp, number or float as a field name.
Django generally prefers to use the empty string (‘’) rather than NULL, but Oracle treats both identically. To get around this, the Oracle backend ignores an explicit null option on fields that have the empty string as a possible value and generates DDL as if null=True. When fetching from the database, it is assumed that a NULL value in one of these fields really means the empty string, and the data is silently converted to reflect this assumption.
The Oracle backend stores TextFields as NCLOB columns. Oracle imposes some limitations on the usage of such LOB columns in general:
En plus des bases de données prises en charge officiellement, il existe des moteurs externes à Django qui permettent d’utiliser d’autres bases de données avec Django :
Les versions de Django et les fonctionnalités ORM prises en charges par ces moteurs inofficiels varient considérablement. Si vous avez des questions concernant les capacités spécifiques de ces moteurs inofficiels ou des questions de support, vous devrez vous adresser aux canaux d’aide offerts par chacun de ces projets externes.
Jan 13, 2016