- Django 1.7 版本发行说明
- Django 1.7 版本发行说明
- Python 兼容性
- What’s new in Django 1.7
- Schema migrations
- App-loading refactor
- New method on Field subclasses
- Calling custom QuerySet methods from the Manager
- Using a custom manager when traversing reverse relations
- New system check framework
- New Prefetch object for advanced prefetch_related operations.
- Admin shortcuts support time zones
- Using database cursors as context managers
- Custom lookups
- Improvements to Form error handling
Django 1.7 版本发行说明
Django 1.7 版本发行说明
2014 年 9 月 2 日
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 兼容性
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:
-
syncdbhas been deprecated and replaced bymigrate. Don’t worry - calls tosyncdbwill still work as before. -
A new
makemigrationscommand 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_syncdbmethod on database routers is now calledallow_migrate, but still performs the same function. Routers withallow_syncdbmethods 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_datafixtures 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 theoperationssection 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
TransactionTestCaseunless 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.pyentirely 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, orNoneif it is not part of a modelpath: A dotted, Python path to the class of this field, including the class name.args: Positional arguments, as a listkwargs: 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
QuerySetand its custom methods were lost after the first call tovalues()orvalues_list(). - Writing a custom
Managerwas still necessary to return the customQuerySetclass and all methods that were desired on theManagerhad to be proxied to theQuerySet. 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.
New Prefetch object for advanced prefetch_related operations.
The new Prefetch object allows customizing prefetch operations.
You can specify the QuerySet used to traverse a given relation or customize the storage location of prefetch results.
This enables things like filtering prefetched relations, calling select_related() from a prefetched relation, or prefetching the same relation multiple times with different querysets. See prefetch_related() for more details.
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(...)
替换成:
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>(), orForm.clean()for non-field errors.) - Fiddling with
Form._errorswhen targeting a specific field inForm.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 清理和验证相互依赖的字段 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 引发 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.
(本文超出站点单文档体积上限,已按小节截断)
