Django 1.7 release notes

September 2, 2014

Welcome to Django 1.7!

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.6 or older versions. We’ve begun the deprecation process for some features, and some features have reached the end of their deprecation process and have been removed.

Python compatibility

Django 1.7 requires Python 2.7, 3.2, 3.3, or 3.4. We highly recommend and only officially support the latest release of each series.

The Django 1.6 series is the last to support Python 2.6. Django 1.7 is the first release to support Python 3.4.

This change should affect only a small number of Django users, as most operating-system vendors today are shipping Python 2.7 or newer as their default version. If you’re still using Python 2.6, however, you’ll need to stick to Django 1.6 until you can upgrade your Python version. Per our support policy, Django 1.6 will continue to receive security support until the release of Django 1.8.

What’s new in Django 1.7

Schema migrations

Django now has built-in support for schema migrations. It allows models to be updated, changed, and deleted by creating migration files that represent the model changes and which can be run on any development, staging or production database.

Migrations are covered in their own documentation, but a few of the key features are:

  • syncdb has been deprecated and replaced by migrate. Don’t worry - calls to syncdb will still work as before.

  • A new makemigrations command provides an easy way to autodetect changes to your models and make migrations for them.

    django.db.models.signals.pre_syncdb and django.db.models.signals.post_syncdb have been deprecated, to be replaced by pre_migrate and post_migrate respectively. These new signals have slightly different arguments. Check the documentation for details.

  • The allow_syncdb method on database routers is now called allow_migrate, but still performs the same function. Routers with allow_syncdb methods will still work, but that method name is deprecated and you should change it as soon as possible (nothing more than renaming is required).

  • initial_data fixtures are no longer loaded for apps with migrations; if you want to load initial data for an app, we suggest you create a migration for your application and define a RunPython or RunSQL operation in the operations section of the migration.

  • Test rollback behavior is different for apps with migrations; in particular, Django will no longer emulate rollbacks on non-transactional databases or inside TransactionTestCase unless specifically requested.

  • It is not advised to have apps without migrations depend on (have a ForeignKey or ManyToManyField to) apps with migrations.

App-loading refactor

Historically, Django applications were tightly linked to models. A singleton known as the 《app cache》 dealt with both installed applications and models. The models module was used as an identifier for applications in many APIs.

As the concept of Django applications matured, this code showed some shortcomings. It has been refactored into an 《app registry》 where models modules no longer have a central role and where it’s possible to attach configuration data to applications.

Improvements thus far include:

  • Applications can run code at startup, before Django does anything else, with the ready() method of their configuration.
  • Application labels are assigned correctly to models even when they’re defined outside of models.py. You don’t have to set app_label explicitly any more.
  • It is possible to omit models.py entirely if an application doesn’t have any models.
  • Applications can be relabeled with the label attribute of application configurations, to work around label conflicts.
  • The name of applications can be customized in the admin with the verbose_name of application configurations.
  • The admin automatically calls autodiscover() when Django starts. You can consequently remove this line from your URLconf.
  • Django imports all application configurations and models as soon as it starts, through a deterministic and straightforward process. This should make it easier to diagnose import issues such as import loops.

New method on Field subclasses

To help power both schema migrations and to enable easier addition of composite keys in future releases of Django, the Field API now has a new required method: deconstruct().

This method takes no arguments, and returns a tuple of four items:

  • name: The field’s attribute name on its parent model, or None if it is not part of a model
  • path: A dotted, Python path to the class of this field, including the class name.
  • args: Positional arguments, as a list
  • kwargs: Keyword arguments, as a dict

These four values allow any field to be serialized into a file, as well as allowing the field to be copied safely, both essential parts of these new features.

This change should not affect you unless you write custom Field subclasses; if you do, you may need to reimplement the deconstruct() method if your subclass changes the method signature of __init__ in any way. If your field just inherits from a built-in Django field and doesn’t override __init__, no changes are necessary.

If you do need to override deconstruct(), a good place to start is the built-in Django fields (django/db/models/fields/__init__.py) as several fields, including DecimalField and DateField, override it and show how to call the method on the superclass and simply add or remove extra arguments.

This also means that all arguments to fields must themselves be serializable; to see what we consider serializable, and to find out how to make your own classes serializable, read the migration serialization documentation.

Calling custom QuerySet methods from the Manager

Historically, the recommended way to make reusable model queries was to create methods on a custom Manager class. The problem with this approach was that after the first method call, you’d get back a QuerySet instance and couldn’t call additional custom manager methods.

Though not documented, it was common to work around this issue by creating a custom QuerySet so that custom methods could be chained; but the solution had a number of drawbacks:

  • The custom QuerySet and its custom methods were lost after the first call to values() or values_list().
  • Writing a custom Manager was still necessary to return the custom QuerySet class and all methods that were desired on the Manager had to be proxied to the QuerySet. The whole process went against the DRY principle.

The QuerySet.as_manager() class method can now directly create Manager with QuerySet methods:

class FoodQuerySet(models.QuerySet):
    def pizzas(self):
        return self.filter(kind='pizza')

    def vegetarian(self):
        return self.filter(vegetarian=True)

class Food(models.Model):
    kind = models.CharField(max_length=50)
    vegetarian = models.BooleanField(default=False)
    objects = FoodQuerySet.as_manager()

Food.objects.pizzas().vegetarian()

Using a custom manager when traversing reverse relations

It is now possible to specify a custom manager when traversing a reverse relationship:

class Blog(models.Model):
    pass

class Entry(models.Model):
    blog = models.ForeignKey(Blog)

    objects = models.Manager()  # Default Manager
    entries = EntryManager()    # Custom Manager

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()

New system check framework

We’ve added a new System check framework for detecting common problems (like invalid models) and providing hints for resolving those problems. The framework is extensible so you can add your own checks for your own apps and libraries.

To perform system checks, you use the check management command. This command replaces the older validate management command.

Admin shortcuts support time zones

The 《today》 and 《now》 shortcuts next to date and time input widgets in the admin are now operating in the current time zone. Previously, they used the browser time zone, which could result in saving the wrong value when it didn’t match the current time zone on the server.

In addition, the widgets now display a help message when the browser and server time zone are different, to clarify how the value inserted in the field will be interpreted.

Using database cursors as context managers

Prior to Python 2.7, database cursors could be used as a context manager. The specific backend’s cursor defined the behavior of the context manager. The behavior of magic method lookups was changed with Python 2.7 and cursors were no longer usable as context managers.

Django 1.7 allows a cursor to be used as a context manager. That is, the following can be used:

with connection.cursor() as c:
    c.execute(...)

instead of:

c = connection.cursor()
try:
    c.execute(...)
finally:
    c.close()

Custom lookups

It is now possible to write custom lookups and transforms for the ORM. Custom lookups work just like Django’s built-in lookups (e.g. lte, icontains) while transforms are a new concept.

The django.db.models.Lookup class provides a way to add lookup operators for model fields. As an example it is possible to add day_lte operator for DateFields.

The django.db.models.Transform class allows transformations of database values prior to the final lookup. For example it is possible to write a year transform that extracts year from the field’s value. Transforms allow for chaining. After the year transform has been added to DateField it is possible to filter on the transformed value, for example qs.filter(author__birthdate__year__lte=1981).

For more information about both custom lookups and transforms refer to the custom lookups documentation.

Improvements to Form error handling

Form.add_error()

Previously there were two main patterns for handling errors in forms:

  • Raising a ValidationError from within certain functions (e.g. Field.clean(), Form.clean_<fieldname>(), or Form.clean() for non-field errors.)
  • Fiddling with Form._errors when targeting a specific field in Form.clean() or adding errors from outside of a 《clean》 method (e.g. directly from a view).

Using the former pattern was straightforward since the form can guess from the context (i.e. which method raised the exception) where the errors belong and automatically process them. This remains the canonical way of adding errors when possible. However the latter was fiddly and error-prone, since the burden of handling edge cases fell on the user.

The new add_error() method allows adding errors to specific form fields from anywhere without having to worry about the details such as creating instances of django.forms.utils.ErrorList or dealing with Form.cleaned_data. This new API replaces manipulating Form._errors which now becomes a private API.

See Cleaning and validating fields that depend on each other for an example using Form.add_error().

Error metadata

The ValidationError constructor accepts metadata such as error code or params which are then available for interpolating into the error message (see Raising ValidationError for more details); however, before Django 1.7 those metadata were discarded as soon as the errors were added to Form.errors.

Form.errors and django.forms.utils.ErrorList now store the ValidationError instances so these metadata can be retrieved at any time through the new Form.errors.as_data method.

The retrieved ValidationError instances can then be identified thanks to their error code which enables things like rewriting the error’s message or writing custom logic in a view when a given error is present. It can also be used to serialize the errors in a custom format such as XML.

The new Form.errors.as_json() method is a convenience method which returns error messages along with error codes serialized as JSON. as_json() uses as_data() and gives an idea of how the new system could be extended.

Error containers and backward compatibility

Heavy changes to the various error containers were necessary in order to support the features above, specifically Form.errors, django.forms.utils.ErrorList, and the internal storages of ValidationError. These containers which used to store error strings now store ValidationError instances and public APIs have been adapted to make this as transparent as possible, but if you’ve been using private APIs, some of the changes are backwards incompatible; see ValidationError constructor and internal storage for more details.

Minor features

django.contrib.admin

django.contrib.auth

django.contrib.formtools

  • Calls to WizardView.done() now include a form_dict to allow easier access to forms by their step name.

django.contrib.gis

  • The default OpenLayers library version included in widgets has been updated from 2.11 to 2.13.
  • Prepared geometries now also support the crosses, disjoint, overlaps, touches and within predicates, if GEOS 3.3 or later is installed.

django.contrib.messages

django.contrib.redirects

django.contrib.sessions

  • The "django.contrib.sessions.backends.cached_db" session backend now respects SESSION_CACHE_ALIAS. In previous versions, it always used the default cache.

django.contrib.sitemaps

django.contrib.sites

django.contrib.staticfiles

  • The static files storage classes may be subclassed to override the permissions that collected static files and directories receive by setting the file_permissions_mode and directory_permissions_mode parameters. See collectstatic for example usage.

  • The CachedStaticFilesStorage backend gets a sibling class called ManifestStaticFilesStorage that doesn’t use the cache system at all but instead a JSON file called staticfiles.json for storing the mapping between the original file name (e.g. css/styles.css) and the hashed file name (e.g. css/styles.55e7cbb9ba48.css). The staticfiles.json file is created when running the collectstatic management command and should be a less expensive alternative for remote storages such as Amazon S3.

    See the ManifestStaticFilesStorage docs for more information.

  • findstatic now accepts verbosity flag level 2, meaning it will show the relative paths of the directories it searched. See findstatic for example output.

django.contrib.syndication

  • The Atom1Feed syndication feed’s updated element now utilizes updateddate instead of pubdate, allowing the published element to be included in the feed (which relies on pubdate).

Cache

  • Access to caches configured in CACHES is now available via django.core.cache.caches. This dict-like object provides a different instance per thread. It supersedes django.core.cache.get_cache() which is now deprecated.
  • If you instantiate cache backends directly, be aware that they aren’t thread-safe any more, as django.core.cache.caches now yields different instances per thread.
  • Defining the TIMEOUT argument of the CACHES setting as None will set the cache keys as 《non-expiring》 by default. Previously, it was only possible to pass timeout=None to the cache backend’s set() method.

Cross Site Request Forgery

  • The CSRF_COOKIE_AGE setting facilitates the use of session-based CSRF cookies.

Email

  • send_mail() now accepts an html_message parameter for sending a multipart text/plain and text/html email.
  • The SMTP EmailBackend now accepts a timeout parameter.

File Storage

  • File locking on Windows previously depended on the PyWin32 package; if it wasn’t installed, file locking failed silently. That dependency has been removed, and file locking is now implemented natively on both Windows and Unix.

File Uploads

  • The new UploadedFile.content_type_extra attribute contains extra parameters passed to the content-type header on a file upload.
  • The new FILE_UPLOAD_DIRECTORY_PERMISSIONS setting controls the file system permissions of directories created during file upload, like FILE_UPLOAD_PERMISSIONS does for the files themselves.
  • The FileField.upload_to attribute is now optional. If it is omitted or given None or an empty string, a subdirectory won’t be used for storing the uploaded files.
  • Uploaded files are now explicitly closed before the response is delivered to the client. Partially uploaded files are also closed as long as they are named file in the upload handler.
  • Storage.get_available_name() now appends an underscore plus a random 7 character alphanumeric string (e.g. "_x3a1gho"), rather than iterating through an underscore followed by a number (e.g. "_1", "_2", etc.) to prevent a denial-of-service attack. This change was also made in the 1.6.6, 1.5.9, and 1.4.14 security releases.

Forms

  • The <label> and <input> tags rendered by RadioSelect and CheckboxSelectMultiple when looping over the radio buttons or checkboxes now include for and id attributes, respectively. Each radio button or checkbox includes an id_for_label attribute to output the element’s ID.
  • The <textarea> tags rendered by Textarea now include a maxlength attribute if the TextField model field has a max_length.
  • Field.choices now allows you to customize the 《empty choice》 label by including a tuple with an empty string or None for the key and the custom label as the value. The default blank option "----------" will be omitted in this case.
  • MultiValueField allows optional subfields by setting the require_all_fields argument to False. The required attribute for each individual field will be respected, and a new incomplete validation error will be raised when any required fields are empty.
  • The clean() method on a form no longer needs to return self.cleaned_data. If it does return a changed dictionary then that will still be used.
  • After a temporary regression in Django 1.6, it’s now possible again to make TypedChoiceField coerce method return an arbitrary value.
  • SelectDateWidget.months can be used to customize the wording of the months displayed in the select widget.
  • The min_num and validate_min parameters were added to formset_factory() to allow validating a minimum number of submitted forms.
  • The metaclasses used by Form and ModelForm have been reworked to support more inheritance scenarios. The previous limitation that prevented inheriting from both Form and ModelForm simultaneously have been removed as long as ModelForm appears first in the MRO.
  • It’s now possible to remove a field from a Form when subclassing by setting the name to None.
  • It’s now possible to customize the error messages for ModelForm’s unique, unique_for_date, and unique_together constraints. In order to support unique_together or any other NON_FIELD_ERROR, ModelForm now looks for the NON_FIELD_ERROR key in the error_messages dictionary of the ModelForm’s inner Meta class. See considerations regarding model’s error_messages for more details.

Internationalization

  • The django.middleware.locale.LocaleMiddleware.response_redirect_class attribute allows you to customize the redirects issued by the middleware.
  • The LocaleMiddleware now stores the user’s selected language with the session key _language. This should only be accessed using the LANGUAGE_SESSION_KEY constant. Previously it was stored with the key django_language and the LANGUAGE_SESSION_KEY constant did not exist, but keys reserved for Django should start with an underscore. For backwards compatibility django_language is still read from in 1.7. Sessions will be migrated to the new key as they are written.
  • The blocktrans tag now supports a trimmed option. This option will remove newline characters from the beginning and the end of the content of the {% blocktrans %} tag, replace any whitespace at the beginning and end of a line and merge all lines into one using a space character to separate them. This is quite useful for indenting the content of a {% blocktrans %} tag without having the indentation characters end up in the corresponding entry in the PO file, which makes the translation process easier.
  • When you run makemessages from the root directory of your project, any extracted strings will now be automatically distributed to the proper app or project message file. See Localization: how to create language files for details.
  • The makemessages command now always adds the --previous command line flag to the msgmerge command, keeping previously translated strings in po files for fuzzy strings.
  • The following settings to adjust the language cookie options were introduced: LANGUAGE_COOKIE_AGE, LANGUAGE_COOKIE_DOMAIN and LANGUAGE_COOKIE_PATH.
  • Added Format localization for Esperanto.

Management Commands

  • The new --no-color option for django-admin disables the colorization of management command output.

  • The new dumpdata --natural-foreign and dumpdata --natural-primary options, and the new use_natural_foreign_keys and use_natural_primary_keys arguments for serializers.serialize(), allow the use of natural primary keys when serializing.

  • It is no longer necessary to provide the cache table name or the --database option for the createcachetable command. Django takes this information from your settings file. If you have configured multiple caches or multiple databases, all cache tables are created.

  • The runserver command received several improvements:

    • On Linux systems, if pyinotify is installed, the development server will reload immediately when a file is changed. Previously, it polled the filesystem for changes every second. That caused a small delay before reloads and reduced battery life on laptops.
    • In addition, the development server automatically reloads when a translation file is updated, i.e. after running compilemessages.
    • All HTTP requests are logged to the console, including requests for static files or favicon.ico that used to be filtered out.
  • Management commands can now produce syntax colored output under Windows if the ANSICON third-party tool is installed and active.

  • collectstatic command with symlink option is now supported on Windows NT 6 (Windows Vista and newer).

  • Initial SQL data now works better if the sqlparse Python library is installed.

    Note that it’s deprecated in favor of the RunSQL operation of migrations, which benefits from the improved behavior.

Models

  • The QuerySet.update_or_create() method was added.
  • The new default_permissions model Meta option allows you to customize (or disable) creation of the default add, change, and delete permissions.
  • Explicit OneToOneField for 다중 테이블 상속 are now discovered in abstract classes.
  • It is now possible to avoid creating a backward relation for OneToOneField by setting its related_name to '+' or ending it with '+'.
  • F expressions support the power operator (**).
  • The remove() and clear() methods of the related managers created by ForeignKey and GenericForeignKey now accept the bulk keyword argument to control whether or not to perform operations in bulk (i.e. using QuerySet.update()). Defaults to True.
  • It is now possible to use None as a query value for the iexact lookup.
  • It is now possible to pass a callable as value for the attribute limit_choices_to when defining a ForeignKey or ManyToManyField.
  • Calling only() and defer() on the result of QuerySet.values() now raises an error (before that, it would either result in a database error or incorrect data).
  • You can use a single list for index_together (rather than a list of lists) when specifying a single set of fields.
  • Custom intermediate models having more than one foreign key to any of the models participating in a many-to-many relationship are now permitted, provided you explicitly specify which foreign keys should be used by setting the new ManyToManyField.through_fields argument.
  • Assigning a model instance to a non-relation field will now throw an error. Previously this used to work if the field accepted integers as input as it took the primary key.
  • Integer fields are now validated against database backend specific min and max values based on their internal_type. Previously model field validation didn’t prevent values out of their associated column data type range from being saved resulting in an integrity error.
  • It is now possible to explicitly order_by() a relation _id field by using its attribute name.

Signals

  • The enter argument was added to the setting_changed signal.
  • The model signals can be now be connected to using a str of the 'app_label.ModelName' form – just like related fields – to lazily reference their senders.

Templates

  • The Context.push() method now returns a context manager which automatically calls pop() upon exiting the with statement. Additionally, push() now accepts parameters that are passed to the dict constructor used to build the new context level.
  • The new Context.flatten() method returns a Context’s stack as one flat dictionary.
  • Context objects can now be compared for equality (internally, this uses Context.flatten() so the internal structure of each Context’s stack doesn’t matter as long as their flattened version is identical).
  • The widthratio template tag now accepts an "as" parameter to capture the result in a variable.
  • The include template tag will now also accept anything with a render() method (such as a Template) as an argument. String arguments will be looked up using get_template() as always.
  • It is now possible to include templates recursively.
  • Template objects now have an origin attribute set when TEMPLATE_DEBUG is True. This allows template origins to be inspected and logged outside of the django.template infrastructure.
  • TypeError exceptions are no longer silenced when raised during the rendering of a template.
  • The following functions now accept a dirs parameter which is a list or tuple to override TEMPLATE_DIRS:
  • The time filter now accepts timezone-related format specifiers 'e', 'O' , 'T' and 'Z' and is able to digest time-zone-aware datetime instances performing the expected rendering.
  • The cache tag will now try to use the cache called 《template_fragments》 if it exists and fall back to using the default cache otherwise. It also now accepts an optional using keyword argument to control which cache it uses.
  • The new truncatechars_html filter truncates a string to be no longer than the specified number of characters, taking HTML into account.

Requests and Responses

Tests

  • DiscoverRunner has two new attributes, test_suite and test_runner, which facilitate overriding the way tests are collected and run.
  • The fetch_redirect_response argument was added to assertRedirects(). Since the test client can’t fetch externals URLs, this allows you to use assertRedirects with redirects that aren’t part of your Django app.
  • Correct handling of scheme when making comparisons in assertRedirects().
  • The secure argument was added to all the request methods of Client. If True, the request will be made through HTTPS.
  • assertNumQueries() now prints out the list of executed queries if the assertion fails.
  • The WSGIRequest instance generated by the test handler is now attached to the django.test.Response.wsgi_request attribute.
  • The database settings for testing have been collected into a dictionary named TEST.

Utilities

  • Improved strip_tags() accuracy (but it still cannot guarantee an HTML-safe result, as stated in the documentation).

Validators

  • RegexValidator now accepts the optional flags and Boolean inverse_match arguments. The inverse_match attribute determines if the ValidationError should be raised when the regular expression pattern matches (True) or does not match (False, by default) the provided value. The flags attribute sets the flags used when compiling a regular expression string.
  • URLValidator now accepts an optional schemes argument which allows customization of the accepted URI schemes (instead of the defaults http(s) and ftp(s)).
  • validate_email() now accepts addresses with IPv6 literals, like example@[2001:db8::1], as specified in RFC 5321.

Backwards incompatible changes in 1.7

경고

In addition to the changes outlined in this section, be sure to review the deprecation plan for any features that have 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.

allow_syncdb / allow_migrate

While Django will still look at allow_syncdb methods even though they should be renamed to allow_migrate, there is a subtle difference in which models get passed to these methods.

For apps with migrations, allow_migrate will now get passed historical models, which are special versioned models without custom attributes, methods or managers. Make sure your allow_migrate methods are only referring to fields or other items in model._meta.

initial_data

Apps with migrations will not load initial_data fixtures when they have finished migrating. Apps without migrations will continue to load these fixtures during the phase of migrate which emulates the old syncdb behavior, but any new apps will not have this support.

Instead, you are encouraged to load initial data in migrations if you need it (using the RunPython operation and your model classes); this has the added advantage that your initial data will not need updating every time you change the schema.

Additionally, like the rest of Django’s old syncdb code, initial_data has been started down the deprecation path and will be removed in Django 1.9.

deconstruct() and serializability

Django now requires all Field classes and all of their constructor arguments to be serializable. If you modify the constructor signature in your custom Field in any way, you’ll need to implement a deconstruct() method; we’ve expanded the custom field documentation with instructions on implementing this method.

The requirement for all field arguments to be serializable means that any custom class instances being passed into Field constructors - things like custom Storage