Context Navigation

Removing the magic

The "magic-removal" branch aims to make several sweeping changes to the Django codebase, removing warts that Django has accumulated over the years. Most changes involve the database API and removing some of its unneeded magic, and other changes involve improving the framework's simplicity and usability.

These changes will be integrated into the next Django release, 0.92.

This document explains the changes in the branch.

How to get the branch

Overview

The biggest changes in magic-removal are:

The magic package django.models no longer exists. To use models, just import the model class from wherever it lives on the Python path. Similarly, the magic modules (such as django.models.polls in the tutorial) no longer exist; now, you interact directly with the model class.

All automatic pluralization is gone.

The database API has changed in several ways.

Various packages, such as the Django template system (previously in django.core.template), have been moved around to make importing less verbose and easier to remember.

Status

Not for the faint of heart at this point. Still being heavily developed.

Database changes you'll need to make

To upgrade from a previous Django installation, you'll need to make some database changes. Obviously, this doesn't apply if you're starting from scratch.

Rename core database tables

We've renamed a bunch of the core Django tables. To upgrade in MySQL and SQLite, execute this SQL in your database:

Database table-naming scheme has been changed

Database table names formerly were created by joining the app_label and module_name. Example: polls_polls.

Because there's no longer any concept of module_name, database table names are now formed by joining the app_label and model class name (lower case). Example: polls_poll.

As always, this behavior can be overridden on a per-model basis by specifying the db_table attribute in class Meta in your model.

To upgrade, you'll either have to explicitly set db_table in your models or rename your database tables to fit the new naming scheme Django expects. We'd recommend setting db_table, because it's easier.

Code changes you'll need to make

Model class and Field classes renamed/relocated

Change your models to import from django.db.models instead of django.core.meta.

The "auth" and "core" models have been split and moved to django.contrib as follows:

django.models.auth has moved to django.contrib.auth.models.

django.models.core.sites has moved to django.contrib.sites.models.

django.models.core.contenttypes has moved to django.contrib.contenttypes.models.

django.models.core.packages has moved to django.contrib.contenttypes.models. (Note that "packages" are going away before magic-removal is done.)

Session middleware has moved from django.middleware.sessions.SessionMiddleware to django.contrib.sessions.middleware.SessionMiddleware. Make sure to update your MIDDLEWARE_CLASSES setting, if you're using sessions.

Also, the Session model has moved from django/models/core.py to django/contrib/sessions/models.py. If you're accessing the Session model for some reason, note that location change.

Changes to model syntax

class META should now be class Meta. The latter is easier on the eyes.

The following are no longer valid parameters to class Meta and should be removed:

module_name

admin (See "Moved admin options to 'class Admin'" below.)

exceptions (Just put your exceptions in the module that contains the models and access them normally.)

module_constants (Just put your constants in the module that contains the models and access them normally.)

where_constraints (Just use a custom manager. See "Custom managers, and multiple managers" below.)

Moved admin options to 'class Admin'

Instead of admin=meta.Admin in the class META, all admin options are in an inner class Admin.

Database connection relocated/renamed

For any code that uses the raw database connection, use django.db.connection instead of django.core.db.db.

Old:

fromdjango.core.dbimport db
cursor = db.cursor()

New:

fromdjango.dbimport connection
cursor = connection.cursor()

Backend-specific functions, if you should need them, are available at django.db.backend.

Old:

fromdjango.coreimport db
db.quote_name('foo')

New:

fromdjango.dbimport backend
backend.quote_name('foo')

Also, the various backend functionality has been split into three separate modules for each backend -- base.py, creation.py and introspection.py. This is purely for performance and memory savings, so that basic, everyday Django usage doesn't have to load the introspective functionality into memory.

Model methods no longer automatically have access to datetime and db modules

Formerly, each model method magically had access to the datetime module and to the variable db, which represents the current database connection. Now, those have to be imported explicitly.

Descriptor fields

All "table-level" functions -- ways of retrieving records tablewide rather than performing instance-specific tasks -- are now accessed via a model class's objects attribute. They aren't direct methods of a model instance object because we want to keep the "table-wide" and "row-specific" namespaces separate.

A model class's objects attribute is an instance of django.db.models.manager.Manager. A manager has the following methods, all of which return a QuerySet instance.

all() -- Returns a QuerySet of all objects in the database. This is like the old get_list(). Takes no arguments.

filter(**kwargs) -- Returns a QuerySet, filtered by the given keyword arguments. Lookup arguments are in the same style as previously, e.g. pubdate__year=2005, except you can leave off __exact as a convenience. For example, name='John' and name__exact='John' are equivalent.

order_by(*fieldnames) -- Returns a QuerySet

count() -- Returns the count of all objects in the database.

dates(field_name, kind) -- Like the old get_FIELD_list() for date fields. For example, old-school get_pubdate_list('year') is now dates('pubdate', 'year').

delete() -- Deletes all objects.

distinct() -- Returns a QuerySet with DISTINCT set.

extra(select=None, where=None, params=None, tables=None) -- Sets the select, where, params and tables arguments, which are in the same format as before.

get(**kwargs) -- Like the old get_object(). Returns an object or raises DoesNotExist on error.

in_bulk(id_list) -- Like the old get_in_bulk().

iterator() -- Returns a generator that iterators over results.

select_related() -- Returns a QuerySet with the "select related" option (which acts the same as before) set.

values(*fieldnames) -- Like the old get_values().

Each QuerySet has the following methods, which return a clone of the query set with the appropriate changes made:

Note that related-object lookup uses the default manager of the related object, which means the API for accessing related objects is completely consistent with the API for accessing objects via a manager.

Also note that managers can't be accessed from instances:

p = Person.objects.get(pk=1)
p.objects.all()# Raises AttributeError

Override default manager name ("objects")

If a model already has an objects attribute, you'll need to specify an alternate name for the objects manager.

Proper subclassing of methods now works, so you can subclass the automatic save() and delete() methods. This removes the need for the _pre_save(), _post_save(), _pre_delete() and _post_delete() hooks -- all of which have been removed. Example:

Moved admin URLconf to shorten its path

get_object_or_404 and get_list_or_404 now take model classes, not modules

Old:

get_object_or_404(polls, pk=1)

New:

get_object_or_404(Poll, pk=1)

Changed the parameters you pass to generic views

Because there's no longer a concept of module_name, the "info_dicts" passed to ​generic views no longer accept "app_label" and "module_name". Instead, pass the parameter "model", which should be your model class.

These examples assume models live in myproject/blog/models.py.

Old:

info_dict ={'app_label':'blog','module_name':'entries'}

New:

frommyproject.blog.modelsimport Entry
info_dict ={'model': Entry}

Changed template names in generic views

Because there's no longer a concept of module_name, ​generic views no longer create templates based on the module_name. Wherever they used module_name, they now use model_name, a lowercase version of the model name.

Note that app_label remains the same.

These examples assume models live in myproject/blog/models.py.

Old: blog/entries_archive.html

New: blog/entry_archive.html

Moved settings into an instance

Settings have moved out of a dedicated module django.conf.settings into an instance in the django.conf module. So now you need to import the settings object and reference settings as attributes of that instance.

Old: from django.conf.settings import LANGUAGE_CODE

New: from django.conf import settings

Wrappers around the Django machinery can make use of this by exchanging the settings instance with a proxy instance that delegates attribute access to a per-thread or per-location global.

Removed SilentVariableFailure exception

Old behavior: Any exception that subclasses django.core.template.SilentVariableFailure fails silently in the template system.

New behavior: Any exception that has a silent_variable_failure attribute fails silently in the template system. django.core.template.SilentVariableFailure no longer exists.