NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #537 most downloaded on PyPI
A high-level Python web framework that encourages rapid development and clean, pragmatic design.
Last release 25 days ago
02 Sep 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 54 of the last 60 stable releases
2 versions withdrawn
withdrawn after publishing
16 years old
442 releases · first in 2010
Django 3.1.3 fixes several bugs in 3.1.2 and adds compatibility with Python 3.9.
November 2, 2020
Django 3.1.3 fixes several bugs in 3.1.2 and adds compatibility with Python 3.9.
Fixed a regression in Django 3.1.2 that caused the incorrect height of the admin changelist search bar (32072).
Fixed a regression in Django 3.1.2 that caused the incorrect width of the admin changelist search bar on a filtered page (32091).
Fixed displaying Unicode characters in forms.JSONField and read-only models.JSONField values in the admin (32080).
Fixed a regression in Django 3.1 that caused a crash of ~django.contrib.postgres.aggregates.ArrayAgg and ~django.contrib.postgres.aggregates.StringAgg with ordering on key transforms for ~django.db.models.JSONField (32096).
Fixed a regression in Django 3.1 that caused a crash of __in lookup when using key transforms for ~django.db.models.JSONField in the lookup value (32096).
Fixed a regression in Django 3.1 that caused a crash of ~django.db.models.ExpressionWrapper with key transforms for ~django.db.models.JSONField (32096).
Fixed a regression in Django 3.1 that caused a migrations crash on PostgreSQL when adding an ~django.contrib.postgres.constraints.ExclusionConstraint with key transforms for ~django.db.models.JSONField in expressions (32096).
Fixed a regression in Django 3.1 where ProtectedError.protected_objects and RestrictedError.restricted_objects attributes returned iterators instead of set of objects (32107).
Fixed a regression in Django 3.1.2 that caused incorrect form input layout on small screens in the admin change form view (32069).
Fixed a regression in Django 3.1 that invalidated pre-Django 3.1 password reset tokens (32130).
Added support for asgiref 3.3 (32128).
Fixed a regression in Django 3.1 that caused incorrect textarea layout on medium-sized screens in the admin change form view with the sidebar open (32127).
Fixed a regression in Django 3.0.7 that didn't use Subquery() aliases in the GROUP BY clause (32152).
One column per quarter.
Django 3.1.2 fixes several bugs in 3.1.1.
October 1, 2020
Django 3.1.2 fixes several bugs in 3.1.1.
Fixed a bug in Django 3.1 where FileField instances with a callable storage were not correctly deconstructed (31941).
Fixed a regression in Django 3.1 where the .QuerySet.ordered attribute returned incorrectly True for GROUP BY queries (e.g. .annotate().values()) on models with Meta.ordering. A model's Meta.ordering doesn't affect such queries (31990).
Fixed a regression in Django 3.1 where a queryset would crash if it contained an aggregation and a Q object annotation (32007).
Fixed a bug in Django 3.1 where a test database was not synced during creation when using the MIGRATE test database setting (32012).
Fixed a django.contrib.admin.EmptyFieldListFilter crash when using on a GenericRelation (32038).
Fixed a regression in Django 3.1.1 where the admin changelist filter sidebar would not scroll for a long list of available filters (31986).
CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+
September 1, 2020
Django 3.1.1 fixes two security issues and several bugs in 3.1.
On Python 3.7+, FILE_UPLOAD_DIRECTORY_PERMISSIONS mode was not applied to intermediate-level directories created in the process of uploading files and to intermediate-level collected static directories when using the collectstatic management command.
You should review and manually fix permissions on existing intermediate-level directories.
On Python 3.7+, the intermediate-level directories of the file system cache had the system's standard umask rather than 0o077 (no group or others permissions).
Fixed wrapping of translated action labels in the admin's navigation sidebar for East Asian languages (31853).
Fixed wrapping of long model names in the admin's navigation sidebar (31854).
Fixed encoding session data while upgrading multiple instances of the same project to Django 3.1 (31864).
Adjusted admin's navigation sidebar template to reduce debug logging when rendering (31865).
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using related fields pointing to a proxy model in the of argument, the corresponding model was not locked (31866).
Fixed a data loss possibility, following a regression in Django 2.0, when copying model instances with a cached fields value (31863).
Fixed a regression in Django 3.1 that caused a crash when decoding an invalid session data (31895).
Reverted a deprecation in Django 3.1 that caused a crash when passing deprecated keyword arguments to a queryset in TemplateView.get_context_data() (31877).
Enforced thread sensitivity of the MiddlewareMixin.process_request() and process_response() hooks when in an async context (31905).
Fixed __in lookup on key transforms for ~django.db.models.JSONField with MariaDB, MySQL, Oracle, and SQLite (31936).
Fixed a regression in Django 3.1 that caused permission errors in CommonPasswordValidator and settings.py generated by the startproject command, when user didn't have permissions to all intermediate directories in a Django installation path (31912).
Fixed detecting an async get_response callable in various builtin middlewares (31928).
Fixed a QuerySet.order_by() crash on PostgreSQL when ordering and grouping by ~django.db.models.JSONField with a custom ~django.db.models.JSONField.decoder (31956). As a consequence, fetching a JSONField with raw SQL now returns a string instead of preloaded data. You will need to explicitly call json.loads() in such cases.
Fixed a QuerySet.delete() crash on MySQL, following a performance regression in Django 3.1 on MariaDB 10.3.2+, when filtering against an aggregate function (31965).
Fixed a django.contrib.admin.EmptyFieldListFilter crash when using on reverse relations (31952).
Prevented content overflowing in the admin changelist view when the navigation sidebar is enabled (31901).
- Django 3.1.14 release notes - Django 3.1.13 release notes - Django 3.1.12 release notes - Django 3.1.11 release notes - Django 3.1.10 release notes
Django 3.1.14 release notes
Django 3.1.13 release notes
Django 3.1.12 release notes
Django 3.1.11 release notes
Django 3.1.10 release notes
Django 3.1.9 release notes
Django 3.1.8 release notes
Django 3.1.7 release notes
Django 3.1.6 release notes
Django 3.1.5 release notes
Django 3.1.4 release notes
Django 3.1.3 release notes
Django 3.1.2 release notes
Django 3.1.1 release notes
Django 3.1 release notes
August 4, 2020
Welcome to Django 3.1!
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 3.0 or earlier. We've dropped some features that have reached the end of their deprecation cycle, and we've begun the deprecation process for some features.
See the /howto/upgrade-version guide if you're updating an existing project.
Django 3.1 supports Python 3.6, 3.7, 3.8, and 3.9 (as of 3.1.3). We highly recommend and only officially support the latest release of each series.
Django now supports a fully asynchronous request path, including:
Asynchronous views
Asynchronous middleware
Asynchronous tests and test client
To get started with async views, you need to declare a view using async def:
async def my_view(request):
await asyncio.sleep(0.5)
return HttpResponse("Hello, async world!")
All asynchronous features are supported whether you are running under WSGI or ASGI mode. However, there will be performance penalties using async code in WSGI mode. You can read more about the specifics in /topics/async documentation.
You are free to mix async and sync views, middleware, and tests as much as you want. Django will ensure that you always end up with the right execution context. We expect most projects will keep the majority of their views synchronous, and only have a select few running in async mode - but it is entirely your choice.
Django's ORM, cache layer, and other pieces of code that do long-running network calls do not yet support async access. We expect to add support for them in upcoming releases. Async views are ideal, however, if you are doing a lot of API or HTTP calls inside your view, you can now natively do all those HTTP calls in parallel to considerably speed up your view's execution.
Asynchronous support should be entirely backwards-compatible and we have tried to ensure that it has no speed regressions for your existing, synchronous code. It should have no noticeable effect on any existing Django projects.
Django now includes .models.JSONField and forms.JSONField that can be used on all supported database backends. Both fields support the use of custom JSON encoders and decoders. The model field supports the introspection, lookups, and transforms that were previously PostgreSQL-only:
from django.db import models
class ContactInfo(models.Model):
data = models.JSONField()
ContactInfo.objects.create(
data={
"name": "John",
"cities": ["London", "Cambridge"],
"pets": {"dogs": ["Rufus", "Meg"]},
}
)
ContactInfo.objects.filter(
data__name="John",
data__pets__has_key="dogs",
data__cities__contains="London",
).delete()
If your project uses django.contrib.postgres.fields.JSONField, plus the related form field and transforms, you should adjust to use the new fields, and generate and apply a database migration. For now, the old fields and transforms are left as a reference to the new ones and are deprecated as of this release.
The new DEFAULT_HASHING_ALGORITHM transitional setting allows specifying the default hashing algorithm to use for encoding cookies, password reset tokens in the admin site, user sessions, and signatures created by django.core.signing.Signer and django.core.signing.dumps.
Support for SHA-256 was added in Django 3.1. If you are upgrading multiple instances of the same project to Django 3.1, you should set DEFAULT_HASHING_ALGORITHM to 'sha1' during the transition, in order to allow compatibility with the older versions of Django. Note that this requires Django 3.1.1+. Once the transition to 3.1 is complete you can stop overriding DEFAULT_HASHING_ALGORITHM.
This setting is deprecated as of this release, because support for tokens, cookies, sessions, and signatures that use SHA-1 algorithm will be removed in Django 4.0.
The new django.contrib.admin.EmptyFieldListFilter for .ModelAdmin.list_filter allows filtering on empty values (empty strings and nulls) in the admin changelist view.
Filters in the right sidebar of the admin changelist view now contain a link to clear all filters.
The admin now has a sidebar on larger screens for easier navigation. It is enabled by default but can be disabled by using a custom AdminSite and setting .AdminSite.enable_nav_sidebar to False.
Rendering the sidebar requires access to the current request in order to set CSS and ARIA role affordances. This requires using 'django.template.context_processors.request' in the 'context_processors' option of OPTIONS.
Initially empty extra inlines can now be removed, in the same way as dynamically created ones.
XRegExp is upgraded from version 2.0.0 to 3.2.0.
jQuery is upgraded from version 3.4.1 to 3.5.1.
Select2 library is upgraded from version 4.0.7 to 4.0.13.
The default iteration count for the PBKDF2 password hasher is increased from 180,000 to 216,000.
The new PASSWORD_RESET_TIMEOUT setting allows defining the number of seconds a password reset link is valid for. This is encouraged instead of the deprecated PASSWORD_RESET_TIMEOUT_DAYS setting, which will be removed in Django 4.0.
The password reset mechanism now uses the SHA-256 hashing algorithm. Support for tokens that use the old hashing algorithm remains until Django 4.0.
.AbstractBaseUser.get_session_auth_hash now uses the SHA-256 hashing algorithm. Support for user sessions that use the old hashing algorithm remains until Django 4.0.
The new remove_stale_contenttypes --include-stale-apps option allows removing stale content types from previously installed apps that have been removed from INSTALLED_APPS.
relate lookup is now supported on MariaDB.
Added the .LinearRing.is_counterclockwise property.
~django.contrib.gis.db.models.functions.AsGeoJSON is now supported on Oracle.
Added the ~django.contrib.gis.db.models.functions.AsWKB and ~django.contrib.gis.db.models.functions.AsWKT functions.
Added support for PostGIS 3 and GDAL 3.
intword template filter now supports negative integers.
The new ~django.contrib.postgres.indexes.BloomIndex class allows creating bloom indexes in the database. The new ~django.contrib.postgres.operations.BloomExtension migration operation installs the bloom extension to add support for this index.
~django.db.models.Model.get_FOO_display now supports ~django.contrib.postgres.fields.ArrayField and ~django.contrib.postgres.fields.RangeField.
The new rangefield.lower_inc, rangefield.lower_inf, rangefield.upper_inc, and rangefield.upper_inf lookups allow querying ~django.contrib.postgres.fields.RangeField by a bound type.
rangefield.contained_by now supports ~django.db.models.SmallAutoField, ~django.db.models.AutoField, ~django.db.models.BigAutoField, ~django.db.models.SmallIntegerField, and ~django.db.models.DecimalField.
~django.contrib.postgres.search.SearchQuery now supports 'websearch' search type on PostgreSQL 11+.
SearchQuery.value now supports query expressions.
The new ~django.contrib.postgres.search.SearchHeadline class allows highlighting search results.
search lookup now supports query expressions.
The new cover_density parameter of ~django.contrib.postgres.search.SearchRank allows ranking by cover density.
The new normalization parameter of ~django.contrib.postgres.search.SearchRank allows rank normalization.
The new .ExclusionConstraint.deferrable attribute allows creating deferrable exclusion constraints.
The SESSION_COOKIE_SAMESITE setting now allows 'None' (string) value to explicitly state that the cookie is sent with all same-site and cross-site requests.
The STATICFILES_DIRS setting now supports pathlib.Path.
The ~django.views.decorators.cache.cache_control decorator and ~django.utils.cache.patch_cache_control method now support multiple field names in the no-cache directive for the Cache-Control header, according to 7234#section-5.2.2.2.
~django.core.cache.cache.delete now returns True if the key was successfully deleted, False otherwise.
The CSRF_COOKIE_SAMESITE setting now allows 'None' (string) value to explicitly state that the cookie is sent with all same-site and cross-site requests.
The EMAIL_FILE_PATH setting, used by the file email backend, now supports pathlib.Path.
django.views.debug.SafeExceptionReporterFilter now filters sensitive values from request.META in exception reports.
The new .SafeExceptionReporterFilter.cleansed_substitute and .SafeExceptionReporterFilter.hidden_settings attributes allow customization of sensitive settings and request.META filtering in exception reports.
The technical 404 debug view now respects DEFAULT_EXCEPTION_REPORTER_FILTER when applying settings filtering.
The new DEFAULT_EXCEPTION_REPORTER allows providing a django.views.debug.ExceptionReporter subclass to customize exception report generation. See custom-error-reports for details.
FileSystemStorage.save() method now supports pathlib.Path.
~django.db.models.FileField and ~django.db.models.ImageField now accept a callable for storage. This allows you to modify the used storage at runtime, selecting different storages for different environments, for example.
~django.forms.ModelChoiceIterator, used by ~django.forms.ModelChoiceField and ~django.forms.ModelMultipleChoiceField, now uses ~django.forms.ModelChoiceIteratorValue that can be used by widgets to access model instances. See iterating-relationship-choices for details.
django.forms.DateTimeField now accepts dates in a subset of ISO 8601 datetime formats, including optional timezone, e.g. 2019-10-10T06:47, 2019-10-10T06:47:23+04:00, or 2019-10-10T06:47:23Z. The timezone will always be retained if provided, with timezone-aware datetimes being returned even when USE_TZ is False.
Additionally, DateTimeField now uses DATE_INPUT_FORMATS in addition to DATETIME_INPUT_FORMATS when converting a field input to a datetime value.
.MultiWidget.widgets now accepts a dictionary which allows customizing subwidget name attributes.
The new .BoundField.widget_type property can be used to dynamically adjust form rendering based upon the widget type.
The LANGUAGE_COOKIE_SAMESITE setting now allows 'None' (string) value to explicitly state that the cookie is sent with all same-site and cross-site requests.
Added support and translations for the Algerian Arabic, Igbo, Kyrgyz, Tajik, and Turkmen languages.
The new check --database option allows specifying database aliases for running the database system checks. Previously these checks were enabled for all configured DATABASES by passing the database tag to the command.
The new migrate --check option makes the command exit with a non-zero status when unapplied migrations are detected.
The new returncode argument for ~django.core.management.CommandError allows customizing the exit status for management commands.
The new dbshell -- ARGUMENTS option allows passing extra arguments to the command-line client for the database.
The flush and sqlflush commands now include SQL to reset sequences on SQLite.
The new ~django.db.models.functions.ExtractIsoWeekDay function extracts ISO-8601 week days from ~django.db.models.DateField and ~django.db.models.DateTimeField, and the new iso_week_day lookup allows querying by an ISO-8601 day of week.
.QuerySet.explain now supports:
TREE format on MySQL 8.0.16+,
analyze option on MySQL 8.0.18+ and MariaDB.
Added ~django.db.models.PositiveBigIntegerField which acts much like a ~django.db.models.PositiveIntegerField except that it only allows values under a certain (database-dependent) limit. Values from 0 to 9223372036854775807 are safe in all databases supported by Django.
The new ~django.db.models.RESTRICT option for ~django.db.models.ForeignKey.on_delete argument of ForeignKey and OneToOneField emulates the behavior of the SQL constraint ON DELETE RESTRICT.
CheckConstraint.check now supports boolean expressions.
The .RelatedManager.add, ~.RelatedManager.create, and ~.RelatedManager.set methods now accept callables as values in the through_defaults argument.
The new is_dst parameter of the .QuerySet.datetimes determines the treatment of nonexistent and ambiguous datetimes.
The new ~django.db.models.F expression bitxor() method allows bitwise XOR operation.
.QuerySet.bulk_create now sets the primary key on objects when using MariaDB 10.5+.
The DatabaseOperations.sql_flush() method now generates more efficient SQL on MySQL by using DELETE instead of TRUNCATE statements for tables which don't require resetting sequences.
SQLite functions are now marked as deterministic on Python 3.8+. This allows using them in check constraints and partial indexes.
The new .UniqueConstraint.deferrable attribute allows creating deferrable unique constraints.
~django.core.paginator.Paginator can now be iterated over to yield its pages.
If ALLOWED_HOSTS is empty and DEBUG=True, subdomains of localhost are now allowed in the Host header, e.g. static.localhost.
.HttpResponse.set_cookie and .HttpResponse.set_signed_cookie now allow using samesite='None' (string) to explicitly state that the cookie is sent with all same-site and cross-site requests.
The new .HttpRequest.accepts method returns whether the request accepts the given MIME type according to the Accept HTTP header.
The SECURE_REFERRER_POLICY setting now defaults to 'same-origin'. With this configured, ~django.middleware.security.SecurityMiddleware sets the referrer-policy header to same-origin on all responses that do not already have it. This prevents the Referer header being sent to other origins. If you need the previous behavior, explicitly set SECURE_REFERRER_POLICY to None.
The default algorithm of django.core.signing.Signer, django.core.signing.loads, and django.core.signing.dumps is changed to the SHA-256. Support for signatures made with the old SHA-1 algorithm remains until Django 4.0.
Also, the new algorithm parameter of the ~django.core.signing.Signer allows customizing the hashing algorithm.
The renamed translate and blocktranslate template tags are introduced for internationalization in template code. The older trans and blocktrans template tags aliases continue to work, and will be retained for the foreseeable future.
The include template tag now accepts iterables of template names.
~django.test.SimpleTestCase now implements the debug() method to allow running a test without collecting the result and catching exceptions. This can be used to support running tests under a debugger.
The new MIGRATE test database setting allows disabling of migrations during a test database creation.
~django.test.runner.DiscoverRunner can now discard output for passing tests using the test --buffer option.
~django.test.runner.DiscoverRunner now skips running the system checks on databases not referenced by tests.
~django.test.TransactionTestCase teardown is now faster on MySQL due to flush command improvements. As a side effect the latter doesn't automatically reset sequences on teardown anymore. Enable .TransactionTestCase.reset_sequences if your tests require this feature.
Path converters can now raise ValueError in to_url() to indicate no match when reversing URLs.
~django.utils.encoding.filepath_to_uri now supports pathlib.Path.
~django.utils.dateparse.parse_duration now supports comma separators for decimal fractions in the ISO 8601 format.
~django.utils.dateparse.parse_datetime, ~django.utils.dateparse.parse_duration, and ~django.utils.dateparse.parse_time now support comma separators for milliseconds.
The SQLite backend now supports pathlib.Path for the NAME setting.
The settings.py generated by the startproject command now uses pathlib.Path instead of os.path for building filesystem paths.
The TIME_ZONE setting is now allowed on databases that support time zones.
This section describes changes that may be needed in third-party database backends.
DatabaseOperations.fetch_returned_insert_columns() now requires an additional returning_params argument.
connection.timezone property is now 'UTC' by default, or the TIME_ZONE when USE_TZ is True on databases that support time zones. Previously, it was None on databases that support time zones.
connection._nodb_connection property is changed to the connection._nodb_cursor() method and now returns a context manager that yields a cursor and automatically closes the cursor and connection upon exiting the with statement.
DatabaseClient.runshell() now requires an additional parameters argument as a list of extra arguments to pass on to the command-line client.
The sequences positional argument of DatabaseOperations.sql_flush() is replaced by the boolean keyword-only argument reset_sequences. If True, the sequences of the truncated tables will be reset.
The allow_cascade argument of DatabaseOperations.sql_flush() is now a keyword-only argument.
The using positional argument of DatabaseOperations.execute_sql_flush() is removed. The method now uses the database of the called instance.
Third-party database backends must implement support for JSONField or set DatabaseFeatures.supports_json_field to False. If storing primitives is not supported, set DatabaseFeatures.supports_primitives_in_json_field to False. If there is a true datatype for JSON, set DatabaseFeatures.has_native_json_field to True. If jsonfield.contains and jsonfield.contained_by are not supported, set DatabaseFeatures.supports_json_field_contains to False.
Third party database backends must implement introspection for JSONField or set can_introspect_json_field to False.
Upstream support for MariaDB 10.1 ends in October 2020. Django 3.1 supports MariaDB 10.2 and higher.
The admin no longer supports the legacy Internet Explorer browser. See the admin FAQ for details on supported browsers.
A migration for django.contrib.auth.models.User.first_name is included. If you have a custom user model inheriting from AbstractUser, you'll need to generate and apply a database migration for your user model.
If you want to preserve the 30 character limit for first names, use a custom form:
from django import forms
from django.contrib.auth.forms import UserChangeForm
class MyUserChangeForm(UserChangeForm):
first_name = forms.CharField(max_length=30, required=False)
If you wish to keep this restriction in the admin when editing users, set UserAdmin.form to use this form:
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
The cache keys used by cache and generated by ~django.core.cache.utils.make_template_fragment_key are different from the keys generated by older versions of Django. After upgrading to Django 3.1, the first request to any previously cached template fragment will be a cache miss.
The logic behind the decision to return a redirection fallback or a 204 HTTP response from the ~django.views.i18n.set_language view is now based on the Accept HTTP header instead of the X-Requested-With HTTP header presence.
The compatibility imports of django.core.exceptions.EmptyResultSet in django.db.models.query, django.db.models.sql, and django.db.models.sql.datastructures are removed.
The compatibility import of django.core.exceptions.FieldDoesNotExist in django.db.models.fields is removed.
The compatibility imports of django.forms.utils.pretty_name() and django.forms.boundfield.BoundField in django.forms.forms are removed.
The compatibility imports of Context, ContextPopException, and RequestContext in django.template.base are removed.
The compatibility import of django.contrib.admin.helpers.ACTION_CHECKBOX_NAME in django.contrib.admin is removed.
The STATIC_URL and MEDIA_URL settings set to relative paths are now prefixed by the server-provided value of SCRIPT_NAME (or / if not set). This change should not affect settings set to valid URLs or absolute paths.
~django.middleware.http.ConditionalGetMiddleware no longer adds the ETag header to responses with an empty ~django.http.HttpResponse.content.
django.utils.decorators.classproperty() decorator is made public and moved to django.utils.functional.classproperty.
floatformat template filter now outputs (positive) 0 for negative numbers which round to zero.
Meta.ordering and Meta.unique_together options on models in django.contrib modules that were formerly tuples are now lists.
The admin calendar widget now handles two-digit years according to the Open Group Specification, i.e. values between 69 and 99 are mapped to the previous century, and values between 0 and 68 are mapped to the current century.
Date-only formats are removed from the default list for DATETIME_INPUT_FORMATS.
The ~django.forms.FileInput widget no longer renders with the required HTML attribute when initial data exists.
The undocumented django.views.debug.ExceptionReporterFilter class is removed. As per the custom-error-reports documentation, classes to be used with DEFAULT_EXCEPTION_REPORTER_FILTER need to inherit from django.views.debug.SafeExceptionReporterFilter.
The cache timeout set by ~django.views.decorators.cache.cache_page decorator now takes precedence over the max-age directive from the Cache-Control header.
Providing a non-local remote field in the .ForeignKey.to_field argument now raises ~django.core.exceptions.FieldError.
SECURE_REFERRER_POLICY now defaults to 'same-origin'. See the What's New Security section above for more details.
check management command now runs the database system checks only for database aliases specified using check --database option.
migrate management command now runs the database system checks only for a database to migrate.
The admin CSS classes row1 and row2 are removed in favor of :nth-child(odd) and :nth-child(even) pseudo-classes.
The ~django.contrib.auth.hashers.make_password function now requires its argument to be a string or bytes. Other types should be explicitly cast to one of these.
The undocumented version parameter to the ~django.contrib.gis.db.models.functions.AsKML function is removed.
JSON and YAML serializers, used by dumpdata, now dump all data with Unicode by default. If you need the previous behavior, pass ensure_ascii=True to JSON serializer, or allow_unicode=False to YAML serializer.
The auto-reloader no longer monitors changes in built-in Django translation files.
The minimum supported version of mysqlclient is increased from 1.3.13 to 1.4.0.
The undocumented django.contrib.postgres.forms.InvalidJSONInput and django.contrib.postgres.forms.JSONString are moved to django.forms.fields.
The undocumented django.contrib.postgres.fields.jsonb.JsonAdapter class is removed.
The {% localize off %} tag and unlocalize filter no longer respect DECIMAL_SEPARATOR setting.
The minimum supported version of asgiref is increased from 3.2 to 3.2.10.
The Media class now renders <script> tags without the type attribute to follow WHATWG recommendations.
~django.forms.ModelChoiceIterator, used by ~django.forms.ModelChoiceField and ~django.forms.ModelMultipleChoiceField, now yields 2-tuple choices containing ~django.forms.ModelChoiceIteratorValue instances as the first value element in each choice. In most cases this proxies transparently, but if you need the field value itself, use the .ModelChoiceIteratorValue.value attribute instead.
django.contrib.postgres.fields.JSONField and django.contrib.postgres.forms.JSONField are deprecated in favor of .models.JSONField and forms.JSONField.
The undocumented django.contrib.postgres.fields.jsonb.KeyTransform and django.contrib.postgres.fields.jsonb.KeyTextTransform are also deprecated in favor of the transforms in django.db.models.fields.json.
The new JSONFields, KeyTransform, and KeyTextTransform can be used on all supported database backends.
PASSWORD_RESET_TIMEOUT_DAYS setting is deprecated in favor of PASSWORD_RESET_TIMEOUT.
The undocumented usage of the isnull lookup with non-boolean values as the right-hand side is deprecated, use True or False instead.
The barely documented django.db.models.query_utils.InvalidQuery exception class is deprecated in favor of ~django.core.exceptions.FieldDoesNotExist and ~django.core.exceptions.FieldError.
The django-admin.py entry point is deprecated in favor of django-admin.
The HttpRequest.is_ajax() method is deprecated as it relied on a jQuery-specific way of signifying AJAX calls, while current usage tends to use the JavaScript Fetch API. Depending on your use case, you can either write your own AJAX detection method, or use the new .HttpRequest.accepts method if your code depends on the client Accept HTTP header.
If you are writing your own AJAX detection method, request.is_ajax() can be reproduced exactly as request.headers.get('x-requested-with') == 'XMLHttpRequest'.
Passing None as the first argument to django.utils.deprecation.MiddlewareMixin.__init__() is deprecated.
The encoding format of cookies values used by ~django.contrib.messages.storage.cookie.CookieStorage is different from the format generated by older versions of Django. Support for the old format remains until Django 4.0.
The encoding format of sessions is different from the format generated by older versions of Django. Support for the old format remains until Django 4.0.
The purely documentational providing_args argument for ~django.dispatch.Signal is deprecated. If you rely on this argument as documentation, you can move the text to a code comment or docstring.
Calling django.utils.crypto.get_random_string() without a length argument is deprecated.
The list message for ~django.forms.ModelMultipleChoiceField is deprecated in favor of invalid_list.
Passing raw column aliases to .QuerySet.order_by is deprecated. The same result can be achieved by passing aliases in a ~django.db.models.expressions.RawSQL instead beforehand.
The NullBooleanField model field is deprecated in favor of BooleanField(null=True, blank=True).
django.conf.urls.url() alias of django.urls.re_path is deprecated.
The {% ifequal %} and {% ifnotequal %} template tags are deprecated in favor of {% if %}. {% if %} covers all use cases, but if you need to continue using these tags, they can be extracted from Django to a module and included as a built-in tag in the 'builtins' option in OPTIONS.
DEFAULT_HASHING_ALGORITHM transitional setting is deprecated.
These features have reached the end of their deprecation cycle and are removed in Django 3.1.
See deprecated-features-2.2 for details on these changes, including how to remove usage of these features.
django.utils.timezone.FixedOffset is removed.
django.core.paginator.QuerySetPaginator is removed.
A model's Meta.ordering doesn't affect GROUP BY queries.
django.contrib.postgres.fields.FloatRangeField and django.contrib.postgres.forms.FloatRangeField are removed.
The FILE_CHARSET setting is removed.
django.contrib.staticfiles.storage.CachedStaticFilesStorage is removed.
The RemoteUserBackend.configure_user() method requires request as the first positional argument.
Support for SimpleTestCase.allow_database_queries and TransactionTestCase.multi_db is removed.
Nothing published for this version
Nothing published for this version
Nothing published for this version
CVE-2021-28658: Potential directory-traversal via uploaded files
April 6, 2021
Django 3.0.14 fixes a security issue with severity "low" in 3.0.13.
MultiPartParser allowed directory-traversal via uploaded files with
suitably crafted file names.
Built-in upload handlers were not affected by this vulnerability.
CVE-2021-23336: Web cache poisoning via django.utils.http.limited_parse_qsl()
February 19, 2021
Django 3.0.13 fixes a security issue in 3.0.12.
Django contains a copy of urllib.parse.parse_qsl which was added to backport some security fixes. A further security fix has been issued recently such that parse_qsl() no longer allows using ; as a query parameter separator by default. Django now includes this fix. See 42967 for further details.
CVE-2021-3281: Potential directory-traversal via archive.extract()
February 1, 2021
Django 3.0.12 fixes a security issue with severity "low" in 3.0.11.
The django.utils.archive.extract() function, used by startapp --template and startproject --template, allowed directory-traversal via an archive with absolute paths or relative paths with dot segments.
Django 3.0.11 fixes a regression in 3.0.7 and adds compatibility with Python 3.9.
November 2, 2020
Django 3.0.11 fixes a regression in 3.0.7 and adds compatibility with Python 3.9.
Subquery() aliases in
the GROUP BY clause (:ticket:32152).CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+
September 1, 2020
Django 3.0.10 fixes two security issues and two data loss bugs in 3.0.9.
On Python 3.7+, FILE_UPLOAD_DIRECTORY_PERMISSIONS mode was not applied to intermediate-level directories created in the process of uploading files and to intermediate-level collected static directories when using the collectstatic management command.
You should review and manually fix permissions on existing intermediate-level directories.
On Python 3.7+, the intermediate-level directories of the file system cache had the system's standard umask rather than 0o077 (no group or others permissions).
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using related fields pointing to a proxy model in the of argument, the corresponding model was not locked (31866).
Fixed a data loss possibility, following a regression in Django 2.0, when copying model instances with a cached fields value (31863).
Django 3.0.9 fixes several bugs in 3.0.8.
August 3, 2020
Django 3.0.9 fixes several bugs in 3.0.8.
Allowed setting the SameSite cookie flag in .HttpResponse.delete_cookie (31790).
Fixed crash when sending emails to addresses with display names longer than 75 chars on Python 3.6.11+, 3.7.8+, and 3.8.4+ (31784).
Django 3.0.8 fixes several bugs in 3.0.7.
July 1, 2020
Django 3.0.8 fixes several bugs in 3.0.7.
Fixed messages of InvalidCacheKey exceptions and CacheKeyWarning
warnings raised by cache key validation (:ticket:31654).
Fixed a regression in Django 3.0.7 that caused a queryset crash when grouping
by a many-to-one relationship (:ticket:31660).
Reallowed, following a regression in Django 3.0, non-expressions having a
filterable attribute to be used as the right-hand side in queryset
filters (:ticket:31664).
Fixed a regression in Django 3.0.2 that caused a migration crash on
PostgreSQL when adding a foreign key to a model with a namespaced
db_table (:ticket:31735).
Added compatibility for cx_Oracle 8 (:ticket:31751).
CVE-2020-13254: Potential data leakage via malformed memcached keys
June 3, 2020
Django 3.0.7 fixes two security issues and several bugs in 3.0.6.
In cases where a memcached backend does not perform key validation, passing malformed cache keys could result in a key collision, and potential data leakage. In order to avoid this vulnerability, key validation is added to the memcached cache backends.
ForeignKeyRawIdWidgetQuery parameters for the admin ForeignKeyRawIdWidget were not properly URL
encoded, posing an XSS attack vector. ForeignKeyRawIdWidget now
ensures query parameters are correctly URL encoded.
Fixed a regression in Django 3.0 by restoring the ability to use field
lookups in Meta.ordering (:ticket:31538).
Fixed a regression in Django 3.0 where QuerySet.values() and
values_list() crashed if a queryset contained an aggregation and a
subquery annotation (:ticket:31566).
Fixed a regression in Django 3.0 where aggregates used wrong annotations when
a queryset has multiple subqueries annotations (:ticket:31568).
Fixed a regression in Django 3.0 where QuerySet.values() and
values_list() crashed if a queryset contained an aggregation and an
Exists() annotation on Oracle (:ticket:31584).
Fixed a regression in Django 3.0 where all resolved Subquery()
expressions were considered equal (:ticket:31607).
Fixed a regression in Django 3.0.5 that affected translation loading for apps
providing translations for territorial language variants as well as a generic
language, where the project has different plural equations for the language
(:ticket:31570).
Tracking a jQuery security release, upgraded the version of jQuery used by the admin from 3.4.1 to 3.5.1.
Django 3.0.6 fixes a bug in 3.0.5.
May 4, 2020
Django 3.0.6 fixes a bug in 3.0.5.
Subquery() annotation of a queryset containing a single related field
against a SimpleLazyObject (:ticket:31420).Django 3.0.5 fixes several bugs in 3.0.4.
April 1, 2020
Django 3.0.5 fixes several bugs in 3.0.4.
Added the ability to handle .po files containing different plural
equations for the same language (:ticket:30439).
Fixed a regression in Django 3.0 where QuerySet.values() and
values_list() crashed if a queryset contained an aggregation and
Subquery() annotation that collides with a field name (:ticket:31377).
CVE-2020-9402: Potential SQL injection via tolerance parameter in GIS functions and aggregates on Oracle
March 4, 2020
Django 3.0.4 fixes a security issue and several bugs in 3.0.3.
GIS functions and aggregates on Oracle were subject to SQL injection, using a suitably crafted tolerance.
Fixed a data loss possibility when using caching from async code (31253).
Fixed a regression in Django 3.0 that caused a file response using a temporary file to be closed incorrectly (31240).
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using related fields or parent link fields with multi-table-inheritance in the of argument, the corresponding models were not locked (31246).
Fixed a regression in Django 3.0 that caused misplacing parameters in logged SQL queries on Oracle (31271).
Fixed a regression in Django 3.0.3 that caused misplacing parameters of SQL queries when subtracting DateField or DateTimeField expressions on MySQL (31312).
Fixed a regression in Django 3.0 that didn't include subqueries spanning multivalued relations in the GROUP BY clause (31150).
CVE-2020-7471: Potential SQL injection via StringAgg(delimiter)
February 3, 2020
Django 3.0.3 fixes a security issue and several bugs in 3.0.2.
~django.contrib.postgres.aggregates.StringAgg aggregation function was subject to SQL injection, using a suitably crafted delimiter.
Fixed a regression in Django 3.0 that caused a crash when subtracting DateField, DateTimeField, or TimeField from a Subquery() annotation (31133).
Fixed a regression in Django 3.0 where QuerySet.values() and values_list() crashed if a queryset contained an aggregation and Exists() annotation (31136).
Relaxed the system check added in Django 3.0 to reallow use of a sublanguage in the LANGUAGE_CODE setting, when a base language is available in Django but the sublanguage is not (31141).
Added support for using enumeration types TextChoices, IntegerChoices, and Choices in templates (31154).
Fixed a system check to ensure the max_length attribute fits the longest choice, when a named group contains only non-string values (31155).
Fixed a regression in Django 2.2 that caused a crash of ~django.contrib.postgres.aggregates.ArrayAgg and ~django.contrib.postgres.aggregates.StringAgg with filter argument when used in a Subquery (31097).
Fixed a regression in Django 2.2.7 that caused ~django.db.models.Model.get_FOO_display to work incorrectly when overriding inherited choices (31124).
Fixed a regression in Django 3.0 that caused a crash of QuerySet.prefetch_related() for GenericForeignKey with a custom ContentType foreign key (31190).
Django 3.0.2 fixes several bugs in 3.0.1.
January 2, 2020
Django 3.0.2 fixes several bugs in 3.0.1.
Fixed a regression in Django 3.0 that didn't include columns referenced by a Subquery() in the GROUP BY clause (31094).
Fixed a regression in Django 3.0 where QuerySet.exists() crashed if a queryset contained an aggregation over a Subquery() (31109).
Fixed a regression in Django 3.0 that caused a migration crash on PostgreSQL 10+ when adding a foreign key and changing data in the same migration (31106).
Fixed a regression in Django 3.0 where loading fixtures crashed for models defining a ~django.db.models.Field.default for the primary key (31071).
CVE-2019-19844: Potential account hijack via password reset form
December 18, 2019
Django 3.0.1 fixes a security issue and several bugs in 3.0.
By submitting a suitably crafted email address making use of Unicode characters, that compared equal to an existing user email when lower-cased for comparison, an attacker could be sent a password reset token for the matched account.
In order to avoid this vulnerability, password reset requests now compare the submitted email using the stricter, recommended algorithm for case-insensitive comparison of two identifiers from Unicode Technical Report 36, section 2.11.2(B)(2). Upon a match, the email containing the reset token will be sent to the email address on record rather than the submitted address.
Fixed a regression in Django 3.0 by restoring the ability to use Django inside Jupyter and other environments that force an async context, by adding an option to disable async-safety mechanism with DJANGO_ALLOW_ASYNC_UNSAFE environment variable (31056).
Fixed a regression in Django 3.0 where RegexPattern, used by ~django.urls.re_path, returned positional arguments to be passed to the view when all optional named groups were missing (31061).
Reallowed, following a regression in Django 3.0, ~django.db.models.expressions.Window expressions to be used in conditions outside of queryset filters, e.g. in ~django.db.models.expressions.When conditions (31060).
Fixed a data loss possibility in ~django.contrib.postgres.forms.SplitArrayField. When using with ArrayField(BooleanField()), all values after the first True value were marked as checked instead of preserving passed values (31073).
- Django 3.0.14 release notes - Django 3.0.13 release notes - Django 3.0.12 release notes - Django 3.0.11 release notes - Django 3.0.10 release notes
Django 3.0.14 release notes
Django 3.0.13 release notes
Django 3.0.12 release notes
Django 3.0.11 release notes
Django 3.0.10 release notes
Django 3.0.9 release notes
Django 3.0.8 release notes
Django 3.0.7 release notes
Django 3.0.6 release notes
Django 3.0.5 release notes
Django 3.0.4 release notes
Django 3.0.3 release notes
Django 3.0.2 release notes
Django 3.0.1 release notes
Django 3.0 release notes
December 2, 2019
Welcome to Django 3.0!
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.2 or earlier. We've dropped some features that have reached the end of their deprecation cycle, and we've begun the deprecation process for some features.
See the /howto/upgrade-version guide if you're updating an existing project.
Django 3.0 supports Python 3.6, 3.7, 3.8, and 3.9 (as of 3.0.11). We highly recommend and only officially support the latest release of each series.
The Django 2.2.x series is the last to support Python 3.5.
Following the release of Django 3.0, we suggest that third-party app authors drop support for all versions of Django prior to 2.2. At that time, you should be able to run your package's tests using python -Wd so that deprecation warnings appear. After making the deprecation warning fixes, your app should be compatible with Django 3.0.
Django now officially supports MariaDB 10.1 and higher. See MariaDB notes for more details.
Django 3.0 begins our journey to making Django fully async-capable by providing support for running as an ASGI application.
This is in addition to our existing WSGI support. Django intends to support both for the foreseeable future. Async features will only be available to applications that run under ASGI, however.
At this stage async support only applies to the outer ASGI application. Internally everything remains synchronous. Asynchronous middleware, views, etc. are not yet supported. You can, however, use ASGI middleware around Django's application, allowing you to combine Django with other ASGI frameworks.
There is no need to switch your applications over unless you want to start experimenting with asynchronous code, but we have documentation on deploying with ASGI if you want to learn more.
Note that as a side-effect of this change, Django is now aware of asynchronous event loops and will block you calling code marked as "async unsafe" - such as ORM operations - from an asynchronous context. If you were using Django from async code before, this may trigger if you were doing it incorrectly. If you see a SynchronousOnlyOperation error, then closely examine your code and move any database operations to be in a synchronous child thread.
The new ~django.contrib.postgres.constraints.ExclusionConstraint class enable adding exclusion constraints on PostgreSQL. Constraints are added to models using the Meta.constraints option.
Expressions that output ~django.db.models.BooleanField may now be used directly in QuerySet filters, without having to first annotate and then filter against the annotation.
Custom enumeration types TextChoices, IntegerChoices, and Choices are now available as a way to define .Field.choices. TextChoices and IntegerChoices types are provided for text and integer fields. The Choices class allows defining a compatible enumeration for other concrete data types. These custom enumeration types support human-readable labels that can be translated and accessed via a property on the enumeration or its members. See Enumeration types for more details and examples.
Added support for the admin_order_field attribute on properties in .ModelAdmin.list_display.
The new ModelAdmin.get_inlines() method allows specifying the inlines based on the request or model instance.
Select2 library is upgraded from version 4.0.3 to 4.0.7.
jQuery is upgraded from version 3.3.1 to 3.4.1.
The new reset_url_token attribute in ~django.contrib.auth.views.PasswordResetConfirmView allows specifying a token parameter displayed as a component of password reset URLs.
Added ~django.contrib.auth.backends.BaseBackend class to ease customization of authentication backends.
Added ~django.contrib.auth.models.User.get_user_permissions method to mirror the existing ~django.contrib.auth.models.User.get_group_permissions method.
Added HTML autocomplete attribute to widgets of username, email, and password fields in django.contrib.auth.forms for better interaction with browser password managers.
createsuperuser now falls back to environment variables for password and required fields, when a corresponding command line argument isn't provided in non-interactive mode.
~django.contrib.auth.models.CustomUser.REQUIRED_FIELDS now supports ~django.db.models.ManyToManyFields.
The new .UserManager.with_perm method returns users that have the specified permission.
The default iteration count for the PBKDF2 password hasher is increased from 150,000 to 180,000.
Allowed MySQL spatial lookup functions to operate on real geometries. Previous support was limited to bounding boxes.
Added the ~django.contrib.gis.db.models.functions.GeometryDistance function, supported on PostGIS.
Added support for the furlong unit in ~django.contrib.gis.measure.Distance.
The GEOIP_PATH setting now supports pathlib.Path.
The ~django.contrib.gis.geoip2.GeoIP2 class now accepts pathlib.Path path.
The new ~django.contrib.postgres.fields.RangeOperators helps to avoid typos in SQL operators that can be used together with ~django.contrib.postgres.fields.RangeField.
The new ~django.contrib.postgres.fields.RangeBoundary expression represents the range boundaries.
The new ~django.contrib.postgres.operations.AddIndexConcurrently and ~django.contrib.postgres.operations.RemoveIndexConcurrently classes allow creating and dropping indexes CONCURRENTLY on PostgreSQL.
The new ~django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age method allows dynamically specifying the session cookie age.
Added the language class attribute to the django.contrib.syndication.views.Feed to customize a feed language. The default value is ~django.utils.translation.get_language instead of LANGUAGE_CODE.
~django.utils.cache.add_never_cache_headers and ~django.views.decorators.cache.never_cache now add the private directive to Cache-Control headers.
The new .Storage.get_alternative_name method allows customizing the algorithm for generating filenames if a file with the uploaded name already exists.
Formsets may control the widget used when ordering forms via ~django.forms.formsets.BaseFormSet.can_order by setting the ~django.forms.formsets.BaseFormSet.ordering_widget attribute or overriding ~django.forms.formsets.BaseFormSet.get_ordering_widget.
Added the LANGUAGE_COOKIE_HTTPONLY, LANGUAGE_COOKIE_SAMESITE, and LANGUAGE_COOKIE_SECURE settings to set the HttpOnly, SameSite, and Secure flags on language cookies. The default values of these settings preserve the previous behavior.
Added support and translations for the Uzbek language.
The new reporter_class parameter of ~django.utils.log.AdminEmailHandler allows providing an django.views.debug.ExceptionReporter subclass to customize the traceback text sent to site ADMINS when DEBUG is False.
The new compilemessages --ignore option allows ignoring specific directories when searching for .po files to compile.
showmigrations --list now shows the applied datetimes when --verbosity is 2 and above.
On PostgreSQL, dbshell now supports client-side TLS certificates.
inspectdb now introspects ~django.db.models.OneToOneField when a foreign key has a unique or primary key constraint.
The new --skip-checks option skips running system checks prior to running the command.
The startapp --template and startproject --template options now support templates stored in XZ archives (.tar.xz, .txz) and LZMA archives (.tar.lzma, .tlz).
Added hash database functions ~django.db.models.functions.MD5, ~django.db.models.functions.SHA1, ~django.db.models.functions.SHA224, ~django.db.models.functions.SHA256, ~django.db.models.functions.SHA384, and ~django.db.models.functions.SHA512.
Added the ~django.db.models.functions.Sign database function.
The new is_dst parameter of the ~django.db.models.functions.Trunc database functions determines the treatment of nonexistent and ambiguous datetimes.
connection.queries now shows COPY … TO statements on PostgreSQL.
~django.db.models.FilePathField now accepts a callable for path.
Allowed symmetrical intermediate table for self-referential ~django.db.models.ManyToManyField.
The name attributes of ~django.db.models.CheckConstraint, ~django.db.models.UniqueConstraint, and ~django.db.models.Index now support app label and class interpolation using the '%(app_label)s' and '%(class)s' placeholders.
The new .Field.descriptor_class attribute allows model fields to customize the get and set behavior by overriding their descriptors.
~django.db.models.Avg and ~django.db.models.Sum now support the distinct argument.
Added ~django.db.models.SmallAutoField which acts much like an ~django.db.models.AutoField except that it only allows values under a certain (database-dependent) limit. Values from 1 to 32767 are safe in all databases supported by Django.
~django.db.models.AutoField, ~django.db.models.BigAutoField, and ~django.db.models.SmallAutoField now inherit from IntegerField, BigIntegerField and SmallIntegerField respectively. System checks and validators are now also properly inherited.
.FileField.upload_to now supports pathlib.Path.
~django.db.models.CheckConstraint is now supported on MySQL 8.0.16+.
The new allows_group_by_selected_pks_on_model() method of django.db.backends.base.BaseDatabaseFeatures allows optimization of GROUP BY clauses to require only the selected models' primary keys. By default, it's supported only for managed models on PostgreSQL.
To enable the GROUP BY primary key-only optimization for unmanaged models, you have to subclass the PostgreSQL database engine, overriding the features class allows_group_by_selected_pks_on_model() method as you require. See Subclassing the built-in database backends for an example.
Allowed ~django.http.HttpResponse to be initialized with memoryview content.
For use in, for example, Django templates, .HttpRequest.headers now allows lookups using underscores (e.g. user_agent) in place of hyphens.
X_FRAME_OPTIONS now defaults to 'DENY'. In older versions, the X_FRAME_OPTIONS setting defaults to 'SAMEORIGIN'. If your site uses frames of itself, you will need to explicitly set X_FRAME_OPTIONS = 'SAMEORIGIN' for them to continue working.
SECURE_CONTENT_TYPE_NOSNIFF now defaults to True. With this enabled, ~django.middleware.security.SecurityMiddleware sets the x-content-type-options header on all responses that do not already have it.
~django.middleware.security.SecurityMiddleware can now send the Referrer-Policy header.
The new test ~django.test.Client argument raise_request_exception allows controlling whether or not exceptions raised during the request should also be raised in the test. The value defaults to True for backwards compatibility. If it is False and an exception occurs, the test client will return a 500 response with the attribute ~django.test.Response.exc_info, a tuple providing information of the exception that occurred.
Tests and test cases to run can be selected by test name pattern using the new test -k option.
HTML comparison, as used by ~django.test.SimpleTestCase.assertHTMLEqual, now treats text, character references, and entity references that refer to the same character as equivalent.
~django.test.runner.DiscoverRunner can now spawn a debugger at each error or failure using the test --pdb option.
.Model.save no longer attempts to find a row when saving a new Model instance and a default value for the primary key is provided, and always performs a single INSERT query. In older Django versions, Model.save() performed either an INSERT or an UPDATE based on whether or not the row exists.
This makes calling Model.save() while providing a default primary key value equivalent to passing force_insert=True to model's save(). Attempts to use a new Model instance to update an existing row will result in an IntegrityError.
In order to update an existing model for a specific primary key value, use the ~django.db.models.query.QuerySet.update_or_create method or QuerySet.filter(pk=…).update(…) instead. For example:
>>> MyModel.objects.update_or_create(pk=existing_pk, defaults={"name": "new name"})
>>> MyModel.objects.filter(pk=existing_pk).update(name="new name")
This section describes changes that may be needed in third-party database backends.
The second argument of DatabaseIntrospection.get_geometry_type() is now the row description instead of the column name.
DatabaseIntrospection.get_field_type() may no longer return tuples.
If the database can create foreign keys in the same SQL statement that adds a field, add SchemaEditor.sql_create_column_inline_fk with the appropriate SQL; otherwise, set DatabaseFeatures.can_create_inline_fk = False.
DatabaseFeatures.can_return_id_from_insert and can_return_ids_from_bulk_insert are renamed to can_return_columns_from_insert and can_return_rows_from_bulk_insert.
Database functions now handle datetime.timezone formats when created using datetime.timedelta instances (e.g. timezone(timedelta(hours=5)), which would output 'UTC+05:00'). Third-party backends should handle this format when preparing ~django.db.models.DateTimeField in datetime_cast_date_sql(), datetime_extract_sql(), etc.
Entries for AutoField, BigAutoField, and SmallAutoField are added to DatabaseOperations.integer_field_ranges to support the integer range validators on these field types. Third-party backends may need to customize the default entries.
DatabaseOperations.fetch_returned_insert_id() is replaced by fetch_returned_insert_columns() which returns a list of values returned by the INSERT … RETURNING statement, instead of a single value.
DatabaseOperations.return_insert_id() is replaced by return_insert_columns() that accepts a fields argument, which is an iterable of fields to be returned after insert. Usually this is only the auto-generated primary key.
Admin's model history change messages now prefers more readable field labels instead of field names.
Support for PostGIS 2.1 is removed.
Support for SpatiaLite 4.1 and 4.2 is removed.
Support for GDAL 1.11 and GEOS 3.4 is removed.
Upstream support for PostgreSQL 9.4 ends in December 2019. Django 3.0 supports PostgreSQL 9.5 and higher.
Upstream support for Oracle 12.1 ends in July 2021. Django 2.2 will be supported until April 2022. Django 3.0 officially supports Oracle 12.2 and 18c.
While Python 2 support was removed in Django 2.0, some private APIs weren't removed from Django so that third party apps could continue using them until the Python 2 end-of-life.
Since we expect apps to drop Python 2 compatibility when adding support for Django 3.0, we're removing these APIs at this time.
django.test.utils.str_prefix() - Strings don't have 'u' prefixes in Python 3.
django.test.utils.patch_logger() - Use unittest.TestCase.assertLogs instead.
django.utils.lru_cache.lru_cache() - Alias of functools.lru_cache.
django.utils.decorators.available_attrs() - This function returns functools.WRAPPER_ASSIGNMENTS.
django.utils.decorators.ContextDecorator - Alias of contextlib.ContextDecorator.
django.utils._os.abspathu() - Alias of os.path.abspath.
django.utils._os.upath() and npath() - These functions do nothing on Python 3.
django.utils.six - Remove usage of this vendored library or switch to six.
django.utils.encoding.python_2_unicode_compatible() - Alias of six.python_2_unicode_compatible().
django.utils.functional.curry() - Use functools.partial or functools.partialmethod. See 5b1c389603a353625ae1603ba345147356336afb.
django.utils.safestring.SafeBytes - Unused since Django 2.0.
In older versions, the FILE_UPLOAD_PERMISSIONS setting defaults to None. With the default FILE_UPLOAD_HANDLERS, this results in uploaded files having different permissions depending on their size and which upload handler is used.
FILE_UPLOAD_PERMISSIONS now defaults to 0o644 to avoid this inconsistency.
To make Django projects more secure by default, some security settings now have more secure default values:
X_FRAME_OPTIONS now defaults to 'DENY'.
SECURE_CONTENT_TYPE_NOSNIFF now defaults to True.
See the What's New Security section above for more details on these changes.
ContentType.__str__() now includes the model's app_label to disambiguate models with the same name in different apps.
Because accessing the language in the session rather than in the cookie is deprecated, LocaleMiddleware no longer looks for the user's language in the session and django.contrib.auth.logout no longer preserves the session's language after logout.
django.utils.html.escape now uses html.escape to escape HTML. This converts ' to ' instead of the previous equivalent decimal code '.
The django-admin test -k option now works as the unittest -k option rather than as a shortcut for --keepdb.
Support for pywatchman < 1.2.0 is removed.
~django.utils.http.urlencode now encodes iterable values as they are when doseq=False, rather than iterating them, bringing it into line with the standard library urllib.parse.urlencode function.
intword template filter now translates 1.0 as a singular phrase and all other numeric values as plural. This may be incorrect for some languages.
Assigning a value to a model's ~django.db.models.ForeignKey or ~django.db.models.OneToOneField '_id' attribute now unsets the corresponding field. Accessing the field afterward will result in a query.
~django.utils.cache.patch_vary_headers now handles an asterisk '*' according to 7231#section-7.1.4, i.e. if a list of header field names contains an asterisk, then the Vary header will consist of a single asterisk '*'.
On MySQL 8.0.16+, PositiveIntegerField and PositiveSmallIntegerField now include a check constraint to prevent negative values in the database.
alias=None is added to the signature of .Expression.get_group_by_cols.
RegexPattern, used by ~django.urls.re_path, no longer returns keyword arguments with None values to be passed to the view for the optional named groups that are missing.
The smart_text() and force_text() aliases (since Django 2.0) of smart_str() and force_str() are deprecated. Ignore this deprecation if your code supports Python 2 as the behavior of smart_str() and force_str() is different there.
django.utils.http.urlquote(), urlquote_plus(), urlunquote(), and urlunquote_plus() are deprecated in favor of the functions that they're aliases for: urllib.parse.quote, ~urllib.parse.quote_plus, ~urllib.parse.unquote, and ~urllib.parse.unquote_plus.
django.utils.translation.ugettext(), ugettext_lazy(), ugettext_noop(), ungettext(), and ungettext_lazy() are deprecated in favor of the functions that they're aliases for: django.utils.translation.gettext, ~django.utils.translation.gettext_lazy, ~django.utils.translation.gettext_noop, ~django.utils.translation.ngettext, and ~django.utils.translation.ngettext_lazy.
To limit creation of sessions and hence favor some caching strategies, django.views.i18n.set_language will stop setting the user's language in the session in Django 4.0. Since Django 2.1, the language is always stored in the LANGUAGE_COOKIE_NAME cookie.
django.utils.text.unescape_entities() is deprecated in favor of html.unescape. Note that unlike unescape_entities(), html.unescape() evaluates lazy strings immediately.
To avoid possible confusion as to effective scope, the private internal utility is_safe_url() is renamed to url_has_allowed_host_and_scheme(). That a URL has an allowed host and scheme doesn't in general imply that it's "safe". It may still be quoted incorrectly, for example. Ensure to also use ~django.utils.encoding.iri_to_uri on the path component of untrusted URLs.
These features have reached the end of their deprecation cycle and are removed in Django 3.0.
See deprecated-features-2.0 for details on these changes, including how to remove usage of these features.
The django.db.backends.postgresql_psycopg2 module is removed.
django.shortcuts.render_to_response() is removed.
The DEFAULT_CONTENT_TYPE setting is removed.
HttpRequest.xreadlines() is removed.
Support for the context argument of Field.from_db_value() and Expression.convert_value() is removed.
The field_name keyword argument of QuerySet.earliest() and latest() is removed.
See deprecated-features-2.1 for details on these changes, including how to remove usage of these features.
The ForceRHR GIS function is removed.
django.utils.http.cookie_date() is removed.
The staticfiles and admin_static template tag libraries are removed.
django.contrib.staticfiles.templatetags.staticfiles.static() is removed.
Nothing published for this version
Nothing published for this version
Nothing published for this version
CVE-2022-28346: Potential SQL injection in QuerySet.annotate(), aggregate(), and extra()
April 11, 2022
Django 2.2.28 fixes two security issues with severity "high" in 2.2.27.
.QuerySet.annotate, ~.QuerySet.aggregate, and ~.QuerySet.extra methods were subject to SQL injection in column aliases, using a suitably crafted dictionary, with dictionary expansion, as the **kwargs passed to these methods.
.QuerySet.explain method was subject to SQL injection in option names, using a suitably crafted dictionary, with dictionary expansion, as the **options argument.
CVE-2022-22818: Possible XSS via {% debug %} template tag
February 1, 2022
Django 2.2.27 fixes two security issues with severity "medium" in 2.2.26.
{% debug %} template tagThe {% debug %} template tag didn't properly encode the current context,
posing an XSS attack vector.
In order to avoid this vulnerability, {% debug %} no longer outputs
information when the DEBUG setting is False, and it ensures all context
variables are correctly escaped when the DEBUG setting is True.
Passing certain inputs to multipart forms could result in an infinite loop when parsing files.
CVE-2021-45115: Denial-of-service possibility in UserAttributeSimilarityValidator
January 4, 2022
Django 2.2.26 fixes one security issue with severity "medium" and two security issues with severity "low" in 2.2.25.
.UserAttributeSimilarityValidator incurred significant overhead evaluating submitted password that were artificially large in relative to the comparison values. On the assumption that access to user registration was unrestricted this provided a potential vector for a denial-of-service attack.
In order to mitigate this issue, relatively long values are now ignored by UserAttributeSimilarityValidator.
This issue has severity "medium" according to the Django security policy.
Due to leveraging the Django Template Language's variable resolution logic, the dictsort template filter was potentially vulnerable to information disclosure or unintended method calls, if passed a suitably crafted key.
In order to avoid this possibility, dictsort now works with a restricted resolution logic, that will not call methods, nor allow indexing on dictionaries.
As a reminder, all untrusted user input should be validated before use.
This issue has severity "low" according to the Django security policy.
Storage.save() allowed directory-traversal if directly passed suitably crafted file names.
This issue has severity "low" according to the Django security policy.
CVE-2021-44420: Potential bypass of an upstream access control based on URL paths
December 7, 2021
Django 2.2.25 fixes a security issue with severity "low" in 2.2.24.
HTTP requests for URLs with trailing newlines could bypass an upstream access control based on URL paths.
CVE-2021-33203: Potential directory traversal via admindocs
June 2, 2021
Django 2.2.24 fixes two security issues in 2.2.23.
Staff members could use the ~django.contrib.admindocs TemplateDetailView view to check the existence of arbitrary files. Additionally, if (and only if) the default admindocs templates have been customized by the developers to also expose the file contents, then not only the existence but also the file contents would have been exposed.
As a mitigation, path sanitation is now applied and only files within the template root directories can be loaded.
~django.core.validators.URLValidator, ~django.core.validators.validate_ipv4_address, and ~django.core.validators.validate_ipv46_address didn't prohibit leading zeros in octal literals. If you used such values you could suffer from indeterminate SSRF, RFI, and LFI attacks.
~django.core.validators.validate_ipv4_address and ~django.core.validators.validate_ipv46_address validators were not affected on Python 3.9.5+.
Django 2.2.23 fixes a regression in 2.2.21.
May 13, 2021
Django 2.2.23 fixes a regression in 2.2.21.
Fixed a regression in Django 2.2.21 where saving FileField would raise a SuspiciousFileOperation even when a custom ~django.db.models.FileField.upload_to returns a valid file path (32718).
CVE-2021-32052: Header injection possibility since URLValidator accepted newlines in input on Python 3.9.5+
May 6, 2021
Django 2.2.22 fixes a security issue in 2.2.21.
On Python 3.9.5+, ~django.core.validators.URLValidator didn't prohibit newlines and tabs. If you used values with newlines in HTTP response, you could suffer from header injection attacks. Django itself wasn't vulnerable because ~django.http.HttpResponse prohibits newlines in HTTP headers.
Moreover, the URLField form field which uses URLValidator silently removes newlines and tabs on Python 3.9.5+, so the possibility of newlines entering your data only existed if you are using this validator outside of the form fields.
This issue was introduced by the 43882 fix.
CVE-2021-31542: Potential directory-traversal via uploaded files
May 4, 2021
Django 2.2.21 fixes a security issue in 2.2.20.
MultiPartParser, UploadedFile, and FieldFile allowed
directory-traversal via uploaded files with suitably crafted file names.
In order to mitigate this risk, stricter basename and path sanitation is now applied.
CVE-2021-28658: Potential directory-traversal via uploaded files
April 6, 2021
Django 2.2.20 fixes a security issue with severity "low" in 2.2.19.
MultiPartParser allowed directory-traversal via uploaded files with
suitably crafted file names.
Built-in upload handlers were not affected by this vulnerability.
CVE-2021-23336: Web cache poisoning via django.utils.http.limited_parse_qsl()
February 19, 2021
Django 2.2.19 fixes a security issue in 2.2.18.
Django contains a copy of urllib.parse.parse_qsl which was added to backport some security fixes. A further security fix has been issued recently such that parse_qsl() no longer allows using ; as a query parameter separator by default. Django now includes this fix. See 42967 for further details.
CVE-2021-3281: Potential directory-traversal via archive.extract()
February 1, 2021
Django 2.2.18 fixes a security issue with severity "low" in 2.2.17.
The django.utils.archive.extract() function, used by startapp --template and startproject --template, allowed directory-traversal via an archive with absolute paths or relative paths with dot segments.
Django 2.2.17 adds compatibility with Python 3.9.
November 2, 2020
Django 2.2.17 adds compatibility with Python 3.9.
CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+
September 1, 2020
Django 2.2.16 fixes two security issues and two data loss bugs in 2.2.15.
On Python 3.7+, FILE_UPLOAD_DIRECTORY_PERMISSIONS mode was not applied to intermediate-level directories created in the process of uploading files and to intermediate-level collected static directories when using the collectstatic management command.
You should review and manually fix permissions on existing intermediate-level directories.
On Python 3.7+, the intermediate-level directories of the file system cache had the system's standard umask rather than 0o077 (no group or others permissions).
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using related fields pointing to a proxy model in the of argument, the corresponding model was not locked (31866).
Fixed a data loss possibility, following a regression in Django 2.0, when copying model instances with a cached fields value (31863).
Django 2.2.15 fixes two bugs in 2.2.14.
August 3, 2020
Django 2.2.15 fixes two bugs in 2.2.14.
Allowed setting the SameSite cookie flag in .HttpResponse.delete_cookie (31790).
Fixed crash when sending emails to addresses with display names longer than 75 chars on Python 3.6.11+, 3.7.8+, and 3.8.4+ (31784).
Django 2.2.14 fixes a bug in 2.2.13.
July 1, 2020
Django 2.2.14 fixes a bug in 2.2.13.
InvalidCacheKey exceptions and CacheKeyWarning
warnings raised by cache key validation (:ticket:31654).CVE-2020-13254: Potential data leakage via malformed memcached keys
June 3, 2020
Django 2.2.13 fixes two security issues and a regression in 2.2.12.
In cases where a memcached backend does not perform key validation, passing malformed cache keys could result in a key collision, and potential data leakage. In order to avoid this vulnerability, key validation is added to the memcached cache backends.
ForeignKeyRawIdWidgetQuery parameters for the admin ForeignKeyRawIdWidget were not properly URL
encoded, posing an XSS attack vector. ForeignKeyRawIdWidget now
ensures query parameters are correctly URL encoded.
Fixed a regression in Django 2.2.12 that affected translation loading for
apps providing translations for territorial language variants as well as a
generic language, where the project has different plural equations for the
language (:ticket:31570).
Tracking a jQuery security release, upgraded the version of jQuery used by the admin from 3.3.1 to 3.5.1.
Django 2.2.12 fixes a bug in 2.2.11.
April 1, 2020
Django 2.2.12 fixes a bug in 2.2.11.
.po files containing different plural
equations for the same language (:ticket:30439).CVE-2020-9402: Potential SQL injection via tolerance parameter in GIS functions and aggregates on Oracle
March 4, 2020
Django 2.2.11 fixes a security issue and a data loss bug in 2.2.10.
GIS functions and aggregates on Oracle were subject to SQL injection, using a suitably crafted tolerance.
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using related fields or parent link fields with multi-table-inheritance in the of argument, the corresponding models were not locked (31246).
CVE-2020-7471: Potential SQL injection via StringAgg(delimiter)
February 3, 2020
Django 2.2.10 fixes a security issue in 2.2.9.
~django.contrib.postgres.aggregates.StringAgg aggregation function was subject to SQL injection, using a suitably crafted delimiter.
CVE-2019-19844: Potential account hijack via password reset form
December 18, 2019
Django 2.2.9 fixes a security issue and a data loss bug in 2.2.8.
By submitting a suitably crafted email address making use of Unicode characters, that compared equal to an existing user email when lower-cased for comparison, an attacker could be sent a password reset token for the matched account.
In order to avoid this vulnerability, password reset requests now compare the submitted email using the stricter, recommended algorithm for case-insensitive comparison of two identifiers from Unicode Technical Report 36, section 2.11.2(B)(2). Upon a match, the email containing the reset token will be sent to the email address on record rather than the submitted address.
Fixed a data loss possibility in ~django.contrib.postgres.forms.SplitArrayField. When using with ArrayField(BooleanField()), all values after the first True value were marked as checked instead of preserving passed values (31073).
CVE-2019-19118: Privilege escalation in the Django admin.
December 2, 2019
Django 2.2.8 fixes a security issue, several bugs in 2.2.7, and adds compatibility with Python 3.8.
Since Django 2.1, a Django model admin displaying a parent model with related model inlines, where the user has view-only permissions to a parent model but edit permissions to the inline model, would display a read-only view of the parent model but editable forms for the inline.
Submitting these forms would not allow direct edits to the parent model, but would trigger the parent model's save() method, and cause pre and post-save signal handlers to be invoked. This is a privilege escalation as a user who lacks permission to edit a model should not be able to trigger its save-related signals.
To resolve this issue, the permission handling code of the Django admin interface has been changed. Now, if a user has only the "view" permission for a parent model, the entire displayed form will not be editable, even if the user has permission to edit models included in inlines.
This is a backwards-incompatible change, and the Django security team is aware that some users of Django were depending on the ability to allow editing of inlines in the admin form of an otherwise view-only parent model.
Given the complexity of the Django admin, and in-particular the permissions related checks, it is the view of the Django security team that this change was necessary: that it is not currently feasible to maintain the existing behavior while escaping the potential privilege escalation in a way that would avoid a recurrence of similar issues in the future, and that would be compatible with Django's safe by default philosophy.
For the time being, developers whose applications are affected by this change should replace the use of inlines in read-only parents with custom forms and views that explicitly implement the desired functionality. In the longer term, adding a documented, supported, and properly-tested mechanism for partially-editable multi-model forms to the admin interface may occur in Django itself.
Fixed a data loss possibility in the admin changelist view when a custom formset's prefix contains regular expression special characters, e.g. '$' (31031).
Fixed a regression in Django 2.2.1 that caused a crash when migrating permissions for proxy models with a multiple database setup if the default entry was empty (31021).
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using 'self' in the of argument with multi-table inheritance, a parent model was locked instead of the queryset's model (30953).
Django 2.2.7 fixes several bugs in 2.2.6.
November 4, 2019
Django 2.2.7 fixes several bugs in 2.2.6.
Fixed a crash when using a contains, contained_by, has_key, has_keys, or has_any_keys lookup on django.contrib.postgres.fields.JSONField, if the right or left hand side of an expression is a key transform (30826).
Prevented migrate --plan from showing that RunPython operations are irreversible when reverse_code callables don't have docstrings or when showing a forward migration plan (30870).
Fixed migrations crash on PostgreSQL when adding an ~django.db.models.Index with fields ordering and ~.Index.opclasses (30903).
Restored the ability to override ~django.db.models.Model.get_FOO_display (30931).
Django 2.2.6 fixes several bugs in 2.2.5.
October 1, 2019
Django 2.2.6 fixes several bugs in 2.2.5.
Fixed migrations crash on SQLite when altering a model containing partial indexes (30754).
Fixed a regression in Django 2.2.4 that caused a crash when filtering with a Subquery() annotation of a queryset containing django.contrib.postgres.fields.JSONField or ~django.contrib.postgres.fields.HStoreField (30769).
Django 2.2.5 fixes several bugs in 2.2.4.
September 2, 2019
Django 2.2.5 fixes several bugs in 2.2.4.
Relaxed the system check added in Django 2.2 for models to reallow use of the same db_table by multiple models when database routers are installed (30673).
Fixed crash of KeyTransform() for django.contrib.postgres.fields.JSONField and ~django.contrib.postgres.fields.HStoreField when using on expressions with params (30672).
Fixed a regression in Django 2.2 where ModelAdmin.list_filter choices to foreign objects don't respect a model's Meta.ordering (30449).
CVE-2019-14232: Denial-of-service possibility in django.utils.text.Truncator
August 1, 2019
Django 2.2.4 fixes security issues and several bugs in 2.2.3.
If django.utils.text.Truncator's chars() and words() methods were passed the html=True argument, they were extremely slow to evaluate certain inputs due to a catastrophic backtracking vulnerability in a regular expression. The chars() and words() methods are used to implement the truncatechars_html and truncatewords_html template filters, which were thus vulnerable.
The regular expressions used by Truncator have been simplified in order to avoid potential backtracking issues. As a consequence, trailing punctuation may now at times be included in the truncated output.
Due to the behavior of the underlying HTMLParser, django.utils.html.strip_tags would be extremely slow to evaluate certain inputs containing large sequences of nested incomplete HTML entities. The strip_tags() method is used to implement the corresponding striptags template filter, which was thus also vulnerable.
strip_tags() now avoids recursive calls to HTMLParser when progress removing tags, but necessarily incomplete HTML entities, stops being made.
Remember that absolutely NO guarantee is provided about the results of strip_tags() being HTML safe. So NEVER mark safe the result of a strip_tags() call without escaping it first, for example with django.utils.html.escape.
Key and index lookups for django.contrib.postgres.fields.JSONField and key lookups for ~django.contrib.postgres.fields.HStoreField were subject to SQL injection, using a suitably crafted dictionary, with dictionary expansion, as the **kwargs passed to QuerySet.filter().
If passed certain inputs, django.utils.encoding.uri_to_iri could lead to significant memory usage due to excessive recursion when re-percent-encoding invalid UTF-8 octet sequences.
uri_to_iri() now avoids recursion when re-percent-encoding invalid UTF-8 octet sequences.
Fixed a regression in Django 2.2 when ordering a QuerySet.union(), intersection(), or difference() by a field type present more than once results in the wrong ordering being used (30628).
Fixed a migration crash on PostgreSQL when adding a check constraint with a contains lookup on ~django.contrib.postgres.fields.DateRangeField or ~django.contrib.postgres.fields.DateTimeRangeField, if the right hand side of an expression is the same type (30621).
Fixed a regression in Django 2.2 where auto-reloader crashes if a file path contains null characters ('\x00') (30506).
Fixed a regression in Django 2.2 where auto-reloader crashes if a translation directory cannot be resolved (30647).
CVE-2019-12781: Incorrect HTTP detection with reverse-proxy connecting via HTTPS
July 1, 2019
Django 2.2.3 fixes a security issue and several bugs in 2.2.2. Also, the latest string translations from Transifex are incorporated.
When deployed behind a reverse-proxy connecting to Django via HTTPS, django.http.HttpRequest.scheme would incorrectly detect client requests made via HTTP as using HTTPS. This entails incorrect results for ~django.http.HttpRequest.is_secure, and ~django.http.HttpRequest.build_absolute_uri, and that HTTP requests would not be redirected to HTTPS in accordance with SECURE_SSL_REDIRECT.
HttpRequest.scheme now respects SECURE_PROXY_SSL_HEADER, if it is configured, and the appropriate header is set on the request, for both HTTP and HTTPS requests.
If you deploy Django behind a reverse-proxy that forwards HTTP requests, and that connects to Django via HTTPS, be sure to verify that your application correctly handles code paths relying on scheme, is_secure(), build_absolute_uri(), and SECURE_SSL_REDIRECT.
Fixed a regression in Django 2.2 where ~django.db.models.Avg, ~django.db.models.StdDev, and ~django.db.models.Variance crash with filter argument (30542).
Fixed a regression in Django 2.2.2 where auto-reloader crashes with AttributeError, e.g. when using ipdb (30588).
CVE-2019-12308: AdminURLFieldWidget XSS
June 3, 2019
Django 2.2.2 fixes security issues and several bugs in 2.2.1.
The clickable "Current URL" link generated by AdminURLFieldWidget displayed the provided value without validating it as a safe URL. Thus, an unvalidated value stored in the database, or a value provided as a URL query parameter payload, could result in an clickable JavaScript link.
AdminURLFieldWidget now validates the provided value using ~django.core.validators.URLValidator before displaying the clickable link. You may customize the validator by passing a validator_class kwarg to AdminURLFieldWidget.__init__(), e.g. when using ~django.contrib.admin.ModelAdmin.formfield_overrides.
jQuery before 3.4.0, mishandles jQuery.extend(true, {}, ...) because of Object.prototype pollution. If an unsanitized source object contained an enumerable __proto__ property, it could extend the native Object.prototype.
The bundled version of jQuery used by the Django admin has been patched to allow for the select2 library's use of jQuery.extend().
Fixed a regression in Django 2.2 that stopped Show/Hide toggles working on dynamically added admin inlines (30459).
Fixed a regression in Django 2.2 where deprecation message crashes if Meta.ordering contains an expression (30463).
Fixed a regression in Django 2.2.1 where ~django.contrib.postgres.search.SearchVector generates SQL with a redundant Coalesce call (30488).
Fixed a regression in Django 2.2 where auto-reloader doesn't detect changes in manage.py file when using StatReloader (30479).
Fixed crash of ~django.contrib.postgres.aggregates.ArrayAgg and ~django.contrib.postgres.aggregates.StringAgg with ordering argument when used in a Subquery (30315).
Fixed a regression in Django 2.2 that caused a crash of auto-reloader when an exception with custom signature is raised (30516).
Fixed a regression in Django 2.2.1 where auto-reloader unnecessarily reloads translation files multiple times when using StatReloader (30523).
Django 2.2.1 fixes several bugs in 2.2.
May 1, 2019
Django 2.2.1 fixes several bugs in 2.2.
Fixed a regression in Django 2.1 that caused the incorrect quoting of database user password when using dbshell on Oracle (30307).
Added compatibility for psycopg2 2.8 (30331).
Fixed a regression in Django 2.2 that caused a crash when loading the template for the technical 500 debug page (30324).
Fixed crash of ordering argument in ~django.contrib.postgres.aggregates.ArrayAgg and ~django.contrib.postgres.aggregates.StringAgg when it contains an expression with params (30332).
Fixed a regression in Django 2.2 that caused a single instance fast-delete to not set the primary key to None (30330).
Prevented makemigrations from generating infinite migrations for check constraints and partial indexes when condition contains a ~python:range object (30350).
Reverted an optimization in Django 2.2 (29725) that caused the inconsistent behavior of count() and exists() on a reverse many-to-many relationship with a custom manager (30325).
Fixed a regression in Django 2.2 where ~django.core.paginator.Paginator crashes if object_list is a queryset ordered or aggregated over a nested JSONField key transform (30335).
Fixed a regression in Django 2.2 where IntegerField validation of database limits crashes if limit_value attribute in a custom validator is callable (30328).
Fixed a regression in Django 2.2 where ~django.contrib.postgres.search.SearchVector generates SQL that is not indexable (30385).
Fixed a regression in Django 2.2 that caused an exception to be raised when a custom error handler could not be imported (30318).
Relaxed the system check added in Django 2.2 for the admin app's dependencies to reallow use of ~django.contrib.sessions.middleware.SessionMiddleware subclasses, rather than requiring django.contrib.sessions to be in INSTALLED_APPS (30312).
Increased the default timeout when using Watchman to 5 seconds to prevent falling back to StatReloader on larger projects and made it customizable via the DJANGO_WATCHMAN_TIMEOUT environment variable (30361).
Fixed a regression in Django 2.2 that caused a crash when migrating permissions for proxy models if the target permissions already existed. For example, when a permission had been created manually or a model had been migrated from concrete to proxy (30351).
Fixed a regression in Django 2.2 that caused a crash of runserver when URLConf modules raised exceptions (30323).
Fixed a regression in Django 2.2 where changes were not reliably detected by auto-reloader when using StatReloader (30323).
Fixed a migration crash on Oracle and PostgreSQL when adding a check constraint with a contains, startswith, or endswith lookup (or their case-insensitive variant) (30408).
Fixed a migration crash on Oracle and SQLite when adding a check constraint with condition contains | (OR) operator (30412).
- Django 2.2.28 release notes - Django 2.2.27 release notes - Django 2.2.26 release notes - Django 2.2.25 release notes - Django 2.2.24 release notes
Django 2.2.28 release notes
Django 2.2.27 release notes
Django 2.2.26 release notes
Django 2.2.25 release notes
Django 2.2.24 release notes
Django 2.2.23 release notes
Django 2.2.22 release notes
Django 2.2.21 release notes
Django 2.2.20 release notes
Django 2.2.19 release notes
Django 2.2.18 release notes
Django 2.2.17 release notes
Django 2.2.16 release notes
Django 2.2.15 release notes
Django 2.2.14 release notes
Django 2.2.13 release notes
Django 2.2.12 release notes
Django 2.2.11 release notes
Django 2.2.10 release notes
Django 2.2.9 release notes
Django 2.2.8 release notes
Django 2.2.7 release notes
Django 2.2.6 release notes
Django 2.2.5 release notes
Django 2.2.4 release notes
Django 2.2.3 release notes
Django 2.2.2 release notes
Django 2.2.1 release notes
Django 2.2 release notes
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 /howto/upgrade-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 ~django.db.models.CheckConstraint and ~django.db.models.UniqueConstraint classes enable adding custom database constraints. Constraints are added to models using the Meta.constraints option.
Added a CSS class to the column headers of ~django.contrib.admin.TabularInline.
The HttpRequest is now passed as the first positional argument to .RemoteUserBackend.configure_user, if it accepts it.
Added Oracle support for the ~django.contrib.gis.db.models.functions.Envelope function.
Added SpatiaLite support for the coveredby and covers lookups.
The new ordering argument for ~django.contrib.postgres.aggregates.ArrayAgg and ~django.contrib.postgres.aggregates.StringAgg determines the ordering of the aggregated elements.
The new ~django.contrib.postgres.indexes.BTreeIndex, ~django.contrib.postgres.indexes.HashIndex and ~django.contrib.postgres.indexes.SpGistIndex classes allow creating B-Tree, hash, and SP-GiST indexes in the database.
~django.contrib.postgres.indexes.BrinIndex now has the autosummarize parameter.
The new search_type parameter of ~django.contrib.postgres.search.SearchQuery allows searching for a phrase or raw expression.
Added path matching to the collectstatic --ignore option so that patterns like /vendor/*.js can be used.
Added result streaming for .QuerySet.iterator on SQLite.
The new View.setup hook initializes view attributes before calling ~django.views.generic.base.View.dispatch. It allows mixins to set up instance attributes for reuse in child classes.
Added support and translations for the Armenian language.
The new --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.
The new 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 ~django.db.models.DurationField for Oracle and PostgreSQL, and ~django.db.models.AutoField for SQLite.
On Oracle, dbshell is wrapped with rlwrap, if available. rlwrap provides a command history and editing of keyboard input.
The new 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.
The new migrate --plan option prints the list of migration operations that will be performed.
NoneType can now be serialized in migrations.
You can now register custom serializers for migrations.
Added support for PostgreSQL operator classes (.Index.opclasses).
Added support for partial indexes (.Index.condition).
Added the ~django.db.models.functions.NullIf and ~django.db.models.functions.Reverse database functions, as well as many math database functions.
Setting the new 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.
The new ~django.db.models.functions.ExtractIsoYear function extracts ISO-8601 week-numbering years from ~django.db.models.DateField and ~django.db.models.DateTimeField, and the new iso_year lookup allows querying by an ISO-8601 week-numbering year.
The new .QuerySet.bulk_update method allows efficiently updating specific fields on multiple model instances.
Django no longer always starts a transaction when a single query is being performed, such as Model.save(), QuerySet.update(), and Model.delete(). This improves the performance of autocommit by reducing the number of database round trips.
Added SQLite support for the ~django.db.models.StdDev and ~django.db.models.Variance functions.
The handling of DISTINCT aggregation is added to the ~django.db.models.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.
The .RelatedManager.add, ~.RelatedManager.create, ~.RelatedManager.remove, ~.RelatedManager.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).
Added .HttpRequest.headers to allow simple access to a request's headers.
You can now deserialize data using natural keys containing forward references by passing handle_forward_references=True to serializers.deserialize(). Additionally, loaddata handles forward references automatically.
The new .SimpleTestCase.assertURLEqual assertion checks for a given URL, ignoring the ordering of the query string. ~.SimpleTestCase.assertRedirects uses the new assertion.
The test ~.django.test.Client now supports automatic JSON serialization of list and tuple data when content_type='application/json'.
The new ORACLE_MANAGED_FILES test database setting allows using Oracle Managed Files (OMF) tablespaces.
Deferrable database constraints are now checked at the end of each ~django.test.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.
~django.test.runner.DiscoverRunner now skips the setup of databases not referenced by tests.
The new .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.
Third-party database backends must implement support for table check constraints or set DatabaseFeatures.supports_table_check_constraints to False.
Third party database backends must implement support for ignoring constraints or uniqueness errors while inserting or set DatabaseFeatures.supports_ignore_conflicts to False.
Third party database backends must implement introspection for DurationField or set DatabaseFeatures.can_introspect_duration_field to False.
DatabaseFeatures.uses_savepoints now defaults to True.
Third party database backends must implement support for partial indexes or set 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().
SQL generation for indexes is moved from ~django.db.models.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()
The third argument of DatabaseWrapper.__init__(), allow_thread_sharing, is removed.
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"]
Support for GDAL 1.9 and 1.10 is dropped.
Initial data migrations are now loaded in ~django.test.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 ~django.test.TransactionTestCase's internals.
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.
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').
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 ~django.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 django.contrib.sitemaps.ping_google function, set the new sitemap_uses_https argument to False.
runserver no longer supports pyinotify (replaced by Watchman).
The ~django.db.models.Avg, ~django.db.models.StdDev, and ~django.db.models.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.
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.
The undocumented QuerySetPaginator alias of django.core.paginator.Paginator is deprecated.
The 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.
The 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.
The 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__'.
Nothing published for this version
Nothing published for this version
Nothing published for this version
CVE-2019-19118: Privilege escalation in the Django admin.
December 2, 2019
Django 2.1.15 fixes a security issue and a data loss bug in 2.1.14.
Since Django 2.1, a Django model admin displaying a parent model with related model inlines, where the user has view-only permissions to a parent model but edit permissions to the inline model, would display a read-only view of the parent model but editable forms for the inline.
Submitting these forms would not allow direct edits to the parent model, but would trigger the parent model's save() method, and cause pre and post-save signal handlers to be invoked. This is a privilege escalation as a user who lacks permission to edit a model should not be able to trigger its save-related signals.
To resolve this issue, the permission handling code of the Django admin interface has been changed. Now, if a user has only the "view" permission for a parent model, the entire displayed form will not be editable, even if the user has permission to edit models included in inlines.
This is a backwards-incompatible change, and the Django security team is aware that some users of Django were depending on the ability to allow editing of inlines in the admin form of an otherwise view-only parent model.
Given the complexity of the Django admin, and in-particular the permissions related checks, it is the view of the Django security team that this change was necessary: that it is not currently feasible to maintain the existing behavior while escaping the potential privilege escalation in a way that would avoid a recurrence of similar issues in the future, and that would be compatible with Django's safe by default philosophy.
For the time being, developers whose applications are affected by this change should replace the use of inlines in read-only parents with custom forms and views that explicitly implement the desired functionality. In the longer term, adding a documented, supported, and properly-tested mechanism for partially-editable multi-model forms to the admin interface may occur in Django itself.
Fixed a data loss possibility in the ~django.db.models.query.QuerySet.select_for_update. When using 'self' in the of argument with multi-table inheritance, a parent model was locked instead of the queryset's model (30953).
Django 2.1.14 fixes a regression in 2.1.13.
November 4, 2019
Django 2.1.14 fixes a regression in 2.1.13.
contains, contained_by, has_key,
has_keys, or has_any_keys lookup on
django.contrib.postgres.fields.JSONField, if the right or left hand
side of an expression is a key transform (:ticket:30826).Django 2.1.13 fixes a regression in 2.1.11.
October 1, 2019
Django 2.1.13 fixes a regression in 2.1.11.
Fixed a crash when filtering with a Subquery() annotation of a queryset containing django.contrib.postgres.fields.JSONField or ~django.contrib.postgres.fields.HStoreField (30769).
Your coding agent can read these notes before it upgrades. Set up the MCP server →