April 1, 2019
Welcome to Django 2.2!
These release notes cover the new features, as well as some backwards incompatible changes you’ll want to be aware of when upgrading from Django 2.1 or earlier. We’ve begun the deprecation process for some features.
See the Upgrading Django to a newer version guide if you’re updating an existing project.
Django 2.2 is designated as a long-term support release. It will receive security updates for at least three years after its release. Support for the previous LTS, Django 1.11, will end in April 2020.
Django 2.2 supports Python 3.5, 3.6, 3.7, 3.8 (as of 2.2.8), and 3.9 (as of 2.2.17). We highly recommend and only officially support the latest release of each series.
The new CheckConstraint
and
UniqueConstraint
classes enable adding custom
database constraints. Constraints are added to models using the
Meta.constraints
option.
django.contrib.admin
¶TabularInline
.django.contrib.auth
¶HttpRequest
is now passed as the first positional argument to
RemoteUserBackend.configure_user()
, if it accepts it.django.contrib.postgres
¶ordering
argument for
ArrayAgg
and
StringAgg
determines the
ordering of the aggregated elements.BTreeIndex
,
HashIndex
and
SpGistIndex
classes allow
creating B-Tree
, hash
, and SP-GiST
indexes in the database.BrinIndex
now has the
autosummarize
parameter.search_type
parameter of
SearchQuery
allows searching for
a phrase or raw expression.django.contrib.staticfiles
¶collectstatic --ignore
option so that
patterns like /vendor/*.js
can be used.QuerySet.iterator()
on SQLite.View.setup
hook
initializes view attributes before calling
dispatch()
. It allows mixins to setup
instance attributes for reuse in child classes.--force-color
option forces colorization of the command
output.inspectdb
now creates models for foreign tables on PostgreSQL.inspectdb --include-views
now creates models for materialized views
on Oracle and PostgreSQL.inspectdb --include-partitions
option allows creating
models for partition tables on PostgreSQL. In older versions, models are
created child tables instead the parent.inspectdb
now introspects DurationField
for Oracle and PostgreSQL, and AutoField
for
SQLite.dbshell
is wrapped with rlwrap
, if available.
rlwrap
provides a command history and editing of keyboard input.makemigrations --no-header
option avoids writing header
comments in generated migration file(s). This option is also available for
squashmigrations
.runserver
can now use Watchman to improve the performance of
watching a large number of files for changes.migrate --plan
option prints the list of migration
operations that will be performed.NoneType
can now be serialized in migrations.Index.opclasses
).Index.condition
).NullIf
and
Reverse
database functions, as well as
many math database functions.ignore_conflicts
parameter of
QuerySet.bulk_create()
to True
tells the database to ignore
failure to insert rows that fail uniqueness constraints or other checks.ExtractIsoYear
function extracts
ISO-8601 week-numbering years from DateField
and
DateTimeField
, and the new iso_year
lookup allows querying by an ISO-8601 week-numbering year.QuerySet.bulk_update()
method allows efficiently updating
specific fields on multiple model instances.Model.save()
, QuerySet.update()
, and
Model.delete()
. This improves the performance of autocommit by reducing
the number of database round trips.StdDev
and
Variance
functions.DISTINCT
aggregation is added to the
Aggregate
class. Adding allow_distinct =
True
as a class attribute on
Aggregate
subclasses allows a distinct
keyword argument to be
specified on initialization to ensure that the aggregate function is only
called for each distinct value of expressions
.RelatedManager.add()
, create()
,
remove()
, set()
,
get_or_create()
, and update_or_create()
methods are now allowed on
many-to-many relationships with intermediate models. The new
through_defaults
argument is used to specify values for new intermediate
model instance(s).HttpRequest.headers
to allow simple access to a request’s
headers.handle_forward_references=True
to serializers.deserialize()
.
Additionally, loaddata
handles forward references automatically.SimpleTestCase.assertURLEqual()
assertion checks for a given
URL, ignoring the ordering of the query string.
assertRedirects()
uses the new assertion.Client
now supports automatic JSON
serialization of list and tuple data
when
content_type='application/json'
.ORACLE_MANAGED_FILES
test
database setting allows using Oracle Managed Files (OMF) tablespaces.TestCase
test on SQLite 3.20+, just like on other
backends that support deferrable constraints. These checks aren’t implemented
for older versions of SQLite because they would require expensive table
introspection there.DiscoverRunner
now skips the setup of databases
not referenced by tests.ResolverMatch.route
attribute stores the route of the
matching URL pattern.MaxValueValidator
, MinValueValidator
,
MinLengthValidator
, and MaxLengthValidator
now accept
a callable limit_value
.This section describes changes that may be needed in third-party database backends.
DatabaseFeatures.supports_table_check_constraints
to
False
.DatabaseFeatures.supports_ignore_conflicts
to False
.DurationField
or set DatabaseFeatures.can_introspect_duration_field
to False
.DatabaseFeatures.uses_savepoints
now defaults to True
.DatabaseFeatures.supports_partial_indexes
to False
.DatabaseIntrospection.table_name_converter()
and
column_name_converter()
are removed. Third party database backends may
need to instead implement DatabaseIntrospection.identifier_converter()
.
In that case, the constraint names that
DatabaseIntrospection.get_constraints()
returns must be normalized by
identifier_converter()
.Index
to
SchemaEditor
and these SchemaEditor
methods are added:_create_primary_key_sql()
and _delete_primary_key_sql()
_delete_index_sql()
(to pair with _create_index_sql()
)_delete_unique_sql
(to pair with _create_unique_sql()
)_delete_fk_sql()
(to pair with _create_fk_sql()
)_create_check_sql()
and _delete_check_sql()
DatabaseWrapper.__init__()
,
allow_thread_sharing
, is removed.ModelAdmin
classes¶For example, in older versions of Django:
from django.contrib import admin
class BaseAdmin(admin.ModelAdmin):
actions = ['a']
class SubAdmin(BaseAdmin):
actions = ['b']
SubAdmin
would have actions 'a'
and 'b'
.
Now actions
follows standard Python inheritance. To get the same result as
before:
class SubAdmin(BaseAdmin):
actions = BaseAdmin.actions + ['b']
django.contrib.gis
¶TransactionTestCase
serialized data loading¶Initial data migrations are now loaded in
TransactionTestCase
at the end of the test, after the
database flush. In older versions, this data was loaded at the beginning of the
test, but this prevents the test --keepdb
option from working
properly (the database was empty at the end of the whole test suite). This
change shouldn’t have an impact on your tests unless you’ve customized
TransactionTestCase
’s internals.
sqlparse
is required dependency¶To simplify a few parts of Django’s database handling, sqlparse 0.2.2+ is now a required dependency. It’s automatically installed along with Django.
cached_property
aliases¶In usage like:
from django.utils.functional import cached_property
class A:
@cached_property
def base(self):
return ...
alias = base
alias
is not cached. Where the problem can be detected (Python 3.6 and
later), such usage now raises TypeError: Cannot assign the same
cached_property to two different names ('base' and 'alias').
Use this instead:
import operator
class A:
...
alias = property(operator.attrgetter('base'))
Permissions for proxy models are now
created using the content type of the proxy model rather than the content type
of the concrete model. A migration will update existing permissions when you
run migrate
.
In the admin, the change is transparent for proxy models having the same
app_label
as their concrete model. However, in older versions, users with
permissions for a proxy model with a different app_label
than its
concrete model couldn’t access the model in the admin. That’s now fixed, but
you might want to audit the permissions assignments for such proxy models
([add|view|change|delete]_myproxy
) prior to upgrading to ensure the new
access is appropriate.
Finally, proxy model permission strings must be updated to use their own
app_label
. For example, for app.MyProxyModel
inheriting from
other_app.ConcreteModel
, update
user.has_perm('other_app.add_myproxymodel')
to
user.has_perm('app.add_myproxymodel')
.
Media
assets¶Form Media
assets are now merged using a topological sort algorithm, as the
old pairwise merging algorithm is insufficient for some cases. CSS and
JavaScript files which don’t include their dependencies may now be sorted
incorrectly (where the old algorithm produced results correctly by
coincidence).
Audit all Media
classes for any missing dependencies. For example,
widgets depending on django.jQuery
must specify
js=['admin/js/jquery.init.js', ...]
when declaring form media assets.
To improve readability, the UUIDField
form field now displays values with
dashes, e.g. 550e8400-e29b-41d4-a716-446655440000
instead of
550e8400e29b41d4a716446655440000
.
On SQLite, PositiveIntegerField
and PositiveSmallIntegerField
now
include a check constraint to prevent negative values in the database. If you
have existing invalid data and run a migration that recreates a table, you’ll
see CHECK constraint failed
.
For consistency with WSGI servers, the test client now sets the
Content-Length
header to a string rather than an integer.
The return value of django.utils.text.slugify()
is no longer marked as
HTML safe.
The default truncation character used by the urlizetrunc
,
truncatechars
, truncatechars_html
,
truncatewords
, and truncatewords_html
template filters
is now the real ellipsis character (…
) instead of 3 dots. You may have to
adapt some test output comparisons.
Support for bytestring paths in the template filesystem loader is removed.
django.utils.http.urlsafe_base64_encode()
now returns a string instead
of a bytestring, and django.utils.http.urlsafe_base64_decode()
may no
longer be passed a bytestring.
Support for cx_Oracle
< 6.0 is removed.
The minimum supported version of mysqlclient
is increased from 1.3.7 to
1.3.13.
The minimum supported version of SQLite is increased from 3.7.15 to 3.8.3.
In an attempt to provide more semantic query data, NullBooleanSelect
now
renders <option>
values of unknown
, true
, and false
instead
of 1
, 2
, and 3
. For backwards compatibility, the old values are
still accepted as data.
Group.name
max_length
is increased from 80 to 150 characters.
Tests that violate deferrable database constraints now error when run on SQLite 3.20+, just like on other backends that support such constraints.
To catch usage mistakes, the test Client
and
django.utils.http.urlencode()
now raise TypeError
if None
is
passed as a value to encode because None
can’t be encoded in GET and POST
data. Either pass an empty string or omit the value.
The ping_google
management command now defaults to https
instead of http
for the sitemap’s URL. If your site uses http, use the
new ping_google --sitemap-uses-http
option. If you use the
ping_google()
function, set the new
sitemap_uses_https
argument to False
.
runserver
no longer supports pyinotify
(replaced by Watchman).
The Avg
, StdDev
, and
Variance
aggregate functions now return a
Decimal
instead of a float
when the input is Decimal
.
Tests will fail on SQLite if apps without migrations have relations to apps
with migrations. This has been a documented restriction since migrations were
added in Django 1.7, but it fails more reliably now. You’ll see tests failing
with errors like no such table: <app_label>_<model>
. This was observed
with several third-party apps that had models in tests without migrations.
You must add migrations for such models.
Providing an integer in the key
argument of the cache.delete()
or
cache.get()
now raises ValueError
.
Plural equations for some languages are changed, because the latest versions from Transifex are incorporated.
Note
The ability to handle .po
files containing different plural equations
for the same language was added in Django 2.2.12.
Meta.ordering
will no longer affect GROUP BY
queries¶A model’s Meta.ordering
affecting GROUP BY
queries (such as
.annotate().values()
) is a common source of confusion. Such queries now
issue a deprecation warning with the advice to add an order_by()
to retain
the current query. Meta.ordering
will be ignored in such queries starting
in Django 3.1.
django.utils.timezone.FixedOffset
is deprecated in favor of
datetime.timezone
.QuerySetPaginator
alias of
django.core.paginator.Paginator
is deprecated.FloatRangeField
model and form fields in django.contrib.postgres
are deprecated in favor of a new name, DecimalRangeField
, to match the
underlying numrange
data type used in the database.FILE_CHARSET
setting is deprecated. Starting with Django 3.1, files
read from disk must be UTF-8 encoded.django.contrib.staticfiles.storage.CachedStaticFilesStorage
is
deprecated due to the intractable problems that it has. Use
ManifestStaticFilesStorage
or a third-party cloud storage instead.RemoteUserBackend.configure_user()
is now passed request
as the
first positional argument, if it accepts it. Support for overrides that don’t
accept it will be removed in Django 3.1.SimpleTestCase.allow_database_queries
,
TransactionTestCase.multi_db
, and TestCase.multi_db
attributes are deprecated in favor of SimpleTestCase.databases
,
TransactionTestCase.databases
, and TestCase.databases
.
These new attributes allow databases dependencies to be declared in order to
prevent unexpected queries against non-default databases to leak state
between tests. The previous behavior of allow_database_queries=True
and
multi_db=True
can be achieved by setting databases='__all__'
.Jul 28, 2023