August 1, 2016

Welcome to Django 1.10!

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 1.9 or older versions. 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 Upgrading Django to a newer version guide if you’re updating an existing project.

Like Django 1.9, Django 1.10 requires Python 2.7, 3.4, or 3.5. We highly recommend and only officially support the latest release of each series.

Custom user models may use the new ASCIIUsernameValidator or UnicodeUsernameValidator .

The username validator now explicitly accepts Unicode letters by default on Python 3 only.

The User model in django.contrib.auth originally only accepted ASCII letters in usernames. Although it wasn’t a deliberate choice, Unicode characters have always been accepted when using Python 3.

It also now includes trigram support, using the trigram_similar lookup, and the TrigramSimilarity and TrigramDistance expressions.

django.contrib.postgres now includes a collection of database functions to allow the use of the full text search engine. You can search across multiple fields in your relational database, combine the searches with other lookups, use different language configurations and weightings, and rank the results by relevance.

Backwards incompatible changes in 1.10¶

Warning In addition to the changes outlined in this section, be sure to review the Features removed in 1.10 for the features that have reached the end of their deprecation cycle and therefore been removed. If you haven’t updated your code within the deprecation timeline for a given feature, its removal may appear as a backwards incompatible change.

Database backend API¶ GIS’s AreaField uses an unspecified underlying numeric type that could in practice be any numeric Python type. decimal.Decimal values retrieved from the database are now converted to float to make it easier to combine them with values used by the GIS libraries.

uses an unspecified underlying numeric type that could in practice be any numeric Python type. values retrieved from the database are now converted to to make it easier to combine them with values used by the GIS libraries. In order to enable temporal subtraction you must set the supports_temporal_subtraction database feature flag to True and implement the DatabaseOperations.subtract_temporals() method. This method should return the SQL and parameters required to compute the difference in microseconds between the lhs and rhs arguments in the datatype used to store DurationField .

select_related() prohibits non-relational fields for nested relations¶ Django 1.8 added validation for non-relational fields in select_related() : >>> Book . objects . select_related ( 'title' ) Traceback (most recent call last): ... FieldError : Non-relational field given in select_related: 'title' But it didn’t prohibit nested non-relation fields as it does now: >>> Book . objects . select_related ( 'author__name' ) Traceback (most recent call last): ... FieldError : Non-relational field given in select_related: 'name'

_meta.get_fields() returns consistent reverse fields for proxy models¶ Before Django 1.10, the get_fields() method returned different reverse fields when called on a proxy model compared to its proxied concrete class. This inconsistency was fixed by returning the full set of fields pointing to a concrete class or one of its proxies in both cases.

AbstractUser.username max_length increased to 150¶ A migration for django.contrib.auth.models.User.username 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. We considered an increase to 254 characters to more easily allow the use of email addresses (which are limited to 254 characters) as usernames but rejected it due to a MySQL limitation. When using the utf8mb4 encoding (recommended for proper Unicode support), MySQL can only create unique indexes with 191 characters by default. Therefore, if you need a longer length, please use a custom user model. If you want to preserve the 30 character limit for usernames, use a custom form when creating a user or changing usernames: from django.contrib.auth.forms import UserCreationForm class MyUserCreationForm ( UserCreationForm ): username = forms . CharField ( max_length = 30 , help_text = 'Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.' , ) If you wish to keep this restriction in the admin, set UserAdmin.add_form to use this form: from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User class UserAdmin ( BaseUserAdmin ): add_form = MyUserCreationForm admin . site . unregister ( User ) admin . site . register ( User , UserAdmin )

Dropped support for PostgreSQL 9.1¶ Upstream support for PostgreSQL 9.1 ends in September 2016. As a consequence, Django 1.10 sets PostgreSQL 9.2 as the minimum version it officially supports.

runserver output goes through logging¶ Request and response handling of the runserver command is sent to the django.server logger instead of to sys.stderr . If you disable Django’s logging configuration or override it with your own, you’ll need to add the appropriate logging configuration if you want to see that output: 'formatters' : { 'django.server' : { '()' : 'django.utils.log.ServerFormatter' , 'format' : '[ %(server_time)s ] %(message)s ' , } }, 'handlers' : { 'django.server' : { 'level' : 'INFO' , 'class' : 'logging.StreamHandler' , 'formatter' : 'django.server' , }, }, 'loggers' : { 'django.server' : { 'handlers' : [ 'django.server' ], 'level' : 'INFO' , 'propagate' : False , } }

auth.CustomUser and auth.ExtensionUser test models were removed¶ Since the introduction of migrations for the contrib apps in Django 1.8, the tables of these custom user test models were not created anymore making them unusable in a testing context.

Apps registry is no longer auto-populated when unpickling models outside of Django¶ The apps registry is no longer auto-populated when unpickling models. This was added in Django 1.7.2 as an attempt to allow unpickling models outside of Django, such as in an RQ worker, without calling django.setup() , but it creates the possibility of a deadlock. To adapt your code in the case of RQ, you can provide your own worker script that calls django.setup() .

Removed null assignment check for non-null foreign key fields¶ In older versions, assigning None to a non-nullable ForeignKey or OneToOneField raised ValueError('Cannot assign None: "model.field" does not allow null values.') . For consistency with other model fields which don’t have a similar check, this check is removed.

Removed weak password hashers from the default PASSWORD_HASHERS setting¶ Django 0.90 stored passwords as unsalted MD5. Django 0.91 added support for salted SHA1 with automatic upgrade of passwords when a user logs in. Django 1.4 added PBKDF2 as the default password hasher. If you have an old Django project with MD5 or SHA1 (even salted) encoded passwords, be aware that these can be cracked fairly easily with today’s hardware. To make Django users acknowledge continued use of weak hashers, the following hashers are removed from the default PASSWORD_HASHERS setting: 'django.contrib.auth.hashers.SHA1PasswordHasher' 'django.contrib.auth.hashers.MD5PasswordHasher' 'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher' 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher' 'django.contrib.auth.hashers.CryptPasswordHasher' Consider using a wrapped password hasher to strengthen the hashes in your database. If that’s not feasible, add the PASSWORD_HASHERS setting to your project and add back any hashers that you need. You can check if your database has any of the removed hashers like this: from django.contrib.auth import get_user_model User = get_user_model () # Unsalted MD5/SHA1: User . objects . filter ( password__startswith = 'md5$$' ) User . objects . filter ( password__startswith = 'sha1$$' ) # Salted MD5/SHA1: User . objects . filter ( password__startswith = 'md5$' ) . exclude ( password__startswith = 'md5$$' ) User . objects . filter ( password__startswith = 'sha1$' ) . exclude ( password__startswith = 'sha1$$' ) # Crypt hasher: User . objects . filter ( password__startswith = 'crypt$$' ) from django.db.models import CharField from django.db.models.functions import Length CharField . register_lookup ( Length ) # Unsalted MD5 passwords might not have an 'md5$$' prefix: User . objects . filter ( password__length = 32 )

Field.get_prep_lookup() and Field.get_db_prep_lookup() methods are removed¶ If you have a custom field that implements either of these methods, register a custom lookup for it. For example: from django.db.models import Field from django.db.models.lookups import Exact class MyField ( Field ): ... class MyFieldExact ( Exact ): def get_prep_lookup ( self ): # do_custom_stuff_for_myfield .... MyField . register_lookup ( MyFieldExact )

django.contrib.gis ¶ Support for SpatiaLite < 3.0 and GEOS < 3.3 is dropped.

The add_postgis_srs() backwards compatibility alias for django.contrib.gis.utils.add_srs_entry() is removed.

backwards compatibility alias for is removed. On Oracle/GIS, the Area aggregate function now returns a float instead of decimal.Decimal . (It’s still wrapped in a measure of square meters.)

aggregate function now returns a instead of . (It’s still wrapped in a measure of square meters.) The default GEOSGeometry representation (WKT output) is trimmed by default. That is, instead of POINT (23.0000000000000000 5.5000000000000000) , you’ll get POINT (23 5.5) .

Maximum size of a request body and the number of GET/POST parameters is limited¶ Two new settings help mitigate denial-of-service attacks via large requests: DATA_UPLOAD_MAX_MEMORY_SIZE limits the size that a request body may be. File uploads don’t count towards this limit.

limits the size that a request body may be. File uploads don’t count towards this limit. DATA_UPLOAD_MAX_NUMBER_FIELDS limits the number of GET/POST parameters that are parsed. Applications that receive unusually large form posts may need to tune these settings.