23.20 The versions Django needs: Python, databases and libraries
The oldest Python, database server and library that each release from Django 5.0 to this commit supports, and where the code at this commit holds a project to each floor: BaseDatabaseFeatures, checked as a connection opens; the versions of the PostgreSQL and MySQL drivers, checked as their backend is imported; and pyproject.toml, which only an installer reads.
The code enforces only part of what the release notes state: Python and the two libraries Django requires are held only by the package’s metadata, and of GeoDjango’s libraries only an old SpatiaLite is refused.
Python
Django 5.0 supported Python 3.10, 3.11 and 3.12; 5.1 added 3.13, from 5.1.3, and 5.2 added 3.14, from 5.2.8. 6.0, 6.1 and 6.2 support 3.12, 3.13 and 3.14, the 5.2 series being the last for 3.10 and 3.11. At this commit pyproject.toml gives "requires-python" as ">= 3.12".
Nothing in Django refuses an interpreter older than 3.12. Under Python 3.11 every module of the package parses and import django succeeds; in a run, django.setup then raised ValueError as it configured the logging handler “mail_admins”, from an ImportError for inspect, which Python added in 3.12 and the module of the generic views imports at its top.
Database servers
| release | PostgreSQL | MySQL | MariaDB | SQLite |
|---|---|---|---|---|
| 5.0 | PostgreSQL 12 | MySQL 8.0.11 | MariaDB 10.4 | SQLite 3.27.0 |
| 5.1 | PostgreSQL 13 | MySQL 8.0.11 | MariaDB 10.5 | SQLite 3.31.0 |
| 5.2 | PostgreSQL 14 | MySQL 8.0.11 | MariaDB 10.5 | SQLite 3.31.0 |
| 6.0 | PostgreSQL 14 | MySQL 8.0.11 | MariaDB 10.6 | SQLite 3.31.0 |
| 6.1 | PostgreSQL 15 | MySQL 8.4 | MariaDB 10.11 | SQLite 3.37.0 |
| 6.2 | PostgreSQL 16 | MySQL 8.4 | MariaDB 10.11 | SQLite 3.37.0 |
Where the notes drop a version of PostgreSQL, MySQL or MariaDB, the reason they give is the end of its upstream support, and 6.1 also passed over MySQL 8.1 to 8.3 and MariaDB 10.7 to 10.10 as short-term releases; SQLite’s floor rises without a reason given. 5.0’s change to MySQL removed only the pre-releases of 8.0.
At this commit each backend’s minimum_database_version holds 6.2’s floor as a tuple: (16,) for PostgreSQL, (3, 37) for SQLite, (19,) for Oracle, and on MySQL a cached property that answers (10, 11) for MariaDB and (8, 4) otherwise. BaseDatabaseWrapper calls BaseDatabaseWrapper for each alias until it passes once in a process, and the check raises NotSupportedError, naming the version required and the version found, for a server older than the floor (BaseDatabaseWrapper; What a database can do: BaseDatabaseFeatures).
Drivers and Django’s own dependencies
| release | asgiref | sqlparse | oracledb | gettext |
|---|---|---|---|---|
| 5.0 | asgiref 3.7.0 | sqlparse 0.3.1 | oracledb 1.3.2, or cx_Oracle 8.3 | gettext 0.15 |
| 5.1 | asgiref 3.8.1 | sqlparse 0.3.1 | oracledb 1.3.2, or cx_Oracle 8.3 | gettext 0.15 |
| 5.2 | asgiref 3.8.1 | sqlparse 0.3.1 | oracledb 2.3.0, or cx_Oracle 8.3 | gettext 0.19 |
| 6.0 | asgiref 3.9.1 | sqlparse 0.5.0 | oracledb 2.3.0 | gettext 0.19 |
| 6.1 | asgiref 3.9.1 | sqlparse 0.5.0 | oracledb 2.3.0 | gettext 0.19 |
| 6.2 | asgiref 3.12.1 | sqlparse 0.5.0 | oracledb 4.0.2 | gettext 0.19 |
asgiref and sqlparse, the libraries Django requires, are at this commit the dependencies of pyproject.toml, "asgiref>=3 and "sqlparse>=0, beside tzdata on Windows; nothing in Django checks the version of either.
Two backends check their driver as their module is imported, refusing with ImproperlyConfigured a psycopg2 older than 2.9.9, a psycopg 3 older than 3.1.12 or a mysqlclient older than 2.2.1. The Oracle backend imports oracledb alone; its connection reads the driver’s version as oracledb_version, and nothing at this commit compares it with 4.0.2. gettext’s floor is a message: makemessages and compilemessages, finding one of its programs missing, ask for GNU gettext 0.19 or newer, and check the version of none they find (check_programs, Command.handle; Making catalogues: makemessages and compilemessages).
In dropping Python 3.11, 6.0 named the first release of each library to add or confirm support for 3.12: aiosmtpd 1.4.5, argon2-cffi 23.1.0, bcrypt 4.1.1, docutils 0.22, geoip2 4.8.0, Pillow 10.1.0, mysqlclient 2.2.1, numpy 1.26.0, PyYAML 6.0.2, psycopg 3.1.12, psycopg2 2.9.9, redis-py 5.1.0, selenium 4.23.0, sqlparse 0.5.0 and tblib 3.0.0; 5.0 had raised selenium to 4.8.0, colorama to 0.4.6 and docutils to 0.19. Of these the code checks only the three drivers; argon2-cffi’s and bcrypt’s floors are also the extras of pyproject.toml.
GeoDjango’s libraries
docs/ref/contrib/gis/install/geolibs.txt ). 5.0 also added GDAL 3.7 and GEOS 3.12 to the versions supported.| release | PostGIS | GDAL | GEOS | PROJ |
|---|---|---|---|---|
| 5.0 | PostGIS 2.5 | GDAL 2.4 | GEOS 3.8 | PROJ 5 |
| 5.1 | PostGIS 3.0 | GDAL 3.0 | GEOS 3.8 | PROJ 6 |
| 5.2 | PostGIS 3.1 | GDAL 3.1 | GEOS 3.8 | PROJ 6 |
| 6.0 | PostGIS 3.1 | GDAL 3.1 | GEOS 3.8 | PROJ 6 |
| 6.1 | PostGIS 3.2 | GDAL 3.3 | GEOS 3.10 | PROJ 6 |
| 6.2 | PostGIS 3.3 | GDAL 3.5 | GEOS 3.11 | PROJ 6 |
None of these floors is a check. GDAL is loaded from GDAL_LIBRARY_PATH or found by name, the versioned names going down to 3.5, but on POSIX the unversioned “gdal” and “GDAL” are tried first, and GDAL_VERSION, read from the library once loaded, is compared with no floor. GEOS is found under unversioned names alone, and geos_version_tuple is compared only with 3.12 and 3.14, for what those releases changed. PostGISOperations takes the setting POSTGIS_VERSION or asks the server, and compares the version with nothing; 3.3 appears only in the message of the ImproperlyConfigured it raises when it cannot read one. The one refusal is SpatiaLite’s: SpatiaLiteOperations raises ImproperlyConfigured below 4.3.0. How the libraries are loaded is told in Geometries in Python: GEOS and GDAL, and the spatial backends in Spatial backends: PostGIS, SpatiaLite, MySQL and Oracle.