diff options
| author | Adrian Holovaty <adrian@holovaty.com> | 2006-05-02 01:31:56 +0000 |
|---|---|---|
| committer | Adrian Holovaty <adrian@holovaty.com> | 2006-05-02 01:31:56 +0000 |
| commit | f69cf70ed813a8cd7e1f963a14ae39103e8d5265 (patch) | |
| tree | d3b32e84cd66573b3833ddf662af020f8ef2f7a8 /docs | |
| parent | d5dbeaa9be359a4c794885c2e9f1b5a7e5e51fb8 (diff) | |
MERGED MAGIC-REMOVAL BRANCH TO TRUNK. This change is highly backwards-incompatible. Please read http://code.djangoproject.com/wiki/RemovingTheMagic for upgrade instructions.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
35 files changed, 4638 insertions, 2476 deletions
diff --git a/docs/add_ons.txt b/docs/add_ons.txt index 44354d9c82..e602e429ad 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -12,9 +12,9 @@ admin ===== The automatic Django administrative interface. For more information, see -`Tutorial 3`_. +`Tutorial 2`_. -.. _Tutorial 3: http://www.djangoproject.com/documentation/tutorial2/ +.. _Tutorial 2: http://www.djangoproject.com/documentation/tutorial2/ comments ======== diff --git a/docs/admin_css.txt b/docs/admin_css.txt index 419e0bcd42..069012a84b 100644 --- a/docs/admin_css.txt +++ b/docs/admin_css.txt @@ -28,11 +28,13 @@ Column Types .. admonition:: Note - In the Django development version, all admin pages (except the dashboard) are fluid-width. All fixed-width classes have been removed. + All admin pages (except the dashboard) are fluid-width. All fixed-width + classes from previous Django versions have been removed. The base template for each admin page has a block that defines the column structure for the page. This sets a class on the page content area -(``div#content``) so everything on the page knows how wide it should be. There are three column types available. +(``div#content``) so everything on the page knows how wide it should be. There +are three column types available. colM This is the default column setting for all pages. The "M" stands for "main". @@ -46,39 +48,12 @@ colMS colSM Same as above, with the sidebar on the left. The source order of the columns doesn't matter. -colM superwide (removed in Django development version) - This is for ridiculously wide pages. Doesn't really work very well for - anything but colM. With superwide, you've got 1000px to work with. Don't - waste them. -flex (removed in Django development version) - This is for liquid-width pages, such as changelists. Currently only works - with single-column pages (does not combine with ``.colMS`` or ``.colSM``). - Form pages should never use ``.flex``. -For instance, you could stick this in a template to make a two-column page with the sidebar on the right:: +For instance, you could stick this in a template to make a two-column page with +the sidebar on the right:: {% block coltype %}colMS{% endblock %} - -Widths -====== - -**Removed in Django development version (see note above).** - -There's a whole mess of classes in the stylesheet for custom pixel widths on -objects. They come in handy for tables and table cells, if you want to avoid -using the ``width`` attribute. Each class sets the width to the number of pixels -in the class, except ``.xfull`` which will always be the width of the column -it's in. (This helps with tables that you want to always fill the horizontal -width, without using ``width="100%"`` which makes IE 5's box model cry.) - -**Note:** Within a ``.flex`` page, the ``.xfull`` class will ``usually`` set -to 100%, but there are exceptions and still some untested cases. - -Available width classes:: - - .x50 .x75 .x100 .x150 .x200 .x250 .x300 .x400 .x500 .xfull - Text Styles =========== @@ -107,17 +82,18 @@ There are also a few styles for styling text. .help This is a custom class for blocks of inline help text explaining the function of form elements. It makes text smaller and gray, and when applied - to ``p`` elements withing ``.form-row`` elements (see Form Styles below), it will - offset the text to align with the form field. Use this for help text, - instead of ``small quiet``. It works on other elements, but try to put the class - on a ``p`` whenever you can. + to ``p`` elements withing ``.form-row`` elements (see Form Styles below), + it will offset the text to align with the form field. Use this for help + text, instead of ``small quiet``. It works on other elements, but try to + put the class on a ``p`` whenever you can. .align-left - It aligns the text left. Only works on block elements containing inline elements. + It aligns the text left. Only works on block elements containing inline + elements. .align-right Are you paying attention? .nowrap - Keeps text and inline objects from wrapping. Comes in handy for table headers you want to stay - on one line. + Keeps text and inline objects from wrapping. Comes in handy for table + headers you want to stay on one line. Floats and Clears ----------------- @@ -173,9 +149,10 @@ Each fieldset can also take extra classes in addition to ``.module`` to apply appropriate formatting to the group of fields. .aligned - this will align the labels and inputs side by side on the same line. + This will align the labels and inputs side by side on the same line. .wide - used in combination with ``.aligned`` to widen the space available for the labels. + Used in combination with ``.aligned`` to widen the space available for the + labels. Form Rows --------- diff --git a/docs/authentication.txt b/docs/authentication.txt index 4c45ec6759..8f618f8a20 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -6,13 +6,8 @@ Django comes with a user authentication system. It handles user accounts, groups, permissions and cookie-based user sessions. This document explains how things work. -The basics -========== - -Django supports authentication out of the box. The ``django-admin.py init`` -command, used to initialize a database with Django's core database tables, -creates the infrastructure for the auth system. You don't have to do anything -else to use authentication. +Overview +======== The auth system consists of: @@ -23,13 +18,35 @@ The auth system consists of: user. * Messages: A simple way to queue messages for given users. +Installation +============ + +Authentication support is bundled as a Django application in +``django.contrib.auth``. To install it, do the following: + + 1. Put ``'django.contrib.auth'`` in your ``INSTALLED_APPS`` setting. + 2. Run the command ``manage.py syncdb``. + +Note that the default ``settings.py`` file created by +``django-admin.py startproject`` includes ``'django.contrib.auth'`` in +``INSTALLED_APPS`` for convenience. If your ``INSTALLED_APPS`` already contains +``'django.contrib.auth'``, feel free to run ``manage.py syncdb`` again; you +can run that command as many times as you'd like, and each time it'll only +install what's needed. + +The ``syncdb`` command creates the necessary database tables, creates +permission objects for all installed apps that need 'em, and prompts you to +create a superuser account. + +Once you've taken those steps, that's it. + Users ===== Users are represented by a standard Django model, which lives in -`django/models/auth.py`_. +`django/contrib/auth/models.py`_. -.. _django/models/auth.py: http://code.djangoproject.com/browser/django/trunk/django/models/auth.py +.. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py API reference ------------- @@ -62,16 +79,20 @@ Methods ~~~~~~~ ``User`` objects have two many-to-many fields: ``groups`` and -``user_permissions``. Because of those relationships, ``User`` objects get -data-access methods like any other `Django model`_: +``user_permissions``. ``User`` objects can access their related +objects in the same way as any other `Django model`_:: - * ``get_group_list(**kwargs)`` - * ``set_groups(id_list)`` - * ``get_permission_list(**kwargs)`` - * ``set_user_permissions(id_list)`` + ``myuser.objects.groups = [group_list]`` + ``myuser.objects.groups.add(group, group,...)`` + ``myuser.objects.groups.remove(group, group,...)`` + ``myuser.objects.groups.clear()`` + ``myuser.objects.permissions = [permission_list]`` + ``myuser.objects.permissions.add(permission, permission, ...)`` + ``myuser.objects.permissions.remove(permission, permission, ...]`` + ``myuser.objects.permissions.clear()`` In addition to those automatic API methods, ``User`` objects have the following -methods: +custom methods: * ``is_anonymous()`` -- Always returns ``False``. This is a way of comparing ``User`` objects to anonymous users. @@ -80,11 +101,12 @@ methods: with a space in between. * ``set_password(raw_password)`` -- Sets the user's password to the given - raw string, taking care of the MD5 hashing. Doesn't save the ``User`` - object. + raw string, taking care of the password hashing. Doesn't save the + ``User`` object. * ``check_password(raw_password)`` -- Returns ``True`` if the given raw - string is the correct password for the user. + string is the correct password for the user. (This takes care of the + password hashing in making the comparison.) * ``get_group_permissions()`` -- Returns a list of permission strings that the user has, through his/her groups. @@ -110,23 +132,25 @@ methods: `DEFAULT_FROM_EMAIL`_ setting. * ``get_profile()`` -- Returns a site-specific profile for this user. - Raises ``django.models.auth.SiteProfileNotAvailable`` if the current site + Raises ``django.contrib.auth.models.SiteProfileNotAvailable`` if the current site doesn't allow profiles. .. _Django model: http://www.djangoproject.com/documentation/model_api/ .. _DEFAULT_FROM_EMAIL: http://www.djangoproject.com/documentation/settings/#default-from-email -Module functions -~~~~~~~~~~~~~~~~ +Manager functions +~~~~~~~~~~~~~~~~~ -The ``django.models.auth.users`` module has the following helper functions: +The ``User`` model has a custom manager that has the following helper functions: * ``create_user(username, email, password)`` -- Creates, saves and returns a ``User``. The ``username``, ``email`` and ``password`` are set as given, and the ``User`` gets ``is_active=True``. + See _`Creating users` for example usage. + * ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')`` - -- Returns a random password with the given length and given string of + Returns a random password with the given length and given string of allowed characters. (Note that the default value of ``allowed_chars`` doesn't contain ``"I"`` or letters that look like it, to avoid user confusion. @@ -140,11 +164,12 @@ Creating users The most basic way to create users is to use the ``create_user`` helper function that comes with Django:: - >>> from django.models.auth import users - >>> user = users.create_user('john', 'lennon@thebeatles.com', 'johnpassword') + >>> from django.contrib.auth.models import User + >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') - # Now, user is a User object already saved to the database. - # You can continue to change its attributes if you want to change other fields. + # At this point, user is a User object ready to be saved + # to the database. You can continue to change its attributes + # if you want to change other fields. >>> user.is_staff = True >>> user.save() @@ -153,28 +178,26 @@ Changing passwords Change a password with ``set_password()``:: - >>> from django.models.auth import users - >>> u = users.get_object(username__exact='john') + >>> from django.contrib.auth.models import User + >>> u = User.objects.get(username__exact='john') >>> u.set_password('new password') >>> u.save() -Don't set the password field directly unless you know what you're doing. This -is explained in the next section. +Don't set the ``password`` attribute directly unless you know what you're +doing. This is explained in the next section. Passwords --------- -Previous versions, such as Django 0.90, used simple MD5 hashes without password -salts. - -The ``password`` field of a ``User`` object is a string in this format:: +The ``password`` attribute of a ``User`` object is a string in this format:: hashtype$salt$hash That's hashtype, salt and hash, separated by the dollar-sign character. -Hashtype is either ``sha1`` (default) or ``md5``. Salt is a random string -used to salt the raw password to create the hash. +Hashtype is either ``sha1`` (default) or ``md5`` -- the algorithm used to +perform a one-way hash of the password. Salt is a random string used to salt +the raw password to create the hash. For example:: @@ -183,17 +206,22 @@ For example:: The ``User.set_password()`` and ``User.check_password()`` functions handle the setting and checking of these values behind the scenes. +Previous Django versions, such as 0.90, used simple MD5 hashes without password +salts. For backwards compatibility, those are still supported; they'll be +converted automatically to the new style the first time ``check_password()`` +works correctly for a given user. + Anonymous users --------------- -``django.parts.auth.anonymoususers.AnonymousUser`` is a class that implements -the ``django.models.auth.users.User`` interface, with these differences: +``django.contrib.auth.models.AnonymousUser`` is a class that implements +the ``django.contirb.auth.models.User`` interface, with these differences: * ``id`` is always ``None``. * ``is_anonymous()`` returns ``True`` instead of ``False``. * ``has_perm()`` always returns ``False``. - * ``set_password()``, ``check_password()``, ``set_groups()`` and - ``set_permissions()`` raise ``NotImplementedError``. + * ``set_password()``, ``check_password()``, ``save()``, ``delete()``, + ``set_groups()`` and ``set_permissions()`` raise ``NotImplementedError``. In practice, you probably won't need to use ``AnonymousUser`` objects on your own, but they're used by Web requests, as explained in the next section. @@ -202,10 +230,15 @@ Authentication in Web requests ============================== Until now, this document has dealt with the low-level APIs for manipulating -authentication-related objects. On a higher level, Django hooks this +authentication-related objects. On a higher level, Django can hook this authentication framework into its system of `request objects`_. -In any Django view, ``request.user`` will give you a ``User`` object +First, install the ``SessionMiddleware`` and ``AuthenticationMiddleware`` +middlewares by adding them to your ``MIDDLEWARE_CLASSES`` setting. See the +`session documentation`_ for more information. + +Once you have those middlewares installed, you'll be able to access +``request.user`` in views. ``request.user`` will give you a ``User`` object representing the currently logged-in user. If a user isn't currently logged in, ``request.user`` will be set to an instance of ``AnonymousUser`` (see the previous section). You can tell them apart with ``is_anonymous()``, like so:: @@ -215,10 +248,6 @@ previous section). You can tell them apart with ``is_anonymous()``, like so:: else: # Do something for logged-in users. -If you want to use ``request.user`` in your view code, make sure you have -``SessionMiddleware`` enabled. See the `session documentation`_ for more -information. - .. _request objects: http://www.djangoproject.com/documentation/request_response/#httprequest-objects .. _session documentation: http://www.djangoproject.com/documentation/sessions/ @@ -227,8 +256,8 @@ How to log a user in To log a user in, do the following within a view:: - from django.models.auth import users - request.session[users.SESSION_KEY] = some_user.id + from django.contrib.auth.models import SESSION_KEY + request.session[SESSION_KEY] = some_user.id Because this uses sessions, you'll need to make sure you have ``SessionMiddleware`` enabled. See the `session documentation`_ for more @@ -246,7 +275,7 @@ The raw way The simple, raw way to limit access to pages is to check ``request.user.is_anonymous()`` and either redirect to a login page:: - from django.utils.httpwrappers import HttpResponseRedirect + from django.http import HttpResponseRedirect def my_view(request): if request.user.is_anonymous(): @@ -257,7 +286,7 @@ The simple, raw way to limit access to pages is to check def my_view(request): if request.user.is_anonymous(): - return render_to_response('myapp/login_error') + return render_to_response('myapp/login_error.html') # ... The login_required decorator @@ -265,15 +294,16 @@ The login_required decorator As a shortcut, you can use the convenient ``login_required`` decorator:: - from django.views.decorators.auth import login_required + from django.contrib.auth.decorators import login_required def my_view(request): # ... my_view = login_required(my_view) -Here's the same thing, using Python 2.4's decorator syntax:: +Here's an equivalent example, using the more compact decorator syntax +introduced in Python 2.4:: - from django.views.decorators.auth import login_required + from django.contrib.auth.decorators import login_required @login_required def my_view(request): @@ -304,7 +334,7 @@ permission ``polls.can_vote``:: As a shortcut, you can use the convenient ``user_passes_test`` decorator:: - from django.views.decorators.auth import user_passes_test + from django.contrib.auth.decorators import user_passes_test def my_view(request): # ... @@ -312,7 +342,7 @@ As a shortcut, you can use the convenient ``user_passes_test`` decorator:: Here's the same thing, using Python 2.4's decorator syntax:: - from django.views.decorators.auth import user_passes_test + from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.has_perm('polls.can_vote')) def my_view(request): @@ -328,7 +358,7 @@ specify the URL for your login page (``/accounts/login/`` by default). Example in Python 2.3 syntax:: - from django.views.decorators.auth import user_passes_test + from django.contrib.auth.decorators import user_passes_test def my_view(request): # ... @@ -336,7 +366,7 @@ Example in Python 2.3 syntax:: Example in Python 2.4 syntax:: - from django.views.decorators.auth import user_passes_test + from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/') def my_view(request): @@ -380,49 +410,52 @@ Permissions are set globally per type of object, not per specific object instance. For example, it's possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a -certain status or publication date." The latter functionality is something +certain status, publication date or ID." The latter functionality is something Django developers are currently discussing. Default permissions ------------------- Three basic permissions -- add, create and delete -- are automatically created -for each Django model that has ``admin`` set. Behind the scenes, these -permissions are added to the ``auth_permissions`` database table when you run -``django-admin.py install [app]``. You can view the exact SQL ``INSERT`` -statements by running ``django-admin.py sqlinitialdata [app]``. +for each Django model that has a ``class Admin`` set. Behind the scenes, these +permissions are added to the ``auth_permission`` database table when you run +``manage.py syncdb``. -Note that if your model doesn't have ``admin`` set when you run -``django-admin.py install``, the permissions won't be created. If you -initialize your database and add ``admin`` to models after the fact, you'll -need to add the permissions to the database manually. Do this by running -``django-admin.py installperms [app]``, which creates any missing permissions -for the given app. +Note that if your model doesn't have ``class Admin`` set when you run +``syncdb``, the permissions won't be created. If you initialize your database +and add ``class Admin`` to models after the fact, you'll need to run +``django-admin.py syncdb`` again. It will create any missing permissions for +all of your installed apps. Custom permissions ------------------ To create custom permissions for a given model object, use the ``permissions`` -`model META attribute`_. +`model Meta attribute`_. This example model creates three custom permissions:: - class USCitizen(meta.Model): + class USCitizen(models.Model): # ... - class META: + class Meta: permissions = ( ("can_drive", "Can drive"), ("can_vote", "Can vote in elections"), ("can_drink", "Can drink alcohol"), ) -.. _model META attribute: http://www.djangoproject.com/documentation/model_api/#meta-options +The only thing this does is create those extra permissions when you run +``syncdb``. + +.. _model Meta attribute: http://www.djangoproject.com/documentation/model_api/#meta-options API reference ------------- Just like users, permissions are implemented in a Django model that lives in -`django/models/auth.py`_. +`django/contrib/auth/models.py`_. + +.. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py Fields ~~~~~~ @@ -430,8 +463,8 @@ Fields ``Permission`` objects have the following fields: * ``name`` -- Required. 50 characters or fewer. Example: ``'Can vote'``. - * ``package`` -- Required. A reference to the ``packages`` database table, - which contains a record for each installed Django application. + * ``content_type`` -- Required. A reference to the ``django_content_type`` + database table, which contains a record for each installed Django model. * ``codename`` -- Required. 100 characters or fewer. Example: ``'can_vote'``. Methods @@ -444,21 +477,21 @@ Authentication data in templates ================================ The currently logged-in user and his/her permissions are made available in the -`template context`_ when you use ``DjangoContext``. +`template context`_ when you use ``RequestContext``. .. admonition:: Technicality Technically, these variables are only made available in the template context - if you use ``DjangoContext`` *and* your ``TEMPLATE_CONTEXT_PROCESSORS`` + if you use ``RequestContext`` *and* your ``TEMPLATE_CONTEXT_PROCESSORS`` setting contains ``"django.core.context_processors.auth"``, which is default. - For more, see the `DjangoContext docs`_. + For more, see the `RequestContext docs`_. - .. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext + .. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext Users ----- -The currently logged-in user, either a ``User`` object or an``AnonymousUser`` +The currently logged-in user, either a ``User`` instance or an``AnonymousUser`` instance, is stored in the template variable ``{{ user }}``:: {% if user.is_anonymous %} @@ -504,25 +537,25 @@ Thus, you can check permissions in template ``{% if %}`` statements:: Groups ====== -Groups are a generic way of categorizing users to apply permissions, or some -other label, to those users. A user can belong to any number of groups. +Groups are a generic way of categorizing users so you can apply permissions, or +some other label, to those users. A user can belong to any number of groups. A user in a group automatically has the permissions granted to that group. For example, if the group ``Site editors`` has the permission ``can_edit_home_page``, any user in that group will have that permission. -Beyond permissions, groups are a convenient way to categorize users to apply -some label, or extended functionality, to them. For example, you could create -a group ``'Special users'``, and you could write code that would do special -things to those users -- such as giving them access to a members-only portion -of your site, or sending them members-only e-mail messages. +Beyond permissions, groups are a convenient way to categorize users to give +them some label, or extended functionality. For example, you could create a +group ``'Special users'``, and you could write code that could, say, give them +access to a members-only portion of your site, or send them members-only e-mail +messages. Messages ======== The message system is a lightweight way to queue messages for given users. -A message is associated with a User. There's no concept of expiration or +A message is associated with a ``User``. There's no concept of expiration or timestamps. Messages are used by the Django admin after successful actions. For example, @@ -530,8 +563,9 @@ Messages are used by the Django admin after successful actions. For example, The API is simple:: - * To add messages, use ``user.add_message(message_text)``. - * To retrieve/delete messages, use ``user.get_and_delete_messages()``, + * To create a new message, use + ``user_obj.message_set.create(message='message_text')``. + * To retrieve/delete messages, use ``user_obj.get_and_delete_messages()``, which returns a list of ``Message`` objects in the user's queue (if any) and deletes the messages from the queue. @@ -541,10 +575,11 @@ a playlist:: def create_playlist(request, songs): # Create the playlist with the given songs. # ... - request.user.add_message("Your playlist was added successfully.") - return render_to_response("playlists/create", context_instance=DjangoContext(request)) + request.user.message_set.create(message="Your playlist was added successfully.") + return render_to_response("playlists/create.html", + context_instance=RequestContext(request)) -When you use ``DjangoContext``, the currently logged-in user and his/her +When you use ``RequestContext``, the currently logged-in user and his/her messages are made available in the `template context`_ as the template variable ``{{ messages }}``. Here's an example of template code that displays messages:: @@ -556,7 +591,7 @@ messages are made available in the `template context`_ as the template variable </ul> {% endif %} -Note that ``DjangoContext`` calls ``get_and_delete_messages`` behind the +Note that ``RequestContext`` calls ``get_and_delete_messages`` behind the scenes, so any messages will be deleted even if you don't display them. Finally, note that this messages framework only works with users in the user diff --git a/docs/cache.txt b/docs/cache.txt index f1f5668137..4fecdc6372 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -2,63 +2,180 @@ Django's cache framework ======================== -So, you got slashdotted_. Now what? +A fundamental tradeoff in dynamic Web sites is, well, they're dynamic. Each +time a user requests a page, the Web server makes all sorts of calculations -- +from database queries to template rendering to business logic -- to create the +page that your site's visitor sees. This is a lot more expensive, from a +processing-overhead perspective, than your standard read-a-file-off-the-filesystem +server arrangement. -Django's cache framework gives you three methods of caching dynamic pages in -memory or in a database. You can cache the output of specific views, you can -cache only the pieces that are difficult to produce, or you can cache your -entire site. +For most Web applications, this overhead isn't a big deal. Most Web +applications aren't washingtonpost.com or slashdot.org; they're simply small- +to medium-sized sites with so-so traffic. But for medium- to high-traffic +sites, it's essential to cut as much overhead as possible. -.. _slashdotted: http://en.wikipedia.org/wiki/Slashdot_effect +That's where caching comes in. + +To cache something is to save the result of an expensive calculation so that +you don't have to perform the calculation next time. Here's some pseudocode +explaining how this would work for a dynamically generated Web page: + + given a URL, try finding that page in the cache + if the page is in the cache: + return the cached page + else: + generate the page + save the generated page in the cache (for next time) + return the generated page + +Django comes with a robust cache system that lets you save dynamic pages so +they don't have to be calculated for each request. For convenience, Django +offers different levels of cache granularity: You can cache the output of +specific views, you can cache only the pieces that are difficult to produce, or +you can cache your entire site. + +Django also works well with "upstream" caches, such as Squid +(http://www.squid-cache.org/) and browser-based caches. These are the types of +caches that you don't directly control but to which you can provide hints (via +HTTP headers) about which parts of your site should be cached, and how. Setting up the cache ==================== -The cache framework allows for different "backends" -- different methods of -caching data. There's a simple single-process memory cache (mostly useful as a -fallback) and a memcached_ backend (the fastest option, by far, if you've got -the RAM). +The cache system requires a small amount of setup. Namely, you have to tell it +where your cached data should live -- whether in a database, on the filesystem +or directly in memory. This is an important decision that affects your cache's +performance; yes, some cache types are faster than others. + +Your cache preference goes in the ``CACHE_BACKEND`` setting in your settings +file. Here's an explanation of all available values for CACHE_BACKEND. + +Memcached +--------- + +By far the fastest, most efficient type of cache available to Django, Memcached +is an entirely memory-based cache framework originally developed to handle high +loads at LiveJournal.com and subsequently open-sourced by Danga Interactive. +It's used by sites such as Slashdot and Wikipedia to reduce database access and +dramatically increase site performance. + +Memcached is available for free at http://danga.com/memcached/ . It runs as a +daemon and is allotted a specified amount of RAM. All it does is provide an +interface -- a *super-lightning-fast* interface -- for adding, retrieving and +deleting arbitrary data in the cache. All data is stored directly in memory, +so there's no overhead of database or filesystem usage. + +After installing Memcached itself, you'll need to install the Memcached Python +bindings. They're in a single Python module, memcache.py, available at +ftp://ftp.tummy.com/pub/python-memcached/ . If that URL is no longer valid, +just go to the Memcached Web site (http://www.danga.com/memcached/) and get the +Python bindings from the "Client APIs" section. + +To use Memcached with Django, set ``CACHE_BACKEND`` to +``memcached://ip:port/``, where ``ip`` is the IP address of the Memcached +daemon and ``port`` is the port on which Memcached is running. + +In this example, Memcached is running on localhost (127.0.0.1) port 11211:: + + CACHE_BACKEND = 'memcached://127.0.0.1:11211/' + +One excellent feature of Memcached is its ability to share cache over multiple +servers. To take advantage of this feature, include all server addresses in +``CACHE_BACKEND``, separated by semicolons. In this example, the cache is +shared over Memcached instances running on IP address 172.19.26.240 and +172.19.26.242, both on port 11211:: + + CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11211/' + +Memory-based caching has one disadvantage: Because the cached data is stored in +memory, the data will be lost if your server crashes. Clearly, memory isn't +intended for permanent data storage, so don't rely on memory-based caching as +your only data storage. Actually, none of the Django caching backends should be +used for permanent storage -- they're all intended to be solutions for caching, +not storage -- but we point this out here because memory-based caching is +particularly temporary. + +Database caching +---------------- + +To use a database table as your cache backend, first create a cache table in +your database by running this command:: + + python manage.py createcachetable [cache_table_name] + +...where ``[cache_table_name]`` is the name of the database table to create. +(This name can be whatever you want, as long as it's a valid table name that's +not already being used in your database.) This command creates a single table +in your database that is in the proper format that Django's database-cache +system expects. + +Once you've created that database table, set your ``CACHE_BACKEND`` setting to +``"db://tablename/"``, where ``tablename`` is the name of the database table. +In this example, the cache table's name is ``my_cache_table``: + + CACHE_BACKEND = 'db://my_cache_table' + +Database caching works best if you've got a fast, well-indexed database server. + +Filesystem caching +------------------ + +To store cached items on a filesystem, use the ``"file://"`` cache type for +``CACHE_BACKEND``. For example, to store cached data in ``/var/tmp/django_cache``, +use this setting:: + + CACHE_BACKEND = 'file:///var/tmp/django_cache' + +Note that there are three forward slashes toward the beginning of that example. +The first two are for ``file://``, and the third is the first character of the +directory path, ``/var/tmp/django_cache``. -Before using the cache, you'll need to tell Django which cache backend you'd -like to use. Do this by setting the ``CACHE_BACKEND`` in your settings file. +The directory path should be absolute -- that is, it should start at the root +of your filesystem. It doesn't matter whether you put a slash at the end of the +setting. -The ``CACHE_BACKEND`` setting is a "fake" URI (really an unregistered scheme). -Examples: +Make sure the directory pointed-to by this setting exists and is readable and +writable by the system user under which your Web server runs. Continuing the +above example, if your server runs as the user ``apache``, make sure the +directory ``/var/tmp/django_cache`` exists and is readable and writable by the +user ``apache``. - ============================== =========================================== - CACHE_BACKEND Explanation - ============================== =========================================== - memcached://127.0.0.1:11211/ A memcached backend; the server is running - on localhost port 11211. You can use - multiple memcached servers by separating - them with semicolons. +Local-memory caching +-------------------- - This backend requires the - `Python memcached bindings`_. +If you want the speed advantages of in-memory caching but don't have the +capability of running Memcached, consider the local-memory cache backend. This +cache is multi-process and thread-safe. To use it, set ``CACHE_BACKEND`` to +``"locmem:///"``. For example:: - db://tablename/ A database backend in a table named - "tablename". This table should be created - with "django-admin createcachetable". + CACHE_BACKEND = 'locmem:///' - file:///var/tmp/django_cache/ A file-based cache stored in the directory - /var/tmp/django_cache/. +Simple caching (for development) +-------------------------------- - simple:/// A simple single-process memory cache; you - probably don't want to use this except for - testing. Note that this cache backend is - NOT thread-safe! +A simple, single-process memory cache is available as ``"simple:///"``. This +merely saves cached data in-process, which means it should only be used in +development or testing environments. For example:: - locmem:/// A more sophisticated local memory cache; - this is multi-process- and thread-safe. + CACHE_BACKEND = 'simple:///' - dummy:/// Doesn't actually cache; just implements the - cache backend interface and doesn't do - anything. This is an easy way to turn off - caching for a test environment. - ============================== =========================================== +Dummy caching (for development) +------------------------------- -All caches may take arguments -- they're given in query-string style. Valid -arguments are: +Finally, Django comes with a "dummy" cache that doesn't actually cache -- it +just implements the cache interface without doing anything. + +This is useful if you have a production site that uses heavy-duty caching in +various places but a development/test environment on which you don't want to +cache. In that case, set ``CACHE_BACKEND`` to ``"dummy:///"`` in the settings +file for your development environment. As a result, your development +environment won't use caching and your production environment still will. + +CACHE_BACKEND arguments +----------------------- + +All caches may take arguments. They're given in query-string style on the +``CACHE_BACKEND`` setting. Valid arguments are: timeout Default timeout, in seconds, to use for the cache. Defaults to 5 @@ -66,7 +183,7 @@ arguments are: max_entries For the simple and database backends, the maximum number of entries - allowed in the cache before it is cleaned. Defaults to 300. + allowed in the cache before it is cleaned. Defaults to 300. cull_percentage The percentage of entries that are culled when max_entries is reached. @@ -77,20 +194,21 @@ arguments are: dumped when max_entries is reached. This makes culling *much* faster at the expense of more cache misses. -For example:: +In this example, ``timeout`` is set to ``60``:: CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=60" +In this example, ``timeout`` is ``30`` and ``max_entries`` is ``400``:: + + CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=30&max_entries=400" + Invalid arguments are silently ignored, as are invalid values of known arguments. -.. _memcached: http://www.danga.com/memcached/ -.. _Python memcached bindings: ftp://ftp.tummy.com/pub/python-memcached/ - The per-site cache ================== -Once the cache is set up, the simplest way to use the cache is to cache your +Once the cache is set up, the simplest way to use caching is to cache your entire site. Just add ``django.middleware.cache.CacheMiddleware`` to your ``MIDDLEWARE_CLASSES`` setting, as in this example:: @@ -159,52 +277,100 @@ For example, you may find it's only necessary to cache the result of an intensive database query. In cases like this, you can use the low-level cache API to store objects in the cache with any level of granularity you like. -The cache API is simple:: +The cache API is simple. The cache module, ``django.core.cache``, exports a +``cache`` object that's automatically created from the ``CACHE_BACKEND`` +setting:: - # The cache module exports a cache object that's automatically - # created from the CACHE_BACKEND setting. >>> from django.core.cache import cache - # The basic interface is set(key, value, timeout_seconds) and get(key). +The basic interface is ``set(key, value, timeout_seconds)`` and ``get(key)``:: + >>> cache.set('my_key', 'hello, world!', 30) >>> cache.get('my_key') 'hello, world!' - # (Wait 30 seconds...) +The ``timeout_seconds`` argument is optional and defaults to the ``timeout`` +argument in the ``CACHE_BACKEND`` setting (explained above). + +If the object doesn't exist in the cache, ``cache.get()`` returns ``None``:: + + >>> cache.get('some_other_key') + None + + # Wait 30 seconds for 'my_key' to expire... + >>> cache.get('my_key') None - # get() can take a default argument. - >>> cache.get('my_key', 'has_expired') - 'has_expired' +get() can take a ``default`` argument:: + + >>> cache.get('my_key', 'has expired') + 'has expired' + +There's also a get_many() interface that only hits the cache once. get_many() +returns a dictionary with all the keys you asked for that actually exist in the +cache (and haven't expired):: - # There's also a get_many() interface that only hits the cache once. - # Also, note that the timeout argument is optional and defaults to what - # you've given in the settings file. >>> cache.set('a', 1) >>> cache.set('b', 2) >>> cache.set('c', 3) - - # get_many() returns a dictionary with all the keys you asked for that - # actually exist in the cache (and haven't expired). >>> cache.get_many(['a', 'b', 'c']) {'a': 1, 'b': 2, 'c': 3} - # There's also a way to delete keys explicitly. +Finally, you can delete keys explicitly with ``delete()``. This is an easy way +of clearing the cache for a particular object:: + >>> cache.delete('a') That's it. The cache has very few restrictions: You can cache any object that can be pickled safely, although keys must be strings. -Controlling cache: Using Vary headers -===================================== +Upstream caches +=============== + +So far, this document has focused on caching your *own* data. But another type +of caching is relevant to Web development, too: caching performed by "upstream" +caches. These are systems that cache pages for users even before the request +reaches your Web site. + +Here are a few examples of upstream caches: + + * Your ISP may cache certain pages, so if you requested a page from + somedomain.com, your ISP would send you the page without having to access + somedomain.com directly. + + * Your Django Web site may site behind a Squid Web proxy + (http://www.squid-cache.org/) that caches pages for performance. In this + case, each request first would be handled by Squid, and it'd only be + passed to your application if needed. -The Django cache framework works with `HTTP Vary headers`_ to allow developers -to instruct caching mechanisms to differ their cache contents depending on -request HTTP headers. + * Your Web browser caches pages, too. If a Web page sends out the right + headers, your browser will use the local (cached) copy for subsequent + requests to that page. -Essentially, the ``Vary`` response HTTP header defines which request headers a -cache mechanism should take into account when building its cache key. +Upstream caching is a nice efficiency boost, but there's a danger to it: +Many Web pages' contents differ based on authentication and a host of other +variables, and cache systems that blindly save pages based purely on URLs could +expose incorrect or sensitive data to subsequent visitors to those pages. + +For example, say you operate a Web e-mail system, and the contents of the +"inbox" page obviously depend on which user is logged in. If an ISP blindly +cached your site, then the first user who logged in through that ISP would have +his user-specific inbox page cached for subsequent visitors to the site. That's +not cool. + +Fortunately, HTTP provides a solution to this problem: A set of HTTP headers +exist to instruct caching mechanisms to differ their cache contents depending +on designated variables, and to tell caching mechanisms not to cache particular +pages. + +Using Vary headers +================== + +One of these headers is ``Vary``. It defines which request headers a cache +mechanism should take into account when building its cache key. For example, if +the contents of a Web page depend on a user's language preference, the page is +said to "vary on language." By default, Django's cache system creates its cache keys using the requested path -- e.g., ``"/stories/2005/jun/23/bank_robbed/"``. This means every request @@ -241,7 +407,7 @@ setting the ``Vary`` header (using something like ``response['Vary'] = 'user-agent'``) is that the decorator adds to the ``Vary`` header (which may already exist) rather than setting it from scratch. -Note that you can pass multiple headers to ``vary_on_headers()``:: +You can pass multiple headers to ``vary_on_headers()``:: @vary_on_headers('User-Agent', 'Cookie') def my_view(request): @@ -261,7 +427,8 @@ decorator. These two views are equivalent:: Also note that the headers you pass to ``vary_on_headers`` are not case sensitive. ``"User-Agent"`` is the same thing as ``"user-agent"``. -You can also use a helper function, ``patch_vary_headers()``, directly:: +You can also use a helper function, ``django.utils.cache.patch_vary_headers``, +directly:: from django.utils.cache import patch_vary_headers def my_view(request): @@ -273,7 +440,9 @@ You can also use a helper function, ``patch_vary_headers()``, directly:: ``patch_vary_headers`` takes an ``HttpResponse`` instance as its first argument and a list/tuple of header names as its second argument. -.. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 +For more on Vary headers, see the `official Vary spec`_. + +.. _`official Vary spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 Controlling cache: Using other headers ====================================== @@ -317,15 +486,19 @@ cache on every access and to store cached versions for, at most, 3600 seconds:: def my_view(request): ... -Any valid ``Cache-Control`` directive is valid in ``cache_control()``. For a -full list, see the `Cache-Control spec`_. Just pass the directives as keyword -arguments to ``cache_control()``, substituting underscores for hyphens. For -directives that don't take an argument, set the argument to ``True``. +Any valid ``Cache-Control`` HTTP directive is valid in ``cache_control()``. +Here's a full list: -Examples: + * ``public=True`` + * ``private=True`` + * ``no_cache=True`` + * ``no_transform=True`` + * ``must_revalidate=True`` + * ``proxy_revalidate=True`` + * ``max_age=num_seconds`` + * ``s_maxage=num_seconds`` - * ``@cache_control(max_age=3600)`` turns into ``max-age=3600``. - * ``@cache_control(public=True)`` turns into ``public``. +For explanation of Cache-Control HTTP directives, see the `Cache-Control spec`_. (Note that the caching middleware already sets the cache header's max-age with the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom diff --git a/docs/db-api.txt b/docs/db-api.txt index e37645e601..8da6ebbac2 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -2,509 +2,1366 @@ Database API reference ====================== -Once you've created your `data models`_, you'll need to retrieve data from the -database. This document explains the database abstraction API derived from the -models, and how to create, retrieve and update objects. +Once you've created your `data models`_, Django automatically gives you a +database-abstraction API that lets you create, retrieve, update and delete +objects. This document explains that API. .. _`data models`: http://www.djangoproject.com/documentation/model_api/ -Throughout this reference, we'll refer to the following Poll application:: +Throughout this reference, we'll refer to the following models, which comprise +a weblog application:: - class Poll(meta.Model): - slug = meta.SlugField(unique_for_month='pub_date') - question = meta.CharField(maxlength=255) - pub_date = meta.DateTimeField() - expire_date = meta.DateTimeField() + class Blog(models.Model): + name = models.CharField(maxlength=100) + tagline = models.TextField() - def __repr__(self): - return self.question + def __str__(self): + return self.name - class Choice(meta.Model): - poll = meta.ForeignKey(Poll, edit_inline=meta.TABULAR, - num_in_admin=10, min_num_in_admin=5) - choice = meta.CharField(maxlength=255, core=True) - votes = meta.IntegerField(editable=False, default=0) + class Author(models.Model): + name = models.CharField(maxlength=50) + email = models.URLField() - def __repr__(self): - return self.choice + class __str__(self): + return self.name -Basic lookup functions -====================== + class Entry(models.Model): + blog = models.ForeignKey(Blog) + headline = models.CharField(maxlength=255) + body_text = models.TextField() + pub_date = models.DateTimeField() + authors = models.ManyToManyField(Author) -Each model exposes these module-level functions for lookups: + def __str__(self): + return self.headline -get_object(\**kwargs) ---------------------- +Creating objects +================ -Returns the object matching the given lookup parameters, which should be in -the format described in "Field lookups" below. Raises a module-level -``*DoesNotExist`` exception if an object wasn't found for the given parameters. -Raises ``AssertionError`` if more than one object was found. +To represent database-table data in Python objects, Django uses an intuitive +system: A model class represents a database table, and an instance of that +class represents a particular record in the database table. -get_list(\**kwargs) -------------------- +To create an object, instantiate it using keyword arguments to the model class, +then call ``save()`` to save it to the database. -Returns a list of objects matching the given lookup parameters, which should be -in the format described in "Field lookups" below. If no objects match the given -parameters, it returns an empty list. ``get_list()`` will always return a list. +You import the model class from wherever it lives on the Python path, as you +may expect. (We point this out here because previous Django versions required +funky model importing.) -get_iterator(\**kwargs) ------------------------ +Assuming models live in a file ``mysite/blog/models.py``, here's an example:: -Just like ``get_list()``, except it returns an iterator instead of a list. This -is more efficient for large result sets. This example shows the difference:: + from mysite.blog.models import Blog + b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') + b.save() - # get_list() loads all objects into memory. - for obj in foos.get_list(): - print repr(obj) +This performs an ``INSERT`` SQL statement behind the scenes. Django doesn't hit +the database until you explicitly call ``save()``. - # get_iterator() only loads a number of objects into memory at a time. - for obj in foos.get_iterator(): - print repr(obj) +The ``save()`` method has no return value. -get_count(\**kwargs) --------------------- +Auto-incrementing primary keys +------------------------------ -Returns an integer representing the number of objects in the database matching -the given lookup parameters, which should be in the format described in -"Field lookups" below. ``get_count()`` never raises exceptions +If a model has an ``AutoField`` -- an auto-incrementing primary key -- then +that auto-incremented value will be calculated and saved as an attribute on +your object the first time you call ``save()``. -Depending on which database you're using (e.g. PostgreSQL vs. MySQL), this may -return a long integer instead of a normal Python integer. +Example:: -get_values(\**kwargs) ---------------------- + b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.') + b2.id # Returns None, because b doesn't have an ID yet. + b2.save() + b2.id # Returns the ID of your new object. -Just like ``get_list()``, except it returns a list of dictionaries instead of -model-instance objects. +There's no way to tell what the value of an ID will be before you call +``save()``, because that value is calculated by your database, not by Django. -It accepts an optional parameter, ``fields``, which should be a list or tuple -of field names. If you don't specify ``fields``, each dictionary in the list -returned by ``get_values()`` will have a key and value for each field in the -database table. If you specify ``fields``, each dictionary will have only the -field keys/values for the fields you specify. Here's an example, using the -``Poll`` model defined above:: +(For convenience, each model has an ``AutoField`` named ``id`` by default +unless you explicitly specify ``primary_key=True`` on a field. See the +`AutoField documentation`_.) - >>> from datetime import datetime - >>> p1 = polls.Poll(slug='whatsup', question="What's up?", - ... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 3, 20)) - >>> p1.save() - >>> p2 = polls.Poll(slug='name', question="What's your name?", - ... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 4, 20)) - >>> p2.save() - >>> polls.get_list() - [What's up?, What's your name?] - >>> polls.get_values() - [{'id': 1, 'slug': 'whatsup', 'question': "What's up?", 'pub_date': datetime.datetime(2005, 2, 20), 'expire_date': datetime.datetime(2005, 3, 20)}, - {'id': 2, 'slug': 'name', 'question': "What's your name?", 'pub_date': datetime.datetime(2005, 3, 20), 'expire_date': datetime.datetime(2005, 4, 20)}] - >>> polls.get_values(fields=['id', 'slug']) - [{'id': 1, 'slug': 'whatsup'}, {'id': 2, 'slug': 'name'}] +.. _AutoField documentation: TODO: Link -Use ``get_values()`` when you know you're only going to need a couple of field -values and you won't need the functionality of a model instance object. It's -more efficient to select only the fields you need to use. +Explicitly specifying auto-primary-key values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -get_values_iterator(\**kwargs) ------------------------------- +If a model has an ``AutoField`` but you want to define a new object's ID +explicitly when saving, just define it explicitly before saving, rather than +relying on the auto-assignment of the ID. -Just like ``get_values()``, except it returns an iterator instead of a list. -See the section on ``get_iterator()`` above. +Example:: -get_in_bulk(id_list, \**kwargs) -------------------------------- + b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.') + b3.id # Returns 3. + b3.save() + b3.id # Returns 3. -Takes a list of IDs and returns a dictionary mapping each ID to an instance of -the object with the given ID. Also takes optional keyword lookup arguments, -which should be in the format described in "Field lookups" below. Here's an -example, using the ``Poll`` model defined above:: +If you assign auto-primary-key values manually, make sure not to use an +already-existing primary-key value! If you create a new object with an explicit +primary-key value that already exists in the database, Django will assume +you're changing the existing record rather than creating a new one. - >>> from datetime import datetime - >>> p1 = polls.Poll(slug='whatsup', question="What's up?", - ... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 3, 20)) - >>> p1.save() - >>> p2 = polls.Poll(slug='name', question="What's your name?", - ... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 4, 20)) - >>> p2.save() - >>> polls.get_list() - [What's up?, What's your name?] - >>> polls.get_in_bulk([1]) - {1: What's up?} - >>> polls.get_in_bulk([1, 2]) - {1: What's up?, 2: What's your name?} +Given the above ``'Cheddar Talk'`` blog example, this example would override +the previous record in the database:: -Field lookups -============= + b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.') + b4.save() # Overrides the previous blog with ID=3! -Basic field lookups take the form ``field__lookuptype`` (that's a -double-underscore). For example:: +See _`How Django knows to UPDATE vs. INSERT`, below, for the reason this +happens. - polls.get_list(pub_date__lte=datetime.datetime.now()) +Explicitly specifying auto-primary-key values is mostly useful for bulk-saving +objects, when you're confident you won't have primary-key collision. -translates (roughly) into the following SQL:: +Saving changes to objects +========================= - SELECT * FROM polls_polls WHERE pub_date <= NOW(); +To save changes to an object that's already in the database, use ``save()``. -.. admonition:: How this is possible +Given a ``Blog`` instance ``b5`` that has already been saved to the database, +this example changes its name and updates its record in the database:: - Python has the ability to define functions that accept arbitrary name-value - arguments whose names and values are evaluated at run time. For more - information, see `Keyword Arguments`_ in the official Python tutorial. + b5.name = 'New name' + b5.save() -The DB API supports the following lookup types: +This performs an ``UPDATE`` SQL statement behind the scenes. Django doesn't hit +the database until you explicitly call ``save()``. - =========== ============================================================== - Type Description - =========== ============================================================== - exact Exact match: ``polls.get_object(id__exact=14)``. - iexact Case-insensitive exact match: - ``polls.get_list(slug__iexact="foo")`` matches a slug of - ``foo``, ``FOO``, ``fOo``, etc. - contains Case-sensitive containment test: - ``polls.get_list(question__contains="spam")`` returns all polls - that contain "spam" in the question. (PostgreSQL and MySQL - only. SQLite doesn't support case-sensitive LIKE statements; - ``contains`` will act like ``icontains`` for SQLite.) - icontains Case-insensitive containment test. - gt Greater than: ``polls.get_list(id__gt=4)``. - gte Greater than or equal to. - lt Less than. - lte Less than or equal to. - ne Not equal to. - in In a given list: ``polls.get_list(id__in=[1, 3, 4])`` returns - a list of polls whose IDs are either 1, 3 or 4. - startswith Case-sensitive starts-with: - ``polls.get_list(question__startswith="Would")``. (PostgreSQL - and MySQL only. SQLite doesn't support case-sensitive LIKE - statements; ``startswith`` will act like ``istartswith`` for - SQLite.) - endswith Case-sensitive ends-with. (PostgreSQL and MySQL only.) - istartswith Case-insensitive starts-with. - iendswith Case-insensitive ends-with. - range Range test: - ``polls.get_list(pub_date__range=(start_date, end_date))`` - returns all polls with a pub_date between ``start_date`` - and ``end_date`` (inclusive). - year For date/datetime fields, exact year match: - ``polls.get_count(pub_date__year=2005)``. - month For date/datetime fields, exact month match. - day For date/datetime fields, exact day match. - isnull True/False; does is IF NULL/IF NOT NULL lookup: - ``polls.get_list(expire_date__isnull=True)``. - =========== ============================================================== +The ``save()`` method has no return value. -Multiple lookups are allowed, of course, and are translated as "AND"s:: +How Django knows to UPDATE vs. INSERT +------------------------------------- - polls.get_list( - pub_date__year=2005, - pub_date__month=1, - question__startswith="Would", - ) +You may have noticed Django database objects use the same ``save()`` method +for creating and changing objects. Django abstracts the need to use ``INSERT`` +or ``UPDATE`` SQL statements. Specifically, when you call ``save()``, Django +follows this algorithm: -...retrieves all polls published in January 2005 that have a question starting with "Would." + * If the object's primary key attribute is set to a value that evaluates to + ``False`` (such as ``None`` or the empty string), Django executes a + ``SELECT`` query to determine whether a record with the given primary key + already exists. + * If the record with the given primary key does already exist, Django + executes an ``UPDATE`` query. + * If the object's primary key attribute is *not* set, or if it's set but a + record doesn't exist, Django executes an ``INSERT``. -For convenience, there's a ``pk`` lookup type, which translates into -``(primary_key)__exact``. In the polls example, these two statements are -equivalent:: +The one gotcha here is that you should be careful not to specify a primary-key +value explicitly when saving new objects, if you cannot guarantee the +primary-key value is unused. For more on this nuance, see +"Explicitly specifying auto-primary-key values" above. - polls.get_object(id__exact=3) - polls.get_object(pk=3) +Retrieving objects +================== -``pk`` lookups also work across joins. In the polls example, these two -statements are equivalent:: +To retrieve objects from your database, you construct a ``QuerySet`` via a +``Manager`` on your model class. - choices.get_list(poll__id__exact=3) - choices.get_list(poll__pk=3) +A ``QuerySet`` represents a collection of objects from your database. It can +have zero, one or many *filters* -- criteria that narrow down the collection +based on given parameters. In SQL terms, a ``QuerySet`` equates to a ``SELECT`` +statement, and a filter is a limiting clause such as ``WHERE`` or ``LIMIT``. -If you pass an invalid keyword argument, the function will raise ``TypeError``. +You get a ``QuerySet`` by using your model's ``Manager``. Each model has at +least one ``Manager``, and it's called ``objects`` by default. Access it +directly via the model class, like so:: -.. _`Keyword Arguments`: http://docs.python.org/tut/node6.html#SECTION006720000000000000000 + Blog.objects # <django.db.models.manager.Manager object at ...> + b = Blog(name='Foo', tagline='Bar') + b.objects # AttributeError: "Manager isn't accessible via Blog instances." -OR lookups ----------- +(``Managers`` are accessible only via model classes, rather than from model +instances, to enforce a separation between "table-level" operations and +"record-level" operations.) + +The ``Manager`` is the main source of ``QuerySets`` for a model. It acts as a +"root" ``QuerySet`` that describes all objects in the model's database table. +For example, ``Blog.objects`` is the initial ``QuerySet`` that contains all +``Blog`` objects in the database. -By default, multiple lookups are "AND"ed together. If you'd like to use ``OR`` -statements in your queries, use the ``complex`` lookup type. +Retrieving all objects +---------------------- -``complex`` takes an expression of clauses, each of which is an instance of -``django.core.meta.Q``. ``Q`` takes an arbitrary number of keyword arguments in -the standard Django lookup format. And you can use Python's "and" (``&``) and -"or" (``|``) operators to combine ``Q`` instances. For example:: +The simplest way to retrieve objects from a table is to get all of them. +To do this, use the ``all()`` method on a ``Manager``. - from django.core.meta import Q - polls.get_object(complex=(Q(question__startswith='Who') | Q(question__startswith='What'))) +Example:: + + all_entries = Entry.objects.all() + +The ``all()`` method returns a ``QuerySet`` of all the objects in the database. + +(If ``Entry.objects`` is a ``QuerySet``, why can't we just do ``Entry.objects``? +That's because ``Entry.objects``, the root ``QuerySet``, is a special case +that cannot be evaluated. The ``all()`` method returns a ``QuerySet`` that +*can* be evaluated.) + +Filtering objects +----------------- -The ``|`` symbol signifies an "OR", so this (roughly) translates into:: +The root ``QuerySet`` provided by the ``Manager`` describes all objects in the +database table. Usually, though, you'll need to select only a subset of the +complete set of objects. - SELECT * FROM polls - WHERE question LIKE 'Who%' OR question LIKE 'What%'; +To create such a subset, you refine the initial ``QuerySet``, adding filter +conditions. The two most common ways to refine a ``QuerySet`` are: + +``filter(**kwargs)`` + Returns a new ``QuerySet`` containing objects that match the given lookup + parameters. + +``exclude(**kwargs)`` + Returns a new ``QuerySet`` containing objects that do *not* match the given + lookup parameters. + +The lookup parameters (``**kwargs`` in the above function definitions) should +be in the format described in _`Field lookups` below. + +For example, to get a ``QuerySet`` of blog entries from the year 2006, use +``filter()`` like so:: + + Entry.objects.filter(pub_date__year=2006) + +(Note we don't have to add an ``all()`` -- ``Entry.objects.all().filter(...)``. +That would still work, but you only need ``all()`` when you want all objects +from the root ``QuerySet``.) + +Chaining filters +~~~~~~~~~~~~~~~~ + +The result of refining a ``QuerySet`` is itself a ``QuerySet``, so it's +possible to chain refinements together. For example:: + + Entry.objects.filter( + headline__startswith='What').exclude( + pub_date__gte=datetime.now()).filter( + pub_date__gte=datetime(2005, 1, 1)) + +...takes the initial ``QuerySet`` of all entries in the database, adds a +filter, then an exclusion, then another filter. The final result is a +``QuerySet`` containing all entries with a headline that starts with "What", +that were published between January 1, 2005, and the current day. + +Filtered QuerySets are unique +----------------------------- + +Each time you refine a ``QuerySet``, you get a brand-new ``QuerySet`` that is +in no way bound to the previous ``QuerySet``. Each refinement creates a +separate and distinct ``QuerySet`` that can be stored, used and reused. -You can use ``&`` and ``|`` operators together, and use parenthetical grouping. Example:: - polls.get_object(complex=(Q(question__startswith='Who') & (Q(pub_date__exact=date(2005, 5, 2)) | Q(pub_date__exact=date(2005, 5, 6)))) + q1 = Entry.objects.filter(headline__startswith="What") + q2 = q1.exclude(pub_date__gte=datetime.now()) + q3 = q1.filter(pub_date__gte=datetime.now()) -This roughly translates into:: +These three ``QuerySets`` are separate. The first is a base ``QuerySet`` +containing all entries that contain a headline starting with "What". The second +is a subset of the first, with an additional criteria that excludes records +whose ``pub_date`` is greater than now. The third is a subset of the first, +with an additional criteria that selects only the records whose ``pub_date`` is +greater than now. The initial ``QuerySet`` (``q1``) is unaffected by the +refinement process. - SELECT * FROM polls - WHERE question LIKE 'Who%' - AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06'); +QuerySets are lazy +------------------ -See the `OR lookups examples page`_ for more examples. +``QuerySets`` are lazy -- the act of creating a ``QuerySet`` doesn't involve +any database activity. You can stack filters together all day long, and Django +won't actually run the query until the ``QuerySet`` is *evaluated*. -.. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/ +When QuerySets are evaluated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Ordering -======== +You can evaluate a ``QuerySet`` in the following ways: -The results are automatically ordered by the ordering tuple given by the -``ordering`` key in the model, but the ordering may be explicitly -provided by the ``order_by`` argument to a lookup:: + * **Iteration.** A ``QuerySet`` is iterable, and it executes its database + query the first time you iterate over it. For example, this will print + the headline of all entries in the database:: - polls.get_list( - pub_date__year=2005, - pub_date__month=1, - order_by=('-pub_date', 'question'), - ) + for e in Entry.objects.all(): + print e.headline + + * **Slicing.** A ``QuerySet`` can be sliced, using Python's array-slicing + syntax, and it executes its database query the first time you slice it. + Examples:: + + fifth_entry = Entry.objects.all()[4] + all_entries_but_the_first_two = Entry.objects.all()[2:] + every_second_entry = Entry.objects.all()[::2] + + * **repr().** A ``QuerySet`` is evaluated when you call ``repr()`` on it. + This is for convenience in the Python interactive interpreter, so you can + immediately see your results when using the API interactively. + + * **len().** A ``QuerySet`` is evaluated when you call ``len()`` on it. + This, as you might expect, returns the length of the result list. + + Note: *Don't* use ``len()`` on ``QuerySet``s if all you want to do is + determine the number of records in the set. It's much more efficient to + handle a count at the database level, using SQL's ``SELECT COUNT(*)``, + and Django provides a ``count()`` method for precisely this reason. See + ``count()`` below. + + * **list().** Force evaluation of a ``QuerySet`` by calling ``list()`` on + it. For example:: + + entry_list = list(Entry.objects.all()) + + Be warned, though, that this could have a large memory overhead, because + Django will load each element of the list into memory. In contrast, + iterating over a ``QuerySet`` will take advantage of your database to + load data and instantiate objects only as you need them. + +QuerySet methods that return new QuerySets +------------------------------------------ -The result set above will be ordered by ``pub_date`` descending, then -by ``question`` ascending. The negative sign in front of "-pub_date" indicates -descending order. Ascending order is implied. To order randomly, use "?", like -so:: +Django provides a range of ``QuerySet`` refinement methods that modify either +the types of results returned by the ``QuerySet`` or the way its SQL query is +executed. - polls.get_list(order_by=['?']) +filter(**kwargs) +~~~~~~~~~~~~~~~~ + +Returns a new ``QuerySet`` containing objects that match the given lookup +parameters. + +The lookup parameters (``**kwargs``) should be in the format described in +_`Field lookups` below. Multiple parameters are joined via ``AND`` in the +underlying SQL statement. + +exclude(**kwargs) +~~~~~~~~~~~~~~~~~ + +Returns a new ``QuerySet`` containing objects that do *not* match the given +lookup parameters. + +The lookup parameters (``**kwargs``) should be in the format described in +_`Field lookups` below. Multiple parameters are joined via ``AND`` in the +underlying SQL statement, and the whole thing is enclosed in a ``NOT()``. + +This example excludes all entries whose ``pub_date`` is the current date/time +AND whose ``headline`` is "Hello":: + + Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello') + +In SQL terms, that evaluates to:: + + SELECT ... + WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello') + +This example excludes all entries whose ``pub_date`` is the current date/time +OR whose ``headline`` is "Hello":: + + Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello') + +In SQL terms, that evaluates to:: + + SELECT ... + WHERE NOT pub_date > '2005-1-3' + AND NOT headline = 'Hello' + +Note the second example is more restrictive. + +order_by(*fields) +~~~~~~~~~~~~~~~~~ + +By default, results returned by a ``QuerySet`` are ordered by the ordering +tuple given by the ``ordering`` option in the model's ``Meta``. You can +override this on a per-``QuerySet`` basis by using the ``order_by`` method. + +Example:: + + Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline') + +The result above will be ordered by ``pub_date`` descending, then by +``headline`` ascending. The negative sign in front of ``"-pub_date"`` indicates +*descending* order. Ascending order is implied. To order randomly, use ``"?"``, +like so:: + + Entry.objects.order_by('?') To order by a field in a different table, add the other table's name and a dot, like so:: - choices.get_list(order_by=('polls.pub_date', 'choice')) + Entry.objects.order_by('blogs_blog.name', 'headline') There's no way to specify whether ordering should be case sensitive. With respect to case-sensitivity, Django will order results however your database backend normally orders them. -Relationships (joins) -===================== +distinct() +~~~~~~~~~~ -Joins may implicitly be performed by following relationships: -``choices.get_list(poll__slug__exact="eggs")`` fetches a list of ``Choice`` -objects where the associated ``Poll`` has a slug of ``eggs``. Multiple levels -of joins are allowed. +Returns a new ``QuerySet`` that uses ``SELECT DISTINCT`` in its SQL query. This +eliminates duplicate rows from the query results. -Given an instance of an object, related objects can be looked-up directly using -convenience functions. For example, if ``p`` is a ``Poll`` instance, -``p.get_choice_list()`` will return a list of all associated choices. Astute -readers will note that this is the same as -``choices.get_list(poll__id__exact=p.id)``, except clearer. +By default, a ``QuerySet`` will not eliminate duplicate rows. In practice, this +is rarely a problem, because simple queries such as ``Blog.objects.all()`` +don't introduce the possibility of duplicate result rows. -Each type of relationship creates a set of methods on each object in the -relationship. These methods are created in both directions, so objects that are -"related-to" need not explicitly define reverse relationships; that happens -automatically. +However, if your query spans multiple tables, it's possible to get duplicate +results when a ``QuerySet`` is evaluated. That's when you'd use ``distinct()``. -One-to-one relations --------------------- +values(*fields) +~~~~~~~~~~~~~~~ -Each object in a one-to-one relationship will have a ``get_relatedobjectname()`` -method. For example:: +Returns a ``ValuesQuerySet`` -- a ``QuerySet`` that evaluates to a list of +dictionaries instead of model-instance objects. - class Place(meta.Model): - # ... +Each of those dictionaries represents an object, with the keys corresponding to +the attribute names of model objects. - class Restaurant(meta.Model): - # ... - the_place = meta.OneToOneField(places.Place) +This example compares the dictionaries of ``values()`` with the normal model +objects:: -In the above example, each ``Place`` will have a ``get_restaurant()`` method, -and each ``Restaurant`` will have a ``get_the_place()`` method. + # This list contains a Blog object. + >>> Blog.objects.filter(name__startswith='Beatles') + [Beatles Blog] -Many-to-one relations ---------------------- + # This list contains a dictionary. + >>> Blog.objects.filter(name__startswith='Beatles').values() + [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}] -In each many-to-one relationship, the related object will have a -``get_relatedobject()`` method, and the related-to object will have -``get_relatedobject()``, ``get_relatedobject_list()``, and -``get_relatedobject_count()`` methods (the same as the module-level -``get_object()``, ``get_list()``, and ``get_count()`` methods). +``values()`` takes optional positional arguments, ``*fields``, which specify +field names to which the ``SELECT`` should be limited. If you specify the +fields, each dictionary will contain only the field keys/values for the fields +you specify. If you don't specify the fields, each dictionary will contain a +key and value for every field in the database table. -In the poll example above, here are the available choice methods on a ``Poll`` object ``p``:: +Example:: - p.get_choice() - p.get_choice_list() - p.get_choice_count() + >>> Blog.objects.values() + [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}], + >>> Blog.objects.values('id', 'name') + [{'id': 1, 'name': 'Beatles Blog'}] -And a ``Choice`` object ``c`` has the following method:: +A ``ValuesQuerySet`` is useful when you know you're only going to need values +from a small number of the available fields and you won't need the +functionality of a model instance object. It's more efficient to select only +the fields you need to use. - c.get_poll() +Finally, note a ``ValuesQuerySet`` is a subclass of ``QuerySet``, so it has all +methods of ``QuerySet``. You can call ``filter()`` on it, or ``order_by()``, or +whatever. Yes, that means these two calls are identical:: -Many-to-many relations ----------------------- + Blog.objects.values().order_by('id') + Blog.objects.order_by('id').values() + +The people who made Django prefer to put all the SQL-affecting methods first, +followed (optionally) by any output-affecting methods (such as ``values()``), +but it doesn't really matter. This is your chance to really flaunt your +individualism. + +dates(field, kind, order='ASC') +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns a ``DateQuerySet`` -- a ``QuerySet`` that evaluates to a list of +``datetime.datetime`` objects representing all available dates of a particular +kind within the contents of the ``QuerySet``. + +``field`` should be the name of a ``DateField`` or ``DateTimeField`` of your +model. + +``kind`` should be either ``"year"``, ``"month"`` or ``"day"``. Each +``datetime.datetime`` object in the result list is "truncated" to the given +``type``. + + * ``"year"`` returns a list of all distinct year values for the field. + * ``"month"`` returns a list of all distinct year/month values for the field. + * ``"day"`` returns a list of all distinct year/month/day values for the field. + +``order``, which defaults to ``'ASC'``, should be either ``'ASC'`` or +``'DESC'``. This specifies how to order the results. + +Examples:: -Many-to-many relations result in the same set of methods as `Many-to-one relations`_, -except that the ``get_relatedobject_list()`` function on the related object will -return a list of instances instead of a single instance. So, if the relationship -between ``Poll`` and ``Choice`` was many-to-many, ``choice.get_poll_list()`` would -return a list. + >>> Entry.objects.dates('pub_date', 'year') + [datetime.datetime(2005, 1, 1)] + >>> Entry.objects.dates('pub_date', 'month') + [datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)] + >>> Entry.objects.dates('pub_date', 'day') + [datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)] + >>> Entry.objects.dates('pub_date', 'day', order='DESC') + [datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)] + >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day') + [datetime.datetime(2005, 3, 20)] -Relationships across applications ---------------------------------- +select_related() +~~~~~~~~~~~~~~~~ -If a relation spans applications -- if ``Place`` was had a ManyToOne relation to -a ``geo.City`` object, for example -- the name of the other application will be -added to the method, i.e. ``place.get_geo_city()`` and -``city.get_places_place_list()``. +Returns a ``QuerySet`` that will automatically "follow" foreign-key +relationships, selecting that additional related-object data when it executes +its query. This is a performance booster which results in (sometimes much) +larger queries but means later use of foreign-key relationships won't require +database queries. -Selecting related objects -------------------------- +The following examples illustrate the difference between plain lookups and +``select_related()`` lookups. Here's standard lookup:: -Relations are the bread and butter of databases, so there's an option to "follow" -all relationships and pre-fill them in a simple cache so that later calls to -objects with a one-to-many relationship don't have to hit the database. Do this by -passing ``select_related=True`` to a lookup. This results in (sometimes much) larger -queries, but it means that later use of relationships is much faster. + # Hits the database. + e = Entry.objects.get(id=5) -For example, using the Poll and Choice models from above, if you do the following:: + # Hits the database again to get the related Blog object. + b = e.blog - c = choices.get_object(id__exact=5, select_related=True) +And here's ``select_related`` lookup:: -Then subsequent calls to ``c.get_poll()`` won't hit the database. + # Hits the database. + e = Entry.objects.select_related().get(id=5) -Note that ``select_related`` follows foreign keys as far as possible. If you have the + # Doesn't hit the database, because e.blog has been prepopulated + # in the previous query. + b = e.blog + +``select_related()`` follows foreign keys as far as possible. If you have the following models:: - class Poll(meta.Model): + class City(models.Model): # ... - class Choice(meta.Model): + class Person(models.Model): # ... - poll = meta.ForeignKey(Poll) + hometown = models.ForeignKey(City) - class SingleVote(meta.Model): + class Book(meta.Model): # ... - choice = meta.ForeignKey(Choice) + author = models.ForeignKey(Person) -then a call to ``singlevotes.get_object(id__exact=4, select_related=True)`` will -cache the related choice *and* the related poll:: +...then a call to ``Book.objects.select_related().get(id=4)`` will cache the +related ``Person`` *and* the related ``City``:: - >>> sv = singlevotes.get_object(id__exact=4, select_related=True) - >>> c = sv.get_choice() # Doesn't hit the database. - >>> p = c.get_poll() # Doesn't hit the database. + b = Book.objects.select_related().get(id=4) + p = b.author # Doesn't hit the database. + c = p.hometown # Doesn't hit the database. - >>> sv = singlevotes.get_object(id__exact=4) # Note no "select_related". - >>> c = sv.get_choice() # Hits the database. - >>> p = c.get_poll() # Hits the database. + sv = Book.objects.get(id=4) # No select_related() in this example. + p = b.author # Hits the database. + c = p.hometown # Hits the database. -Limiting selected rows -====================== +extra(select=None, where=None, params=None, tables=None) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes, the Django query syntax by itself can't easily express a complex +``WHERE`` clause. For these edge cases, Django provides the ``extra()`` +``QuerySet`` modifier -- a hook for injecting specific clauses into the SQL +generated by a ``QuerySet``. + +By definition, these extra lookups may not be portable to different database +engines (because you're explicitly writing SQL code) and violate the DRY +principle, so you should avoid them if possible. + +Specify one or more of ``params``, ``select``, ``where`` or ``tables``. None +of the arguments is required, but you should use at least one of them. + +``select`` + The ``select`` argument lets you put extra fields in the ``SELECT`` clause. + It should be a dictionary mapping attribute names to SQL clauses to use to + calculate that attribute. + + Example:: + + Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) -The ``limit``, ``offset``, and ``distinct`` keywords can be used to control -which rows are returned. Both ``limit`` and ``offset`` should be integers which -will be directly passed to the SQL ``LIMIT``/``OFFSET`` commands. + As a result, each ``Entry`` object will have an extra attribute, + ``is_recent``, a boolean representing whether the entry's ``pub_date`` is + greater than Jan. 1, 2006. -If ``distinct`` is True, only distinct rows will be returned. This is equivalent -to a ``SELECT DISTINCT`` SQL clause. You can use this with ``get_values()`` to -get distinct values. For example, this returns the distinct first_names:: + Django inserts the given SQL snippet directly into the ``SELECT`` + statement, so the resulting SQL of the above example would be:: - >>> people.get_values(fields=['first_name'], distinct=True) - [{'first_name': 'Adrian'}, {'first_name': 'Jacob'}, {'first_name': 'Simon'}] + SELECT blog_entry.*, (pub_date > '2006-01-01') + FROM blog_entry; -Other lookup options -==================== -There are a few other ways of more directly controlling the generated SQL -for the lookup. Note that by definition these extra lookups may not be -portable to different database engines (because you're explicitly writing -SQL code) and should be avoided if possible.: + The next example is more advanced; it does a subquery to give each + resulting ``Blog`` object an ``entry_count`` attribute, an integer count + of associated ``Entry`` objects. + + Blog.objects.extra( + select={ + 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' + }, + ) + + (In this particular case, we're exploiting the fact that the query will + already contain the ``blog_blog`` table in its ``FROM`` clause.) + + The resulting SQL of the above example would be:: + + SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) + FROM blog_blog; + + Note that the parenthesis required by most database engines around + subqueries are not required in Django's ``select`` clauses. Also note that + some database backends, such as some MySQL versions, don't support + subqueries. + +``where`` / ``tables`` + You can define explicit SQL ``WHERE`` clauses -- perhaps to perform + non-explicit joins -- by using ``where``. You can manually add tables to + the SQL ``FROM`` clause by using ``tables``. + + ``where`` and ``tables`` both take a list of strings. All ``where`` + parameters are "AND"ed to any other search criteria. + + Example:: + + Entry.objects.extra(where=['id IN (3, 4, 5, 20)']) + + ...translates (roughly) into the following SQL:: + + SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20); ``params`` ----------- + The ``select`` and ``where`` parameters described above may use standard + Python database string placeholders -- ``'%s'`` to indicate parameters the + database engine should automatically quote. The ``params`` argument is a + list of any extra parameters to be substituted. -All the extra-SQL params described below may use standard Python string -formatting codes to indicate parameters that the database engine will -automatically quote. The ``params`` argument can contain any extra -parameters to be substituted. + Example:: -``select`` ----------- + Entry.objects.extra(where=['headline=%s'], params=['Lennon']) + + Always use ``params`` instead of embedding values directly into ``select`` + or ``where`` because ``params`` will ensure values are quoted correctly + according to your particular backend. (For example, quotes will be escaped + correctly.) + + Bad:: + + Entry.objects.extra(where=["headline='Lennon'"]) + + Good:: + + Entry.objects.extra(where=['headline=%s'], params=['Lennon']) + +QuerySet methods that do not return QuerySets +--------------------------------------------- + +The following ``QuerySet`` methods evaluate the ``QuerySet`` and return +something *other than* a ``QuerySet``. + +These methods do not use a cache (see _`Caching and QuerySets` below). Rather, +they query the database each time they're called. + +get(**kwargs) +~~~~~~~~~~~~~ + +Returns the object matching the given lookup parameters, which should be in +the format described in _`Field lookups`. + +``get()`` raises ``AssertionError`` if more than one object was found. + +``get()`` raises a ``DoesNotExist`` exception if an object wasn't found for the +given parameters. The ``DoesNotExist`` exception is an attribute of the model +class. Example:: + + Entry.objects.get(id='foo') # raises Entry.DoesNotExist + +The ``DoesNotExist`` exception inherits from +``django.core.exceptions.ObjectDoesNotExist``, so you can target multiple +``DoesNotExist`` exceptions. Example:: + + from django.core.exceptions import ObjectDoesNotExist + try: + e = Entry.objects.get(id=3) + b = Blog.objects.get(id=1) + except ObjectDoesNotExist: + print "Either the entry or blog doesn't exist." + +count() +~~~~~~~ + +Returns an integer representing the number of objects in the database matching +the ``QuerySet``. ``count()`` never raises exceptions. + +Example:: + + # Returns the total number of entries in the database. + Entry.objects.count() + + # Returns the number of entries whose headline contains 'Lennon' + Entry.objects.filter(headline__contains='Lennon').count() + +``count()`` performs a ``SELECT COUNT(*)`` behind the scenes, so you should +always use ``count()`` rather than loading all of the record into Python +objects and calling ``len()`` on the result. + +Depending on which database you're using (e.g. PostgreSQL vs. MySQL), +``count()`` may return a long integer instead of a normal Python integer. This +is an underlying implementation quirk that shouldn't pose any real-world +problems. + +in_bulk(id_list) +~~~~~~~~~~~~~~~~ + +Takes a list of primary-key values and returns a dictionary mapping each +primary-key value to an instance of the object with the given ID. + +Example:: + + >>> Blog.objects.in_bulk([1]) + {1: Beatles Blog} + >>> Blog.objects.in_bulk([1, 2]) + {1: Beatles Blog, 2: Cheddar Talk} + >>> Blog.objects.in_bulk([]) + {} + +If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary. + +latest(field_name=None) +~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the latest object in the table, by date, using the ``field_name`` +provided as the date field. + +This example returns the latest ``Entry`` in the table, according to the +``pub_date`` field:: + + Entry.objects.latest('pub_date') + +If your model's ``Meta`` specifies ``get_latest_by``, you can leave off the +``field_name`` argument to ``latest()``. Django will use the field specified in +``get_latest_by`` by default. + +Like ``get()``, ``latest()`` raises ``DoesNotExist`` if an object doesn't +exist with the given parameters. + +Note ``latest()`` exists purely for convenience and readability. + +Field lookups +------------- + +Field lookups are how you specify the meat of an SQL ``WHERE`` clause. They're +specified as keyword arguments to the ``QuerySet`` methods ``filter()``, +``exclude()`` and ``get()``. + +Basic lookups keyword arguments take the form ``field__lookuptype=value``. +(That's a double-underscore). For example:: + + Entry.objects.filter(pub_date__lte='2006-01-01') + +translates (roughly) into the following SQL:: + + SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'; + +.. admonition:: How this is possible + + Python has the ability to define functions that accept arbitrary name-value + arguments whose names and values are evaluated at runtime. For more + information, see `Keyword Arguments`_ in the official Python tutorial. + + .. _`Keyword Arguments`: http://docs.python.org/tut/node6.html#SECTION006720000000000000000 + +If you pass an invalid keyword argument, a lookup function will raise +``TypeError``. + +The database API supports the following lookup types: + +exact +~~~~~ + +Exact match. + +Example:: + + Entry.objects.get(id__exact=14) + +SQL equivalent:: + + SELECT ... WHERE id = 14; + +iexact +~~~~~~ + +Case-insensitive exact match. + +Example:: + + Blog.objects.get(name__iexact='beatles blog') + +SQL equivalent:: + + SELECT ... WHERE name ILIKE 'beatles blog'; + +Note this will match ``'Beatles Blog'``, ``'beatles blog'``, +``'BeAtLes BLoG'``, etc. + +contains +~~~~~~~~ + +Case-sensitive containment test. + +Example:: + + Entry.objects.get(headline__contains='Lennon') + +SQL equivalent:: + + SELECT ... WHERE headline LIKE '%Lennon%'; + +Note this will match the headline ``'Today Lennon honored'`` but not +``'today lennon honored'``. + +SQLite doesn't support case-sensitive ``LIKE`` statements; ``contains`` acts +like ``icontains`` for SQLite. + +icontains +~~~~~~~~~ + +Case-insensitive containment test. + +Example:: + + Entry.objects.get(headline__icontains='Lennon') + +SQL equivalent:: + + SELECT ... WHERE headline ILIKE '%Lennon%'; + +gt +~~ + +Greater than. + +Example:: + + Entry.objects.filter(id__gt=4) + +SQL equivalent:: + + SELECT ... WHERE id > 4; -The ``select`` keyword allows you to select extra fields. This should be a -dictionary mapping attribute names to a SQL clause to use to calculate that -attribute. For example:: +gte +~~~ - polls.get_list( - select={ - 'choice_count': 'SELECT COUNT(*) FROM choices WHERE poll_id = polls.id' - } +Greater than or equal to. + +lt +~~ + +Less than. + +lte +~~~ + +Less than or equal to. + +in +~~ + +In a given list. + +Example:: + + Entry.objects.filter(id__in=[1, 3, 4]) + +SQL equivalent:: + + SELECT ... WHERE id IN (1, 3, 4); + +startswith +~~~~~~~~~~ + +Case-sensitive starts-with. + +Example:: + + Entry.objects.filter(headline__startswith='Will') + +SQL equivalent:: + + SELECT ... WHERE headline LIKE 'Will%'; + +SQLite doesn't support case-sensitive ``LIKE`` statements; ``startswith`` acts +like ``istartswith`` for SQLite. + +istartswith +~~~~~~~~~~~ + +Case-insensitive starts-with. + +Example:: + + Entry.objects.filter(headline__istartswith='will') + +SQL equivalent:: + + SELECT ... WHERE headline ILIKE 'Will%'; + +endswith +~~~~~~~~ + +Case-sensitive ends-with. + +Example:: + + Entry.objects.filter(headline__endswith='cats') + +SQL equivalent:: + + SELECT ... WHERE headline LIKE '%cats'; + +SQLite doesn't support case-sensitive ``LIKE`` statements; ``endswith`` acts +like ``iendswith`` for SQLite. + +iendswith +~~~~~~~~~ + +Case-insensitive ends-with. + +Example:: + + Entry.objects.filter(headline__iendswith='will') + +SQL equivalent:: + + SELECT ... WHERE headline ILIKE '%will' + +range +~~~~~ + +Range test (inclusive). + +Example:: + + start_date = datetime.date(2005, 1, 1) + end_date = datetime.date(2005, 3, 31) + Entry.objects.filter(pub_date__range=(start_date, end_date)) + +SQL equivalent:: + + SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31'; + +You can use ``range`` anywhere you can use ``BETWEEN`` in SQL -- for dates, +numbers and even characters. + +year +~~~~ + +For date/datetime fields, exact year match. Takes a four-digit year. + +Example:: + + Entry.objects.filter(pub_date__year=2005) + +SQL equivalent:: + + SELECT ... WHERE EXTRACT('year' FROM pub_date) = '2005'; + +(The exact SQL syntax varies for each database engine.) + +month +~~~~~ + +For date/datetime fields, exact month match. Takes an integer 1 (January) +through 12 (December). + +Example:: + + Entry.objects.filter(pub_date__month=12) + +SQL equivalent:: + + SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12'; + +(The exact SQL syntax varies for each database engine.) + +day +~~~ + +For date/datetime fields, exact day match. + +Example:: + + Entry.objects.filter(pub_date__day=3) + +SQL equivalent:: + + SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3'; + +(The exact SQL syntax varies for each database engine.) + +Note this will match any record with a pub_date on the third day of the month, +such as January 3, July 3, etc. + +isnull +~~~~~~ + +``NULL`` or ``IS NOT NULL`` match. Takes either ``True`` or ``False``, which +correspond to ``IS NULL`` and ``IS NOT NULL``, respectively. + +Example:: + + Entry.objects.filter(pub_date__isnull=True) + +SQL equivalent:: + + SELECT ... WHERE pub_date IS NULL; + +Default lookups are exact +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you don't provide a lookup type -- that is, if your keyword argument doesn't +contain a double underscore -- the lookup type is assumed to be ``exact``. + +For example, the following two statements are equivalent:: + + Blog.objects.get(id=14) + Blog.objects.get(id__exact=14) + +This is for convenience, because ``exact`` lookups are the common case. + +The pk lookup shortcut +~~~~~~~~~~~~~~~~~~~~~~ + +For convenience, Django provides a ``pk`` lookup type, which stands for +"primary_key". This is shorthand for "an exact lookup on the primary-key." + +In the example ``Blog`` model, the primary key is the ``id`` field, so these +two statements are equivalent:: + + Blog.objects.get(id__exact=14) + Blog.objects.get(pk=14) + +``pk`` lookups also work across joins. For example, these two statements are +equivalent:: + + Entry.objects.filter(blog__id__exact=3) + Entry.objects.filter(blog__pk=3) + +Escaping parenthesis and underscores in LIKE statements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The field lookups that equate to ``LIKE`` SQL statements (``iexact``, +``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith`` +and ``iendswith``) will automatically escape the two special characters used in +``LIKE`` statements -- the percent sign and the underscore. (In a ``LIKE`` +statement, the percent sign signifies a multiple-character wildcard and the +underscore signifies a single-character wildcard.) + +This means things should work intuitively, so the abstraction doesn't leak. +For example, to retrieve all the entries that contain a percent sign, just use +the percent sign as any other character:: + + Entry.objects.filter(headline__contains='%') + +Django takes care of the quoting for you; the resulting SQL will look something +like this:: + + SELECT ... WHERE headline LIKE '%\%%'; + +Same goes for underscores. Both percentage signs and underscores are handled +for you transparently. + +Caching and QuerySets +--------------------- + +Each ``QuerySet`` contains a cache, to minimize database access. It's important +to understand how it works, in order to write the most efficient code. + +In a newly created ``QuerySet``, the cache is empty. The first time a +``QuerySet`` is evaluated -- and, hence, a database query happens -- Django +saves the query results in the ``QuerySet``'s cache and returns the results +that have been explicitly requested (e.g., the next element, if the +``QuerySet`` is being iterated over). Subsequent evaluations of the +``QuerySet`` reuse the cached results. + +Keep this caching behavior in mind, because it may bite you if you don't use +your ``QuerySet``s correctly. For example, the following will create two +``QuerySet``s, evaluate them, and throw them away:: + + print [e.headline for e in Entry.objects.all()] + print [e.pub_date for e in Entry.objects.all()] + +That means the same database query will be executed twice, effectively doubling +your database load. Also, there's a possibility the two lists may not include +the same database records, because an ``Entry`` may have been added or deleted +in the split second between the two requests. + +To avoid this problem, simply save the ``QuerySet`` and reuse it:: + + queryset = Poll.objects.all() + print [p.headline for p in queryset] # Evaluate the query set. + print [p.pub_date for p in queryset] # Re-use the cache from the evaluation. + +Comparing objects +================= + +To compare two model instances, just use the standard Python comparison operator, +the double equals sign: ``==``. Behind the scenes, that compares the primary +key values of two models. + +Using the ``Entry`` example above, the following two statements are equivalent:: + + some_entry == other_entry + some_entry.id == other_entry.id + +If a model's primary key isn't called ``id``, no problem. Comparisons will +always use the primary key, whatever it's called. For example, if a model's +primary key field is called ``name``, these two statements are equivalent:: + + some_obj == other_obj + some_obj.name == other_obj.name + + + + +======================================== +THE REST OF THIS HAS NOT YET BEEN EDITED +======================================== + + +OR lookups +========== + +Keyword argument queries are "AND"ed together. If you have more +complex query requirements (for example, you need to include an ``OR`` +statement in your query), you need to use ``Q`` objects. + +A ``Q`` object (``django.db.models.Q``) is an object used to encapsulate a +collection of keyword arguments. These keyword arguments are specified in +the same way as keyword arguments to the basic lookup functions like get() +and filter(). For example:: + + Q(question__startswith='What') + +is a ``Q`` object encapsulating a single ``LIKE`` query. ``Q`` objects can be +combined using the ``&`` and ``|`` operators. When an operator is used on two +``Q`` objects, it yields a new ``Q`` object. For example the statement:: + + Q(question__startswith='Who') | Q(question__startswith='What') + +... yields a single ``Q`` object that represents the "OR" of two +"question__startswith" queries, equivalent to the SQL WHERE clause:: + + ... WHERE question LIKE 'Who%' OR question LIKE 'What%' + +You can compose statements of arbitrary complexity by combining ``Q`` objects +with the ``&`` and ``|`` operators. Parenthetical grouping can also be used. + +One or more ``Q`` objects can then provided as arguments to the lookup +functions. If multiple ``Q`` object arguments are provided to a lookup +function, they will be "AND"ed together. For example:: + + Poll.objects.get( + Q(question__startswith='Who'), + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) ) -Each of the resulting ``Poll`` objects will have an extra attribute, ``choice_count``, -an integer count of associated ``Choice`` objects. Note that the parenthesis required by -most database engines around sub-selects are not required in Django's ``select`` -clauses. +... roughly translates into the SQL:: -``where`` / ``tables`` ----------------------- + SELECT * from polls WHERE question LIKE 'Who%' + AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') + +If necessary, lookup functions can mix the use of ``Q`` objects and keyword +arguments. All arguments provided to a lookup function (be they keyword +argument or ``Q`` object) are "AND"ed together. However, if a ``Q`` object is +provided, it must precede the definition of any keyword arguments. For +example:: + + Poll.objects.get( + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), + question__startswith='Who') + +... would be a valid query, equivalent to the previous example; but:: + + # INVALID QUERY + Poll.objects.get( + question__startswith='Who', + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))) + +... would not be valid. + +A ``Q`` objects can also be provided to the ``complex`` keyword argument. For example:: + + Poll.objects.get( + complex=Q(question__startswith='Who') & + (Q(pub_date=date(2005, 5, 2)) | + Q(pub_date=date(2005, 5, 6)) + ) + ) + +See the `OR lookups examples page`_ for more examples. + +.. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/ + + +Relationships (joins) +===================== + +When you define a relationship in a model (i.e., a ForeignKey, +OneToOneField, or ManyToManyField), Django uses the name of the +relationship to add a descriptor_ on every instance of the model. +This descriptor behaves just like a normal attribute, providing +access to the related object or objects. For example, +``mychoice.poll`` will return the poll object associated with a specific +instance of ``Choice``. + +.. _descriptor: http://users.rcn.com/python/download/Descriptor.htm + +Django also adds a descriptor for the 'other' side of the relationship - +the link from the related model to the model that defines the relationship. +Since the related model has no explicit reference to the source model, +Django will automatically derive a name for this descriptor. The name that +Django chooses depends on the type of relation that is represented. However, +if the definition of the relation has a `related_name` parameter, Django +will use this name in preference to deriving a name. -If you need to explicitly pass extra ``WHERE`` clauses -- perhaps to perform -non-explicit joins -- use the ``where`` keyword. If you need to -join other tables into your query, you can pass their names to ``tables``. +There are two types of descriptor that can be employed: Single Object +Descriptors and Object Set Descriptors. The following table describes +when each descriptor type is employed. The local model is the model on +which the relation is defined; the related model is the model referred +to by the relation. -``where`` and ``tables`` both take a list of strings. All ``where`` parameters -are "AND"ed to any other search criteria. + =============== ============= ============= + Relation Type Local Model Related Model + =============== ============= ============= + OneToOneField Single Object Single Object + ForeignKey Single Object Object Set + + ManyToManyField Object Set Object Set + =============== ============= ============= + +Single object descriptor +------------------------ + +If the related object is a single object, the descriptor acts +just as if the related object were an attribute:: + + # Obtain the existing poll + old_poll = mychoice.poll + # Set a new poll + mychoice.poll = new_poll + # Save the change + mychoice.save() + +Whenever a change is made to a Single Object Descriptor, save() +must be called to commit the change to the database. + +If no `related_name` parameter is defined, Django will use the +lower case version of the source model name as the name for the +related descriptor. For example, if the ``Choice`` model had +a field:: + + coordinator = models.OneToOneField(User) + +... instances of the model ``User`` would be able to call: + + old_choice = myuser.choice + myuser.choice = new_choice + +By default, relations do not allow values of None; if you attempt +to assign None to a Single Object Descriptor, an AttributeError +will be thrown. However, if the relation has 'null=True' set +(i.e., the database will allow NULLs for the relation), None can +be assigned and returned by the descriptor to represent empty +relations. + +Access to Single Object Descriptors is cached. The first time +a descriptor on an instance is accessed, the database will be +queried, and the result stored. Subsequent attempts to access +the descriptor on the same instance will use the cached value. + +Object set descriptor +--------------------- + +An Object Set Descriptor acts just like the Manager - as an initial Query +Set describing the set of objects related to an instance. As such, any +query refining technique (filter, exclude, etc) can be used on the Object +Set descriptor. This also means that Object Set Descriptor cannot be evaluated +directly - the ``all()`` method must be used to produce a Query Set that +can be evaluated. + +If no ``related_name`` parameter is defined, Django will use the lower case +version of the source model name appended with `_set` as the name for the +related descriptor. For example, every ``Poll`` object has a ``choice_set`` +descriptor. + +The Object Set Descriptor has utility methods to add objects to the +related object set: + +``add(obj1, obj2, ...)`` + Add the specified objects to the related object set. + +``create(\**kwargs)`` + Create a new object, and put it in the related object set. See + _`Creating new objects` + +The Object Set Descriptor may also have utility methods to remove objects +from the related object set: + +``remove(obj1, obj2, ...)`` + Remove the specified objects from the related object set. + +``clear()`` + Remove all objects from the related object set. + +These two removal methods will not exist on ForeignKeys where ``Null=False`` +(such as in the Poll example). This is to prevent database inconsistency - if +the related field cannot be set to None, then an object cannot be removed +from one relation without adding it to another. + +The members of a related object set can be assigned from any iterable object. For example:: - polls.get_list(question__startswith='Who', where=['id IN (3, 4, 5, 20)']) + mypoll.choice_set = [choice1, choice2] -...translates (roughly) into the following SQL: +If the ``clear()`` method is available, any pre-existing objects will be removed +from the Object Set before all objects in the iterable (in this case, a list) +are added to the choice set. If the ``clear()`` method is not available, all +objects in the iterable will be added without removing any existing elements. - SELECT * FROM polls_polls WHERE question LIKE 'Who%' AND id IN (3, 4, 5, 20); +Each of these operations on the Object Set Descriptor has immediate effect +on the database - every add, create and remove is immediately and +automatically saved to the database. -Changing objects -================ +Relationships and queries +========================= -Once you've retrieved an object from the database using any of the above -options, changing it is extremely easy. Make changes directly to the -objects fields, then call the object's ``save()`` method:: +When composing a ``filter`` or ``exclude`` refinement, it may be necessary to +include conditions that span relationships. Relations can be followed as deep +as required - just add descriptor names, separated by double underscores, to +describe the full path to the query attribute. The query:: - >>> p = polls.get_object(id__exact=15) - >>> p.slug = "new_slug" - >>> p.pub_date = datetime.datetime.now() - >>> p.save() + Foo.objects.filter(name1__name2__name3__attribute__lookup=value) -Creating new objects -==================== +... is interpreted as 'get every Foo that has a name1 that has a name2 that +has a name3 that has an attribute with lookup matching value'. In the Poll +example:: -Creating new objects (i.e. ``INSERT``) is done by creating new instances -of objects then calling save() on them:: + Choice.objects.filter(poll__slug__startswith="eggs") - >>> p = polls.Poll(slug="eggs", - ... question="How do you like your eggs?", - ... pub_date=datetime.datetime.now(), - ... expire_date=some_future_date) - >>> p.save() +... describes the set of choices for which the related poll has a slug +attribute that starts with "eggs". Django automatically composes the joins +and conditions required for the SQL query. -Calling ``save()`` on an object with a primary key whose value is ``None`` -signifies to Django that the object is new and should be inserted. +Creating new related objects +============================ -Related objects (e.g. ``Choices``) are created using convenience functions:: +Related objects are created using the ``create()`` convenience function on +the descriptor Manager for relation:: - >>> p.add_choice(choice="Over easy", votes=0) - >>> p.add_choice(choice="Scrambled", votes=0) - >>> p.add_choice(choice="Fertilized", votes=0) - >>> p.add_choice(choice="Poached", votes=0) - >>> p.get_choice_count() + >>> p.choice_set.create(choice="Over easy", votes=0) + >>> p.choice_set.create(choice="Scrambled", votes=0) + >>> p.choice_set.create(choice="Fertilized", votes=0) + >>> p.choice_set.create(choice="Poached", votes=0) + >>> p.choice_set.count() 4 -Each of those ``add_choice`` methods is equivalent to (but much simpler than):: +Each of those ``create()`` methods is equivalent to (but much simpler than):: - >>> c = polls.Choice(poll_id=p.id, choice="Over easy", votes=0) + >>> c = Choice(poll_id=p.id, choice="Over easy", votes=0) >>> c.save() -Note that when using the `add_foo()`` methods, you do not give any value +Note that when using the `create()`` method, you do not give any value for the ``id`` field, nor do you give a value for the field that stores the relation (``poll_id`` in this case). -The ``add_FOO()`` method always returns the newly created object. +The ``create()`` method always returns the newly created object. Deleting objects ================ @@ -514,31 +1371,27 @@ deletes the object and has no return value. Example:: >>> c.delete() -Comparing objects -================= +Objects can also be deleted in bulk. Every Query Set has a ``delete()`` method +that will delete all members of the query set. For example:: -To compare two model objects, just use the standard Python comparison operator, -the double equals sign: ``==``. Behind the scenes, that compares the primary -key values of two models. + >>> Polls.objects.filter(pub_date__year=2005).delete() -Using the ``Poll`` example above, the following two statements are equivalent:: +would bulk delete all Polls with a year of 2005. Note that ``delete()`` is the +only Query Set method that is not exposed on the Manager itself. - some_poll == other_poll - some_poll.id == other_poll.id +This is a safety mechanism to prevent you from accidentally requesting +``Polls.objects.delete()``, and deleting *all* the polls. -If a model's primary key isn't called ID, no problem. Comparisons will always -use the primary key, whatever it's called. For example, if a model's primary -key field is called ``name``, these two statements are equivalent:: +If you *actually* want to delete all the objects, then you have to explicitly +request a complete query set:: - some_obj == other_obj - some_obj.name == other_obj.name + Polls.objects.all().delete() Extra instance methods ====================== -In addition to ``save()``, ``delete()`` and all of the ``add_*`` and ``get_*`` -related-object methods, a model object might get any or all of the following -methods: +In addition to ``save()``, ``delete()``, a model object might get any or all +of the following methods: get_FOO_display() ----------------- @@ -572,10 +1425,10 @@ For every ``DateField`` and ``DateTimeField`` that does not have ``null=True``, the object will have ``get_next_by_FOO()`` and ``get_previous_by_FOO()`` methods, where ``FOO`` is the name of the field. This returns the next and previous object with respect to the date field, raising the appropriate -``*DoesNotExist`` exception when appropriate. +``DoesNotExist`` exception when appropriate. Both methods accept optional keyword arguments, which should be in the format -described in "Field lookups" above. +described in _`Field lookups` above. Note that in the case of identical date values, these methods will use the ID as a fallback check. This guarantees that no records are skipped or duplicated. @@ -604,14 +1457,14 @@ returns an empty string. get_FOO_size() -------------- -For every ``FileField``, the object will have a ``get_FOO_size()`` method, +For every ``FileField``, the object will have a ``get_FOO_filename()`` method, where ``FOO`` is the name of the field. This returns the size of the file, in bytes. (Behind the scenes, it uses ``os.path.getsize``.) save_FOO_file(filename, raw_contents) ------------------------------------- -For every ``FileField``, the object will have a ``save_FOO_file()`` method, +For every ``FileField``, the object will have a ``get_FOO_filename()`` method, where ``FOO`` is the name of the field. This saves the given file to the filesystem, using the given filename. If a file with the given filename already exists, Django adds an underscore to the end of the filename (but before the @@ -623,48 +1476,3 @@ get_FOO_height() and get_FOO_width() For every ``ImageField``, the object will have ``get_FOO_height()`` and ``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This returns the height (or width) of the image, as an integer, in pixels. - -Extra module functions -====================== - -In addition to every function described in "Basic lookup functions" above, a -model module might get any or all of the following methods: - -get_FOO_list(kind, \**kwargs) ------------------------------ - -For every ``DateField`` and ``DateTimeField``, the model module will have a -``get_FOO_list()`` function, where ``FOO`` is the name of the field. This -returns a list of ``datetime.datetime`` objects representing all available -dates of the given scope, as defined by the ``kind`` argument. ``kind`` should -be either ``"year"``, ``"month"`` or ``"day"``. Each ``datetime.datetime`` -object in the result list is "truncated" to the given ``type``. - - * ``"year"`` returns a list of all distinct year values for the field. - * ``"month"`` returns a list of all distinct year/month values for the field. - * ``"day"`` returns a list of all distinct year/month/day values for the field. - -Additional, optional keyword arguments, in the format described in -"Field lookups" above, are also accepted. - -Here's an example, using the ``Poll`` model defined above:: - - >>> from datetime import datetime - >>> p1 = polls.Poll(slug='whatsup', question="What's up?", - ... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 3, 20)) - >>> p1.save() - >>> p2 = polls.Poll(slug='name', question="What's your name?", - ... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 4, 20)) - >>> p2.save() - >>> polls.get_pub_date_list('year') - [datetime.datetime(2005, 1, 1)] - >>> polls.get_pub_date_list('month') - [datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)] - >>> polls.get_pub_date_list('day') - [datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)] - >>> polls.get_pub_date_list('day', question__contains='name') - [datetime.datetime(2005, 3, 20)] - -``get_FOO_list()`` also accepts an optional keyword argument ``order``, which -should be either ``"ASC"`` or ``"DESC"``. This specifies how to order the -results. Default is ``"ASC"``. diff --git a/docs/design_philosophies.txt b/docs/design_philosophies.txt index 89a537da17..17ed3ad6da 100644 --- a/docs/design_philosophies.txt +++ b/docs/design_philosophies.txt @@ -20,6 +20,9 @@ For example, the template system knows nothing about Web requests, the database layer knows nothing about data display and the view system doesn't care which template system a programmer uses. +Although Django comes with a full stack for convenience, the pieces of the +stack are independent of another wherever possible. + .. _`loose coupling and tight cohesion`: http://c2.com/cgi/wiki?CouplingAndCohesion Less code @@ -49,7 +52,10 @@ Explicit is better than implicit -------------------------------- This, a `core Python principle`_, means Django shouldn't do too much "magic." -Magic shouldn't happen unless there's a really good reason for it. +Magic shouldn't happen unless there's a really good reason for it. Magic is +worth using only if it creates a huge convenience unattainable in other ways, +and it isn't implemented in a way that confuses developers who are trying to +learn how to use the feature. .. _`core Python principle`: http://www.python.org/doc/Humor.html#zen @@ -96,8 +102,9 @@ optimize statements internally. This is why developers need to call ``save()`` explicitly, rather than the framework saving things behind the scenes silently. -This is also why the ``select_related`` argument exists. It's an optional -performance booster for the common case of selecting "every related object." +This is also why the ``select_related()`` ``QuerySet`` method exists. It's an +optional performance booster for the common case of selecting "every related +object." Terse, powerful syntax ---------------------- @@ -144,6 +151,8 @@ design pretty URLs than ugly ones. File extensions in Web-page URLs should be avoided. +Vignette-style commas in URLs deserve severe punishment. + Definitive URLs --------------- @@ -186,6 +195,13 @@ The template system shouldn't be designed so that it only outputs HTML. It should be equally good at generating other text-based formats, or just plain text. +XML should not be used for template languages +--------------------------------------------- + +Using an XML engine to parse templates introduces a whole new world of human +error in editing templates -- and incurs an unacceptable level of overhead in +template processing. + Assume designer competence -------------------------- diff --git a/docs/django-admin.txt b/docs/django-admin.txt index 45cc2363dc..b314366fee 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -1,15 +1,10 @@ -=========================== -The django-admin.py utility -=========================== +============================= +django-admin.py and manage.py +============================= ``django-admin.py`` is Django's command-line utility for administrative tasks. This document outlines all it can do. -The ``django-admin.py`` script should be on your system path if you installed -Django via its ``setup.py`` utility. If it's not on your path, you can find it in -``site-packages/django/bin`` within your Python installation. Consider -symlinking to it from some place on your path, such as ``/usr/local/bin``. - In addition, ``manage.py`` is automatically created in each Django project. ``manage.py`` is a thin wrapper around ``django-admin.py`` that takes care of two things for you before delegating to ``django-admin.py``: @@ -19,6 +14,11 @@ two things for you before delegating to ``django-admin.py``: * It sets the ``DJANGO_SETTINGS_MODULE`` environment variable so that it points to your project's ``settings.py`` file. +The ``django-admin.py`` script should be on your system path if you installed +Django via its ``setup.py`` utility. If it's not on your path, you can find it in +``site-packages/django/bin`` within your Python installation. Consider +symlinking to it from some place on your path, such as ``/usr/local/bin``. + Generally, when working on a single Django project, it's easier to use ``manage.py``. Use ``django-admin.py`` with ``DJANGO_SETTINGS_MODULE``, or the ``--settings`` command line option, if you need to switch between multiple @@ -38,18 +38,17 @@ document. Run ``django-admin.py --help`` to display a help message that includes a terse list of all available actions and options. -Most actions take a list of "modelmodule"s. A "modelmodule," in this case, is -the name of a file containing Django models. For example, if you have a model -module called ``myproject/apps/polls/pollmodels.py``, the "modelmodule" in this -case would be ``"pollmodels"``. +Most actions take a list of ``appname``s. An ``appname`` is the basename of the +package containing your models. For example, if your ``INSTALLED_APPS`` +contains the string ``'mysite.blog'``, the ``appname`` is ``blog``. Available actions ================= -adminindex [modelmodule modelmodule ...] ----------------------------------------- +adminindex [appname appname ...] +-------------------------------- -Prints the admin-index template snippet for the given model module(s). +Prints the admin-index template snippet for the given appnames. Use admin-index template snippets if you want to customize the look and feel of your admin's index page. See `Tutorial 2`_ for more information. @@ -64,29 +63,41 @@ backend. See the `cache documentation`_ for more information. .. _cache documentation: http://www.djangoproject.com/documentation/cache/ -createsuperuser ---------------- +dbshell +------- -Creates a superuser account interactively. It asks you for a username, e-mail -address and password. +Runs the command-line client for the database engine specified in your +``DATABASE_ENGINE`` setting, with the connection parameters specified in your +``DATABASE_USER``, ``DATABASE_PASSWORD``, etc., settings. -You can specify ``username email password`` on the command line, for convenient -use in shell scripts. Example:: + * For PostgreSQL, this runs the ``psql`` command-line client. + * For MySQL, this runs the ``mysql`` command-line client. + * For SQLite, this runs the ``sqlite3`` command-line client. - django-admin.py createsuperuser john john@example.com mypassword +This command assumes the programs are on your ``PATH`` so that a simple call to +the program name (``psql``, ``mysql``, ``sqlite3``) will find the program in +the right place. There's no way to specify the location of the program +manually. -init ----- +diffsettings +------------ -Initializes the database with the tables and data Django needs by default. -Specifically, these are the database tables from the ``auth`` and ``core`` -models. +Displays differences between the current settings file and Django's default +settings. -inspectdb [dbname] ------------------- +Settings that don't appear in the defaults are followed by ``"###"``. For +example, the default settings don't define ``ROOT_URLCONF``, so +``ROOT_URLCONF`` is followed by ``"###"`` in the output of ``diffsettings``. -Introspects the database tables in the given database and outputs a Django -model module to standard output. +Note that Django's default settings live in ``django/conf/global_settings.py``, +if you're ever curious to see the full list of defaults. + +inspectdb +--------- + +Introspects the database tables in the database pointed-to by the +``DATABASE_NAME`` setting and outputs a Django model module (a ``models.py`` +file) to standard output. Use this if you have a legacy database with which you'd like to use Django. The script will inspect the database and create a model for each table within @@ -101,12 +112,12 @@ output: ``'This field type is a guess.'`` next to the field in the generated model. - * **New in Django development version.** If the database column name is a - Python reserved word (such as ``'pass'``, ``'class'`` or ``'for'``), - ``inspectdb`` will append ``'_field'`` to the attribute name. For - example, if a table has a column ``'for'``, the generated model will have - a field ``'for_field'``, with the ``db_column`` attribute set to - ``'for'``. ``inspectdb`` will insert the Python comment + * If the database column name is a Python reserved word (such as + ``'pass'``, ``'class'`` or ``'for'``), ``inspectdb`` will append + ``'_field'`` to the attribute name. For example, if a table has a column + ``'for'``, the generated model will have a field ``'for_field'``, with + the ``db_column`` attribute set to ``'for'``. ``inspectdb`` will insert + the Python comment ``'Field renamed because it was a Python reserved word.'`` next to the field. @@ -115,25 +126,16 @@ you run it, you'll want to look over the generated models yourself to make customizations. In particular, you'll need to rearrange models' order, so that models that refer to other models are ordered properly. -If you're using Django 0.90 or 0.91, you'll need to add ``primary_key=True`` to -one field in each model. In the Django development version, primary keys are -automatically introspected for PostgreSQL and MySQL, and Django puts in the -``primary_key=True`` where needed. +Primary keys are automatically introspected for PostgreSQL and MySQL, in which +case Django puts in the ``primary_key=True`` where needed. ``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection -only works in PostgreSQL. - -install [modelmodule modelmodule ...] -------------------------------------- - -Executes the equivalent of ``sqlall`` for the given model module(s). +only works in PostgreSQL and with certain types of MySQL tables. -installperms [modelmodule modelmodule ...] ------------------------------------------- +install [appname appname ...] +----------------------------- -Installs any admin permissions for the given model module(s) that aren't -already installed in the database. Outputs a message telling how many -permissions were added, if any. +Executes the equivalent of ``sqlall`` for the given appnames. runserver [optional port number, or ipaddr:port] ------------------------------------------------ @@ -144,7 +146,7 @@ IP address and port number explicitly. If you run this script as a user with normal privileges (recommended), you might not have access to start a port on a low port number. Low port numbers -are reserved for superusers (root). +are reserved for the superuser (root). DO NOT USE THIS SERVER IN A PRODUCTION SETTING. @@ -153,7 +155,7 @@ needed. You don't need to restart the server for code changes to take effect. When you start the server, and each time you change Python code while the server is running, the server will validate all of your installed models. (See -the "validate" option below.) If the validator finds errors, it will print +the ``validate`` command below.) If the validator finds errors, it will print them to standard output, but it won't stop the server. You can run as many servers as you want, as long as they're on separate ports. @@ -180,49 +182,49 @@ shell Starts the Python interactive interpreter. -**New in Django development version:** Uses IPython_, if it's installed. If you -have IPython installed and want to force use of the "plain" Python interpreter, -use the ``--plain`` option, like so:: +Django will use IPython_, if it's installed. If you have IPython installed and +want to force use of the "plain" Python interpreter, use the ``--plain`` +option, like so:: django-admin.py shell --plain .. _IPython: http://ipython.scipy.org/ -sql [modelmodule modelmodule ...] ---------------------------------- +sql [appname appname ...] +------------------------- -Prints the CREATE TABLE SQL statements for the given model module(s). +Prints the CREATE TABLE SQL statements for the given appnames. -sqlall [modelmodule modelmodule ...] ------------------------------------- +sqlall [appname appname ...] +---------------------------- -Prints the CREATE TABLE and initial-data SQL statements for the given model module(s). +Prints the CREATE TABLE and initial-data SQL statements for the given appnames. -sqlclear [modelmodule modelmodule ...] +sqlclear [appname appname ...] -------------------------------------- -Prints the DROP TABLE SQL statements for the given model module(s). +Prints the DROP TABLE SQL statements for the given appnames. -sqlindexes [modelmodule modelmodule ...] +sqlindexes [appname appname ...] ---------------------------------------- -Prints the CREATE INDEX SQL statements for the given model module(s). +Prints the CREATE INDEX SQL statements for the given appnames. -sqlinitialdata [modelmodule modelmodule ...] +sqlinitialdata [appname appname ...] -------------------------------------------- -Prints the initial INSERT SQL statements for the given model module(s). +Prints the initial INSERT SQL statements for the given appnames. -sqlreset [modelmodule modelmodule ...] +sqlreset [appname appname ...] -------------------------------------- -Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given model module(s). +Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given appnames. -sqlsequencereset [modelmodule modelmodule ...] +sqlsequencereset [appname appname ...] ---------------------------------------------- Prints the SQL statements for resetting PostgreSQL sequences for the given -model module(s). +appnames. See http://simon.incutio.com/archive/2004/04/21/postgres for more information. @@ -252,11 +254,12 @@ Available options Example usage:: - django-admin.py init --settings=myproject.settings + django-admin.py syncdb --settings=mysite.settings Explicitly specifies the settings module to use. The settings module should be -in Python path syntax, e.g. "myproject.settings". If this isn't provided, -``django-admin.py`` will use the DJANGO_SETTINGS_MODULE environment variable. +in Python package syntax, e.g. ``mysite.settings``. If this isn't provided, +``django-admin.py`` will use the ``DJANGO_SETTINGS_MODULE`` environment +variable. Note that this option is unnecessary in ``manage.py``, because it takes care of setting ``DJANGO_SETTINGS_MODULE`` for you. @@ -266,7 +269,7 @@ setting ``DJANGO_SETTINGS_MODULE`` for you. Example usage:: - django-admin.py init --pythonpath='/home/djangoprojects/myproject' + django-admin.py syncdb --pythonpath='/home/djangoprojects/myproject' Adds the given filesystem path to the Python `import search path`_. If this isn't provided, ``django-admin.py`` will use the ``PYTHONPATH`` environment @@ -282,3 +285,27 @@ setting the Python path for you. Displays a help message that includes a terse list of all available actions and options. + +Extra niceties +============== + +Syntax coloring +--------------- + +The ``django-admin.py`` / ``manage.py`` commands that output SQL to standard +output will use pretty color-coded output if your terminal supports +ANSI-colored output. It won't use the color codes if you're piping the +command's output to another program. + +Bash completion +--------------- + +If you use the Bash shell, consider installing the Django bash completion +script, which lives in ``extras/django_bash_completion`` in the Django +distribution. It enables tab-completion of ``django-admin.py`` and +``manage.py`` commands, so you can, for instance... + + * Type ``django-admin.py``. + * Press [TAB] to see all available options. + * Type ``sql``, then [TAB], to see all available options whose names start + with ``sql``. diff --git a/docs/email.txt b/docs/email.txt index ae55a51a14..b38b855cb3 100644 --- a/docs/email.txt +++ b/docs/email.txt @@ -20,11 +20,11 @@ In two lines:: send_mail('Subject here', 'Here is the message.', 'from@example.com', ['to@example.com'], fail_silently=False) -The send_mail function -====================== +send_mail() +=========== The simplest way to send e-mail is using the function -``django.core.mail.send_mail``. Here's its definition:: +``django.core.mail.send_mail()``. Here's its definition:: send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=EMAIL_HOST_USER, @@ -42,20 +42,19 @@ are required. * ``fail_silently``: A boolean. If it's ``False``, ``send_mail`` will raise an ``smtplib.SMTPException``. See the `smtplib docs`_ for a list of possible exceptions, all of which are subclasses of ``SMTPException``. - * ``auth_user``: **New in Django development version.** The optional - username to use to authenticate to the SMTP server. If this isn't - provided, Django will use the value of the ``EMAIL_HOST_USER`` setting. - * ``auth_password``: **New in Django development version.** The optional - password to use to authenticate to the SMTP server. If this isn't - provided, Django will use the value of the ``EMAIL_HOST_PASSWORD`` - setting. + * ``auth_user``: The optional username to use to authenticate to the SMTP + server. If this isn't provided, Django will use the value of the + ``EMAIL_HOST_USER`` setting. + * ``auth_password``: The optional password to use to authenticate to the + SMTP server. If this isn't provided, Django will use the value of the + ``EMAIL_HOST_PASSWORD`` setting. .. _smtplib docs: http://www.python.org/doc/current/lib/module-smtplib.html -The send_mass_mail function -=========================== +send_mass_mail() +================ -``django.core.mail.send_mass_mail`` is intended to handle mass e-mailing. +``django.core.mail.send_mass_mail()`` is intended to handle mass e-mailing. Here's the definition:: send_mass_mail(datatuple, fail_silently=False, @@ -66,25 +65,24 @@ Here's the definition:: (subject, message, from_email, recipient_list) ``fail_silently``, ``auth_user`` and ``auth_password`` have the same functions -as in ``send_mail()``. Note that ``auth_user`` and ``auth_password`` are only -available in the Django development version. +as in ``send_mail()``. Each separate element of ``datatuple`` results in a separate e-mail message. As in ``send_mail()``, recipients in the same ``recipient_list`` will all see the other addresses in the e-mail messages's "To:" field. -send_mass_mail vs. send_mail ----------------------------- +send_mass_mail() vs. send_mail() +-------------------------------- The main difference between ``send_mass_mail()`` and ``send_mail()`` is that ``send_mail()`` opens a connection to the mail server each time it's executed, while ``send_mass_mail()`` uses a single connection for all of its messages. This makes ``send_mass_mail()`` slightly more efficient. -The mail_admins function -======================== +mail_admins() +============= -``django.core.mail.mail_admins`` is a shortcut for sending an e-mail to the +``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the site admins, as defined in the `ADMINS setting`_. Here's the definition:: mail_admins(subject, message, fail_silently=False) @@ -94,14 +92,16 @@ site admins, as defined in the `ADMINS setting`_. Here's the definition:: The "From:" header of the e-mail will be the value of the `SERVER_EMAIL setting`_. +This method exists for convenience and readability. + .. _ADMINS setting: http://www.djangoproject.com/documentation/settings/#admins .. _EMAIL_SUBJECT_PREFIX setting: http://www.djangoproject.com/documentation/settings/#email-subject-prefix .. _SERVER_EMAIL setting: http://www.djangoproject.com/documentation/settings/#server-email -The mail_managers function -========================== +mail_managers() function +======================== -``django.core.mail.mail_managers`` is just like ``mail_admins``, except it +``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it sends an e-mail to the site managers, as defined in the `MANAGERS setting`_. Here's the definition:: diff --git a/docs/faq.txt b/docs/faq.txt index 977a3644fe..e8bf09a7d3 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -8,14 +8,20 @@ General questions Why does this project exist? ---------------------------- -Django grew from a very practical need: in our fast-paced newsroom, we often -have only a matter of hours to take a complicated Web application from -concept to public launch. Django was designed to not only allow us to -build Web applications quickly, but to allow us to build them right. +Django grew from a very practical need: World Online, a newspaper Web +operation, is responsible for building intensive Web applications on journalism +deadlines. In the fast-paced newsroom, World Online often has only a matter of +hours to take a complicated Web application from concept to public launch. + +At the same time, the World Online Web developers have consistently been +perfectionists when it comes to following best practices of Web development. + +Thus, Django was designed not only to allow fast Web development, but +*best-practice* Web development. Django would not be possible without a whole host of open-source projects -- -`Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're thrilled to be -able to give something back to the open-source community. +`Apache`_, `Python`_, and `PostgreSQL`_ to name a few -- and we're thrilled to +be able to give something back to the open-source community. .. _Apache: http://httpd.apache.org/ .. _Python: http://www.python.org/ @@ -29,25 +35,28 @@ to early 1950s. To this day, he's considered one of the best guitarists of all t Listen to his music. You'll like it. -According to Wikipedia_, "Django is pronounced **zhane**-go (with a long 'a')." +Django is pronounced **JANG**-oh. Rhymes with FANG-oh. .. _Django Reinhardt: http://en.wikipedia.org/wiki/Django_Reinhardt -.. _Wikipedia: http://en.wikipedia.org/wiki/Django_Reinhardt Is Django stable? ----------------- -We've been using Django for almost two years. Sites built on Django have -weathered traffic spikes of over one million hits an hour, and at least -one Slashdotting. Yes, it's quite stable. +Yes. World Online has been using Django for more than two years. Sites built on +Django have weathered traffic spikes of over one million hits an hour and at +least one Slashdotting. Yes, it's quite stable. Does Django scale? ------------------ Yes. Compared to development time, hardware is cheap, and so Django is designed to take advantage of as much hardware as you can throw at it. -Django ships with clean separation of the database layer from the -application layer and a simple-yet-powerful `cache framework`_. + +Django uses a "shared-nothing" architecture, which means you can add hardware +at any level -- database servers, caching servers or Web/application servers. + +The framework cleanly separates components such as its database layer and +application layer. And it ships with a simple-yet-powerful `cache framework`_. .. _`cache framework`: http://www.djangoproject.com/documentation/cache/ @@ -60,32 +69,34 @@ Lawrence, Kansas, USA. `Adrian Holovaty`_ Adrian is a Web developer with a background in journalism. He was lead developer at World Online for 2.5 years, during which time Django was - developed and implemented on World Online's sites. Now he's editor of - editorial innovations at washingtonpost.com, and he continues to oversee - Django development. He likes playing guitar (Django Reinhardt style) and - hacking on side projects such as `chicagocrime.org`_. He lives in Chicago. + developed and implemented on World Online's sites. Now he works for + washingtonpost.com building rich, database-backed information sites, and + continues to oversee Django development. He likes playing guitar (Django + Reinhardt style) and hacking on side projects such as `chicagocrime.org`_. + He lives in Chicago. On IRC, Adrian goes by ``adrian_h``. +`Jacob Kaplan-Moss`_ + Jacob is a whipper-snapper from California who spends equal time coding and + cooking. He's lead developer at World Online and actively hacks on various + cool side projects. He's contributed to the Python-ObjC bindings and was + the first guy to figure out how to write Tivo apps in Python. Lately he's + been messing with Python on the PSP. He lives in Lawrence, Kansas. + + On IRC, Jacob goes by ``jacobkm``. + `Simon Willison`_ Simon is a well-respected Web developer from England. He had a one-year internship at World Online, during which time he and Adrian developed - Django from scratch. He's enthusiastic, he's passionate about best - practices in Web development, and he really likes squirrels. Probably to a - fault. He went back to university to finish his degree and is poised to - continue doing big, exciting things on the Web. He lives in England. + Django from scratch. The most enthusiastic Brit you'll ever meet, he's + passionate about best practices in Web development and has maintained a + well-read Web-development blog for years at http://simon.incutio.com. + He works for Yahoo UK, where he managed to score the title "Hacker Liason." + He lives in London. On IRC, Simon goes by ``SimonW``. -`Jacob Kaplan-Moss`_ - Jacob is a whipper-snapper from California who spends equal time coding and - cooking. He does Web development for World Online and actively hacks on - various cool side projects. He's contributed to the Python-ObjC bindings and - was the first guy to figure out how to write Tivo apps in Python. Lately - he's been messing with Python on the PSP. He lives in Lawrence, Kansas. - - On IRC, Jacob goes by ``jacobkm``. - `Wilson Miner`_ Wilson's design-fu makes us all look like rock stars. When not sneaking into apartment complex swimming pools, he's the Commercial Development @@ -106,18 +117,17 @@ Lawrence, Kansas, USA. Which sites use Django? ----------------------- -The Django wiki features a `list of Django-powered sites`_. Feel free to add -your Django-powered site to the list. +The Django wiki features a consistently growing `list of Django-powered sites`_. +Feel free to add your Django-powered site to the list. .. _list of Django-powered sites: http://code.djangoproject.com/wiki/DjangoPoweredSites Django appears to be a MVC framework, but you call the Controller the "view", and the View the "template". How come you don't use the standard names? ----------------------------------------------------------------------------------------------------------------------------------------------------- -That's because Django isn't strictly a MVC framework. We don't really believe in -any capital-M Methodologies; we do what "feels" right. If you squint the right -way, you can call Django's ORM the "Model", the view functions the "View", and -the dynamically-generated API the "Controller" -- but not really. +That's because Django isn't strictly a MVC framework. If you squint the right +way, you can call Django's database layer the "Model", the view functions the +"View", and the URL dispatcher the "Controller" -- but not really. In fact, you might say that Django is a "MTV" framework -- that is, Model, Template, and View make much more sense to us. @@ -183,9 +193,13 @@ begin maintaining backwards compatibility. This should happen in a couple of months or so, although it's entirely possible that it could happen earlier. That translates into summer 2006. +The merging of Django's `magic-removal branch`_ went a long way toward Django +1.0. + Of course, you should note that `quite a few production sites`_ use Django in its current status. Don't let the lack of a 1.0 turn you off. +.. _magic-removal branch: http://code.djangoproject.com/wiki/RemovingTheMagic .. _quite a few production sites: http://code.djangoproject.com/wiki/DjangoPoweredSites How can I download the Django documentation to read it offline? @@ -225,12 +239,12 @@ How do I get started? How do I fix the "install a later version of setuptools" error? --------------------------------------------------------------- -Just run the ``ex_setup.py`` script in the Django distribution. +Just run the ``ez_setup.py`` script in the Django distribution. What are Django's prerequisites? -------------------------------- -Django requires Python_ 2.3 or later. +Django requires Python_ 2.3 or later. No other Python libraries are required. For a development environment -- if you just want to experiment with Django -- you don't need to have a separate Web server installed; Django comes with its @@ -256,7 +270,7 @@ Not if you just want to play around and develop things on your local computer. Django comes with its own Web server, and things should Just Work. For production use, though, we recommend mod_python. The Django developers have -been running it on mod_python for about two years, and it's quite stable. +been running it on mod_python for more than two years, and it's quite stable. However, if you don't want to use mod_python, you can use a different server, as long as that server has WSGI_ hooks. See the `server arrangements wiki page`_. @@ -325,6 +339,14 @@ but we recognize that choosing a template language runs close to religion. There's nothing about Django that requires using the template language, so if you're attached to ZPT, Cheetah, or whatever, feel free to use those. +Do I have to use your model/database layer? +------------------------------------------- + +Nope. Just like the template system, the model/database layer is decoupled from +the rest of the framework. The one exception is: If you use a different +database library, you won't get to use Django's automatically-generated admin +site. That app is coupled to the Django database layer. + How do I use image and file fields? ----------------------------------- @@ -367,9 +389,8 @@ input. If you do care about deleting data, you'll have to execute the ``ALTER TABLE`` statements manually in your database. That's the way we've always done it, because dealing with data is a very sensitive operation that we've wanted to -avoid automating. That said, there's some work being done to add a -``django-admin.py updatedb`` command, which would output the necessary -``ALTER TABLE`` statements, if any. +avoid automating. That said, there's some work being done to add partially +automated database-upgrade functionality. Do Django models support multiple-column primary keys? ------------------------------------------------------ @@ -392,19 +413,19 @@ How can I see the raw SQL queries Django is running? Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do this:: - >>> from django.core.db import db - >>> db.queries + >>> from django.db import connection + >>> connection.queries [{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls', 'time': '0.002'}] -``db.queries`` is only available if ``DEBUG`` is ``True``. It's a list of -dictionaries in order of query execution. Each dictionary has the following:: +``connection.queries`` is only available if ``DEBUG`` is ``True``. It's a list +of dictionaries in order of query execution. Each dictionary has the following:: ``sql`` -- The raw SQL statement ``time`` -- How long the statement took to execute, in seconds. -``db.queries`` includes all SQL statements -- INSERTs, UPDATES, SELECTs, etc. -Each time your app hits the database, the query will be recorded. +``connection.queries`` includes all SQL statements -- INSERTs, UPDATES, +SELECTs, etc. Each time your app hits the database, the query will be recorded. Can I use Django with a pre-existing database? ---------------------------------------------- @@ -465,8 +486,8 @@ documentation. My "list_filter" contains a ManyToManyField, but the filter doesn't display. ---------------------------------------------------------------------------- -Django won't bother displaying the filter for a ManyToManyField if there are -fewer than two related objects. +Django won't bother displaying the filter for a ``ManyToManyField`` if there +are fewer than two related objects. For example, if your ``list_filter`` includes ``sites``, and there's only one site in your database, it won't display a "Site" filter. In that case, @@ -477,9 +498,9 @@ How can I customize the functionality of the admin interface? You've got several options. If you want to piggyback on top of an add/change form that Django automatically generates, you can attach arbitrary JavaScript -modules to the page via the model's ``admin.js`` parameter. That parameter is -a list of URLs, as strings, pointing to JavaScript modules that will be -included within the admin form via a <script> tag. +modules to the page via the model's ``class Admin`` ``js`` parameter. That +parameter is a list of URLs, as strings, pointing to JavaScript modules that +will be included within the admin form via a ``<script>`` tag. If you want more flexibility than simply tweaking the auto-generated forms, feel free to write custom views for the admin. The admin is powered by Django @@ -492,10 +513,23 @@ next question. The dynamically-generated admin site is ugly! How can I change it? ------------------------------------------------------------------ -We think it's very purty, but if you don't agree, you can modify the admin -site's presentation by editing the CSS stylesheet and/or associated image files. -The site is built using semantic HTML, so any changes you'd like to make should -be possible by editing the CSS stylesheet. We've got a `guide to the CSS used in -the admin`_ to get you started. +We like it, but if you don't agree, you can modify the admin site's +presentation by editing the CSS stylesheet and/or associated image files. The +site is built using semantic HTML and plenty of CSS hooks, so any changes you'd +like to make should be possible by editing the stylesheet. We've got a +`guide to the CSS used in the admin`_ to get you started. .. _`guide to the CSS used in the admin`: http://www.djangoproject.com/documentation/admin_css/ + +How do I create users without having to edit password hashes? +------------------------------------------------------------- + +We don't recommend you create users via the admin interface, because at the +moment it requires you to edit password hashes manually. (Passwords are hashed +using one-way hash algorithms for security; there's currently no Web interface +for changing passwords by entering the actual password rather than the hash.) + +To create a user, you'll have to use the Python API. See `creating users`_ for +full info. + +.. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users diff --git a/docs/flatpages.txt b/docs/flatpages.txt index 21416079e9..73b5653c6b 100644 --- a/docs/flatpages.txt +++ b/docs/flatpages.txt @@ -3,7 +3,8 @@ The flatpages app ================= Django comes with an optional "flatpages" application. It lets you store simple -"flat" HTML content in a database and handles the management for you. +"flat" HTML content in a database and handles the management for you via +Django's admin interface and a Python API. A flatpage is a simple object with a URL, title and content. Use it for one-off, special-case pages, such as "About" or "Privacy Policy" pages, that @@ -23,10 +24,10 @@ Installation To install the flatpages app, follow these steps: - 1. Add ``"django.contrib.flatpages"`` to your INSTALLED_APPS_ setting. - 2. Add ``"django.contrib.flatpages.middleware.FlatpageFallbackMiddleware"`` + 1. Add ``'django.contrib.flatpages'`` to your INSTALLED_APPS_ setting. + 2. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'`` to your MIDDLEWARE_CLASSES_ setting. - 3. Run the command ``django-admin.py install flatpages``. + 3. Run the command ``manage.py syncdb``. .. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps .. _MIDDLEWARE_CLASSES: http://www.djangoproject.com/documentation/settings/#middleware-classes @@ -34,10 +35,10 @@ To install the flatpages app, follow these steps: How it works ============ -``django-admin.py install flatpages`` creates two tables in your database: -``django_flatpages`` and ``django_flatpages_sites``. ``django_flatpages`` is a -simple lookup table that essentially maps a URL to a title and bunch of text -content. ``django_flatpages_sites`` associates a flatpage with a site. +``manage.py syncdb`` creates two tables in your database: ``django_flatpage`` +and ``django_flatpage_sites``. ``django_flatpage`` is a simple lookup table +that simply maps a URL to a title and bunch of text content. +``django_flatpage_sites`` associates a flatpage with a site. The ``FlatpageFallbackMiddleware`` does all of the work. Each time any Django application raises a 404 error, this middleware checks the flatpages database @@ -49,7 +50,7 @@ If it finds a match, it follows this algorithm: * If the flatpage has a custom template, it loads that template. Otherwise, it loads the template ``flatpages/default``. * It passes that template a single context variable, ``flatpage``, which is - the flatpage object. It uses DjangoContext_ in rendering the template. + the flatpage object. It uses RequestContext_ in rendering the template. If it doesn't find a match, the request continues to be processed as usual. @@ -63,7 +64,7 @@ resort. For more on middleware, read the `middleware docs`_. .. _SITE_ID: http://www.djangoproject.com/documentation/settings/#site-id -.. _DjangoContext: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext +.. _RequestContext: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext .. _middleware docs: http://www.djangoproject.com/documentation/middleware/ How to add, change and delete flatpages @@ -80,8 +81,8 @@ Via the Python API ------------------ Flatpages are represented by a standard `Django model`_, which lives in -`django/contrib/flatpages/models/flatpages.py`_. You can access flatpage -objects via the `Django database API`_. +`django/contrib/flatpages/models.py`_. You can access flatpage objects via the +`Django database API`_. .. _Django model: http://www.djangoproject.com/documentation/model_api/ .. _django/contrib/flatpages/models/flatpages.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/flatpages/models/flatpages.py @@ -90,17 +91,17 @@ objects via the `Django database API`_. Flatpage templates ================== -By default, flatpages are rendered via the template ``flatpages/default``, but -you can override that for a particular flatpage. +By default, flatpages are rendered via the template ``flatpages/default.html``, +but you can override that for a particular flatpage. -Creating the ``flatpages/default`` template is your responsibility; in your -template directory, just create a ``flatpages`` directory containing a file -``default.html``. +Creating the ``flatpages/default.html`` template is your responsibility; in +your template directory, just create a ``flatpages`` directory containing a +file ``default.html``. Flatpage templates are passed a single context variable, ``flatpage``, which is the flatpage object. -Here's a sample ``flatpages/default`` template:: +Here's a sample ``flatpages/default.html`` template:: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> diff --git a/docs/forms.txt b/docs/forms.txt index 5df942c15f..2f8a3106fc 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -9,10 +9,7 @@ code. It is, and this document explains how the framework works. .. admonition:: A note to the lazy If all you want to do is present forms for a user to create and/or - update a given object, don't read any further. Instead, click thyself - to the `generic views`_ documentation. The following exercises are - for those interested in how Django's form framework works and those - needing to do more than simple creation/updating. + update a given object, you may be able to use `generic views`_. We'll take a top-down approach to examining Django's form validation framework, because much of the time you won't need to use the lower-level APIs. Throughout @@ -32,13 +29,14 @@ this document, we'll be working with the following model, a "place" object:: state = meta.USStateField() zip_code = meta.CharField(maxlength=5, blank=True) place_type = meta.IntegerField(choices=PLACE_TYPES) - class META: - admin = meta.Admin() - def __repr__(self): + class Admin: + pass + + def __str__(self): return self.name -Defining the above class is enough to create an admin interface to a ``place``, +Defining the above class is enough to create an admin interface to a ``Place``, but what if you want to allow public users to submit places? Manipulators @@ -53,11 +51,11 @@ similar, but the former knows how to create new instances of the model, while the later modifies existing instances. Both types of classes are automatically created when you define a new class:: - >>> from django.models.places import places - >>> places.AddManipulator - <class django.models.places.PlaceManipulatorAdd at 0x4c1540> - >>> places.ChangeManipulator - <class django.models.places.PlaceManipulatorChange at 0x4c1630> + >>> from mysite.myapp.models import Place + >>> Place.AddManipulator + <class 'django.models.manipulators.AddManipulator'> + >>> Place.ChangeManipulator + <class 'django.models.manipulators.ChangeManipulator'> Using the ``AddManipulator`` ---------------------------- @@ -65,16 +63,15 @@ Using the ``AddManipulator`` We'll start with the ``AddManipulator``. Here's a very simple view that takes POSTed data from the browser and creates a new ``Place`` object:: - from django.core.exceptions import Http404 - from django.core.extensions import render_to_response - from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect - from django.models.places import places - from django.core import formfields + from django.shortcuts import render_to_response + from django.http import Http404, HttpResponse, HttpResponseRedirect + from django import forms + from mysite.myapp.models import Place def naive_create_place(request): """A naive approach to creating places; don't actually use this!""" # Create the AddManipulator. - manipulator = places.AddManipulator() + manipulator = Place.AddManipulator() # Make a copy of the POSTed data so that do_html2python can # modify it in place (request.POST is immutable). @@ -110,16 +107,17 @@ view with a form that submits to this flawed creation view:: """Simplistic place form view; don't actually use anything like this!""" # Create a FormWrapper object that the template can use. Ignore # the last two arguments to FormWrapper for now. - form = formfields.FormWrapper(places.AddManipulator(), {}, {}) - return render_to_response('places/naive_create_form', {'form': form}) + form = forms.FormWrapper(Place.AddManipulator(), {}, {}) + return render_to_response('places/naive_create_form.html', {'form': form}) (This view, as well as all the following ones, has the same imports as in the first example above.) -The ``formfields.FormWrapper`` object is a wrapper that templates can -easily deal with to create forms. Here's the ``naive_create_form`` template:: +The ``forms.FormWrapper`` object is a wrapper that templates can +easily deal with to create forms. Here's the ``naive_create_form.html`` +template:: - {% extends "base" %} + {% extends "base.html" %} {% block content %} <h1>Create a place:</h1> @@ -156,23 +154,23 @@ don't have any validation. Let's revise the validation issue by writing a new creation view that takes validation into account:: def create_place_with_validation(request): - manipulator = places.AddManipulator() + manipulator = Place.AddManipulator() new_data = request.POST.copy() # Check for validation errors errors = manipulator.get_validation_errors(new_data) if errors: - return render_to_response('places/errors', {'errors': errors}) + return render_to_response('places/errors.html', {'errors': errors}) else: - manipulator.do_html2python(request.POST) - new_place = manipulator.save(request.POST) + manipulator.do_html2python(new_data) + new_place = manipulator.save(new_data) return HttpResponse("Place created: %s" % new_place) In this new version, errors will be found -- ``manipulator.get_validation_errors`` handles all the validation for you -- and those errors can be nicely presented on an error page (templated, of course):: - {% extends "base" %} + {% extends "base.html" %} {% block content %} @@ -200,7 +198,7 @@ data is valid). An added bonus of this approach is that errors and the form will both be available on the same page, so errors with fields can be presented in context. -.. admonition:: Philosophy:: +.. admonition:: Philosophy: Finally, for the HTTP purists in the audience (and the authorship), this nicely matches the "true" meanings of HTTP GET and HTTP POST: GET fetches @@ -209,7 +207,7 @@ context. Below is the finished view:: def create_place(request): - manipulator = places.AddManipulator() + manipulator = Place.AddManipulator() if request.POST: # If data was POSTed, we're trying to create a new Place. @@ -233,18 +231,18 @@ Below is the finished view:: errors = new_data = {} # Create the FormWrapper, template, context, response. - form = formfields.FormWrapper(manipulator, new_data, errors) - return render_to_response('places/create_form', {'form': form}) + form = forms.FormWrapper(manipulator, new_data, errors) + return render_to_response('places/create_form.html', {'form': form}) and here's the ``create_form`` template:: - {% extends "base" %} + {% extends "base.html" %} {% block content %} <h1>Create a place:</h1> {% if form.has_errors %} - <h2>Please correct the following error{{ errors|pluralize }}:</h2> + <h2>Please correct the following error{{ form.error_dict|pluralize }}:</h2> {% endif %} <form method="post" action="."> @@ -289,7 +287,8 @@ The second argument is the error list retrieved from this gives each field an ``errors`` item (which is a list of error messages associated with the field) as well as a ``html_error_list`` item, which is a ``<ul>`` of error messages. The above template uses these error items to -display a simple error message next to each field. +display a simple error message next to each field. The error list is saved as +an ``error_dict`` attribute of the ``FormWrapper`` object. Using the ``ChangeManipulator`` ------------------------------- @@ -301,8 +300,8 @@ about editing an existing one? It's shockingly similar to creating a new one:: # Get the place in question from the database and create a # ChangeManipulator at the same time. try: - manipulator = places.ChangeManipulator(place_id) - except places.PlaceDoesNotExist: + manipulator = Place.ChangeManipulator(place_id) + except Place.DoesNotExist: raise Http404 # Grab the Place object in question for future use. @@ -322,8 +321,8 @@ about editing an existing one? It's shockingly similar to creating a new one:: # This makes sure the form accurate represents the fields of the place. new_data = place.__dict__ - form = formfields.FormWrapper(manipulator, new_data, errors) - return render_to_response('places/edit_form', {'form': form, 'place': place}) + form = forms.FormWrapper(manipulator, new_data, errors) + return render_to_response('places/edit_form.html', {'form': form, 'place': place}) The only real differences are: @@ -362,7 +361,7 @@ your own custom manipulators for handling custom forms. Custom manipulators are pretty simple. Here's a manipulator that you might use for a "contact" form on a website:: - from django.core import formfields + from django import forms urgency_choices = ( (1, "Extremely urgent"), @@ -371,18 +370,18 @@ for a "contact" form on a website:: (4, "Unimportant"), ) - class ContactManipulator(formfields.Manipulator): + class ContactManipulator(forms.Manipulator): def __init__(self): self.fields = ( - formfields.EmailField(field_name="from", is_required=True), - formfields.TextField(field_name="subject", length=30, maxlength=200, is_required=True), - formfields.SelectField(field_name="urgency", choices=urgency_choices), - formfields.LargeTextField(field_name="contents", is_required=True), + forms.EmailField(field_name="from", is_required=True), + forms.TextField(field_name="subject", length=30, maxlength=200, is_required=True), + forms.SelectField(field_name="urgency", choices=urgency_choices), + forms.LargeTextField(field_name="contents", is_required=True), ) A certain similarity to Django's models should be apparent. The only required method of a custom manipulator is ``__init__`` which must define the fields -present in the manipulator. See the ``django.core.formfields`` module for +present in the manipulator. See the ``django.forms`` module for all the form fields provided by Django. You use this custom manipulator exactly as you would use an auto-generated one. @@ -401,8 +400,8 @@ Here's a simple function that might drive the above form:: return HttpResponseRedirect("/contact/thankyou/") else: errors = new_data = {} - form = formfields.FormWrapper(manipulator, new_data, errors) - return render_to_response('contact_form', {'form': form}) + form = forms.FormWrapper(manipulator, new_data, errors) + return render_to_response('contact_form.html', {'form': form}) Validators ========== @@ -410,16 +409,17 @@ Validators One useful feature of manipulators is the automatic validation. Validation is done using a simple validation API: A validator is a callable that raises a ``ValidationError`` if there's something wrong with the data. -``django.core.validators`` defines a host of validator functions, but defining -your own couldn't be easier:: +``django.core.validators`` defines a host of validator functions (see below), +but defining your own couldn't be easier:: - from django.core import validators, formfields + from django.core import validators + from django import forms - class ContactManipulator(formfields.Manipulator): + class ContactManipulator(forms.Manipulator): def __init__(self): self.fields = ( # ... snip fields as above ... - formfields.EmailField(field_name="to", validator_list=[self.isValidToAddress]) + forms.EmailField(field_name="to", validator_list=[self.isValidToAddress]) ) def isValidToAddress(self, field_data, all_data): @@ -432,10 +432,153 @@ the field's ``validator_list``. The arguments to a validator function take a little explanation. ``field_data`` is the value of the field in question, and ``all_data`` is a dictionary of all -the data being validated. Note that at the point validators are called all -data will still be strings (as ``do_html2python`` hasn't been called yet). +the data being validated. + +.. admonition:: Note:: + + At the point validators are called all data will still be + strings (as ``do_html2python`` hasn't been called yet). Also, because consistency in user interfaces is important, we strongly urge you to put punctuation at the end of your validation messages. +Ready-made Validators +--------------------- + +Writing your own validator is not difficult, but there are some situations +that come up over and over again. Django comes with a number of validators +that can be used directly in your code. All of these functions and classes +reside in ``django/core/validators.py``. + +The following validators should all be self-explanatory. Each one provides a +check for the given property: + + * isAlphaNumeric + * isAlphaNumericURL + * isSlug + * isLowerCase + * isUpperCase + * isCommaSeparatedIntegerList + * isCommaSeparatedEmailList + * isValidIPAddress4 + * isNotEmpty + * isOnlyDigits + * isNotOnlyDigits + * isInteger + * isOnlyLetters + * isValidANSIDate + * isValidANSITime + * isValidEmail + * isValidImage + * isValidImageURL + * isValidPhone + * isValidQuicktimeVideoURL + * isValidURL + * isValidHTML + * isWellFormedXml + * isWellFormedXmlFragment + * isExistingURL + * isValidUSState + * hasNoProfanities + +There are also a group of validators that are slightly more flexible. For +these validators, you create a validator instance, passing in the parameters +described below. The returned object is a callable that can be used as a +validator. + +For example:: + + from django.core import validators + from django import forms + + power_validator = validators.IsAPowerOf(2) + + class InstallationManipulator(forms.Manipulator) + def __init__(self): + self.fields = ( + ... + forms.IntegerField(field_name = "size", validator_list=[power_validator]) + ) + +Here, ``validators.IsAPowerOf(...)`` returned something that could be used as +a validator (in this case, a check that a number was a power of 2). + +Each of the standard validators that take parameters have an optional final +argument (``error_message``) that is the message returned when validation +fails. If no message is passed in, a default message is used. + +``AlwaysMatchesOtherField`` + Takes a field name and the current field is valid if and only if its value + matches the contents of the other field. + +``ValidateIfOtherFieldEquals`` + Takes three parameters: ``other_field``, ``other_value`` and + ``validator_list``, in that order. If ``other_field`` has a value of + ``other_vaue``, then the validators in ``validator_list`` are all run + against the current field. + +``RequiredIfOtherFieldNotGiven`` + Takes the name of the other field and this field is only required if the + other field has no value. + +``RequiredIfOtherFieldsNotGiven`` + Similar to ``RequiredIfOtherFieldNotGiven``, except that it takes a list + of field names and if any one of the supplied fields does not have a value + provided, the field being validated is required. + +``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual`` + Each of these validator classes takes a field name and a value (in that + order). If the given field does (or does not have, in the latter case) the + given value, then the current field being validated is required. + + Note that because validators are called before any ``do_html2python()`` + functions, the value being compared against is a string. So + ``RequiredIfOtherFieldEquals('choice', '1')`` is correct, whilst + ``RequiredIfOtherFieldEquals('choice', 1)`` will never result in the + equality test succeeding. + +``IsLessThanOtherField`` + Takes a field name and validates that the current field being validated + has a value that is less than (or equal to) the other field's value. + Again, comparisons are done using strings, so be cautious about using + this function to compare data that should be treated as another type. The + string "123" is less than the string "2", for example. If you don't want + string comparison here, you will need to write your own validator. + +``IsAPowerOf`` + Takes an integer argument and when called as a validator, checks that the + field being validated is a power of the integer. + +``IsValidFloat`` + Takes a maximum number of digits and number of decimal places (in that + order) and validates whether the field is a float with less than the + maximum number of digits and decimal place. + +``MatchesRegularExpression`` + Takes a regular expression (a string) as a parameter and validates the + field value against it. + +``AnyValidator`` + Takes a list of validators as a parameter. At validation time, if the + field successfully validates against any one of the validators, it passes + validation. The validators are tested in the order specified in the + original list. + +``URLMimeTypeCheck`` + Used to validate URL fields. Takes a list of MIME types (such as + ``text/plain``) at creation time. At validation time, it verifies that the + field is indeed a URL and then tries to retrieve the content at the URL. + Validation succeeds if the content could be retrieved and it has a content + type from the list used to create the validator. + +``RelaxNGCompact`` + Used to validate an XML document against a Relax NG compact schema. Takes + a file path to the location of the schema and an optional root element + (which is wrapped around the XML fragment before validation, if supplied). + At validation time, the XML fragment is validated against the schema using + the executable specified in the ``JING_PATH`` setting (see the settings_ + document for more details). + .. _`generic views`: http://www.djangoproject.com/documentation/generic_views/ +.. _`models API`: http://www.djangoproject.com/documentation/model_api/ +.. _settings: http://www.djangoproject.com/documentation/settings/ diff --git a/docs/generic_views.txt b/docs/generic_views.txt index 3e6d2244d9..5d20f2e41b 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -1,11 +1,11 @@ -=================== -Using generic views -=================== +============= +Generic views +============= Writing Web applications can be monotonous, because we repeat certain patterns again and again. In Django, the most common of these patterns have been abstracted into "generic views" that let you quickly provide common views of -an object without actually needing to write any views. +an object without actually needing to write any Python code. Django's generic views contain the following: @@ -28,14 +28,14 @@ Django's generic views contain the following: All of these views are used by creating configuration dictionaries in your URLconf files and passing those dictionaries as the third member of the -URLconf tuple. For example, here's the URLconf for the simple weblog app that -drives the blog on djangoproject.com:: +URLconf tuple for a given pattern. For example, here's the URLconf for the +simple weblog app that drives the blog on djangoproject.com:: from django.conf.urls.defaults import * + from django_website.apps.blog.models import Entry info_dict = { - 'app_label': 'blog', - 'module_name': 'entries', + 'queryset': Entry.objects.all(), 'date_field': 'pub_date', } @@ -47,388 +47,902 @@ drives the blog on djangoproject.com:: (r'^/?$', 'archive_index', info_dict), ) -As you can see, this URLconf defines a few options in ``info_dict`` that tell -the generic view which model to use (``blog.entries`` in this case), as well as -some extra information. +As you can see, this URLconf defines a few options in ``info_dict``. +``'queryset'`` gives the generic view a ``QuerySet`` of objects to use (in this +case, all of the ``Entry`` objects) and tells the generic view which model is +being used. Documentation of each generic view follows, along with a list of all keyword arguments that a generic view expects. Remember that as in the example above, arguments may either come from the URL pattern (as ``month``, ``day``, ``year``, etc. do above) or from the additional-information dictionary (as for -``app_label``, ``module_name``, etc.). +``queryset``, ``date_field``, etc.). -Most of the generic views that follow require the ``app_label`` and -``module_name`` keys. These values are easiest to explain through example:: +Most generic views require the ``queryset`` key, which is a ``QuerySet`` +instance; see the `database API docs`_ for more information about ``Queryset`` +objects. - >>> from django.models.blog import entries - -In the above line, ``blog`` is the ``app_label`` (the name of the file that -holds all your model definitions) and ``entries`` is the ``module_name`` -(either a pluralized, lowercased version of the model class name, or the value -of the ``module_name`` option of your model). In the docs below, these keys -will not be repeated, but each generic view requires them. - -Using "simple" generic views -============================ +"Simple" generic views +====================== The ``django.views.generic.simple`` module contains simple views to handle a couple of common cases: rendering a template when no view logic is needed, -and issuing a redirect. These views are: +and issuing a redirect. + +``django.views.generic.simple.direct_to_template`` +-------------------------------------------------- + +**Description:** + +Renders a given template, passing it a ``{{ params }}`` template variable, +which is a dictionary of the parameters captured in the URL. + +**Required arguments:** + + * ``template``: The full name of a template to use. + +**Example:** + +Given the following URL patterns:: + + urlpatterns = patterns('django.views.generic.simple', + (r'^foo/$', 'direct_to_template', {'template': 'foo_index.html'}), + (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}), + ) + +... a request to ``/foo/`` would render the template ``foo_index.html``, and a +request to ``/foo/15/`` would render the ``foo_detail.html`` with a context +variable ``{{ params.id }}`` that is set to ``15``. + +``django.views.generic.simple.redirect_to`` +------------------------------------------- -``direct_to_template`` - Renders a given template, passing it a ``{{ params }}`` template variable, - which is a dictionary of the parameters captured in the URL. This requires - the ``template`` argument. +**Description:** - For example, given the following URL patterns:: +Redirects to a given URL. - urlpatterns = patterns('django.views.generic.simple', - (r'^foo/$', 'direct_to_template', {'template': 'foo_index'}), - (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail'}), - ) +The given URL may contain dictionary-style string formatting, which will be +interpolated against the parameters captured in the URL. - ... a request to ``/foo/`` would cause the ``foo_index`` template to be - rendered, and a request to ``/foo/15/`` would cause the ``foo_detail`` - template to be rendered with a context variable ``{{ params.id }}`` that is - set to ``15``. +If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410). -``redirect_to`` - Issue a redirect to a given URL. +**Required arguments:** - The given URL may contain dict-style string formatting, which will be - interpolated against the params in the URL. For example, to redirect from - ``/foo/<id>/`` to ``/bar/<id>/``, you could use the following urlpattern:: + * ``url``: The URL to redirect to, as a string. Or ``None`` to raise a 410 + (Gone) HTTP error. - urlpatterns = patterns('django.views.generic.simple', - ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url' : '/bar/%(id)s/'}), - ) +**Example:** - If the given URL is ``None``, an ``HttpResponseGone`` (410) will be issued. +This example redirects from ``/foo/<id>/`` to ``/bar/<id>/``:: -Using date-based generic views -============================== + urlpatterns = patterns('django.views.generic.simple', + ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}), + ) + +This example returns a 410 HTTP error for requests to ``/bar/``:: + + urlpatterns = patterns('django.views.generic.simple', + ('^bar/$', 'redirect_to', {'url': None}), + ) + +Date-based generic views +======================== Date-based generic views (in the module ``django.views.generic.date_based``) -feature six functions for dealing with date-based data. Besides ``app_label`` -and ``module_name``, all date-based generic views require that the -``date_field`` argument be passed to them. This is the name of the field that -stores the date the objects should key off of. +are views for displaying drilldown pages for date-based data. + +``django.views.generic.date_based.archive_index`` +------------------------------------------------- + +**Description:** + +A top-level index page showing the "latest" objects, by date. Objects with +a date in the *future* are not included. + +**Required arguments:** + + * ``queryset``: A ``QuerySet`` of objects for which the archive serves. + + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. + +**Optional arguments:** + + * ``num_latest``: The number of latest objects to send to the template + context. By default, it's 15. -Additionally, all date-based generic views have the following optional -arguments: + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). - ======================= ================================================== - Argument Description - ======================= ================================================== - ``template_name`` Overrides the default template name used for the - view. + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. - ``extra_lookup_kwargs`` A dictionary of extra lookup parameters (see - the `database API docs`_). + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. - ``extra_context`` A dictionary of extra data to put into the - template's context. + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``False``. - ``processors`` A tuple of processors to apply to the - ``DjangoContext`` of this view's template. See the - `DjangoContext docs`_ - ======================= ================================================== + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. -.. _database API docs: http://www.djangoproject.com/documentation/db_api/ -.. _DjangoContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext +**Template name:** -The date-based generic functions are: +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_archive.html`` by default, where: -``archive_index`` - A top-level index page showing the "latest" objects. + * ``<model_name>`` is your model's name in all lowercase. For a model + ``StaffMember``, that'd be ``staffmember``. - Takes the following optional arguments: + * ``<app_label>`` is the right-most part of the full Python path to + your model's app. For example, if your model lives in + ``apps/blog/models.py``, that'd be ``blog``. - ======================= ================================================= - Argument Description - ======================= ================================================= - ``num_latest`` The number of items to display on the page. - Defaults to 15. +**Template context:** - ``allow_empty`` If ``False`` and there are no objects to display, - the view will raise a 404 instead of displaying - an empty index page. ``False`` is default. - ======================= ================================================= +In addition to ``extra_context``, the template's context will be: - Uses the template ``app_label/module_name_archive`` by default. + * ``date_list``: A list of ``datetime.date`` objects representing all + years that have objects available according to ``queryset``. These are + ordered in reverse. This is equivalent to + ``queryset.dates(date_field, 'year')[::-1]``. + * ``latest``: The ``num_latest`` objects in the system, ordered descending + by ``date_field``. For example, if ``num_latest`` is ``10``, then + ``latest`` will be a list of the latest 10 objects in ``queryset``. - Has the following template context: +.. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext - ``date_list`` - List of years with objects - ``latest`` - Latest objects by date +``django.views.generic.date_based.archive_year`` +------------------------------------------------ -``archive_year`` - Yearly archive. Requires that the ``year`` argument be present in the URL - pattern. +**Description:** - **New in Django development version:** Takes an optional ``allow_empty`` - parameter, as ``archive_index``. +A yearly archive page showing all available months in a given year. Objects +with a date in the *future* are not displayed. - Uses the template ``app_label/module_name_archive_year`` by default. +**Required arguments:** - Has the following template context: + * ``year``: The four-digit year for which the archive serves. - ``date_list`` - List of months in the given year with objects - ``year`` - The given year (an integer) + * ``queryset``: A ``QuerySet`` of objects for which the archive serves. -``archive_month`` - Monthly archive. Requires that ``year`` and ``month`` arguments be given. - You can pass the additional option ``month_format`` if you'd like to change - the way months are specified in the URL. + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. - ``month_format`` is a format string in the same syntax accepted by Python's - ``time.strftime``. (See the `strftime docs`_.) It's set to ``"%b"`` by - default, which is a three-letter month abbreviation. To change it to use - numbers, use ``"%m"``. +**Optional arguments:** - **New in Django development version:** Takes an optional ``allow_empty`` - parameter, as ``archive_index``. + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). - **New in Django development version:** Takes an optional - ``template_object_name`` parameter, which designates the name of the - template variable to use. Default is ``'object'``. + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. - Uses the template ``app_label/module_name_archive_month`` by default. + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. - Has the following template context: + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``False``. - ``month`` - The given month (a datetime.date object) - ``next_month`` - **New in Django development version.** The first day of the next - month, or None if the next month is in the future (a datetime.date - object) - ``previous_month`` - **New in Django development version.** The first day of the - previous month (a datetime.date object) - ``object_list`` - List of objects published in the given month. - In the Django development version, you can change this variable - name from ``object_list`` by using the ``template_object_name`` - parameter. (See above.) For example, if ``template_object_name`` is - ``foo``, the variable will be ``foo_list``. + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. -``archive_day`` - Daily archive. Requires that ``year``, ``month``, and ``day`` arguments be - given. +**Template name:** - As in ``archive_month``, you can pass an optional ``month_format``. You can - also pass ``day_format``, which defaults to ``"%d"`` (day of the month as a - decimal number, 01-31). +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_archive_year.html`` by default. - **New in Django development version:** Takes an optional - ``template_object_name`` parameter, which designates the name of the - template variable to use. Default is ``'object'``. +**Template context:** - Uses the template ``app_label/module_name_archive_day`` by default. +In addition to ``extra_context``, the template's context will be: - Has the following template context: + * ``date_list``: A list of ``datetime.date`` objects representing all + months that have objects available in the given year, according to + ``queryset``, in ascending order. + * ``year``: The given year, as a four-character string. - ``object_list`` - List of objects published on the given day. - In the Django development version, you can change this variable - name from ``object_list`` by using the ``template_object_name`` - parameter. (See above.) For example, if ``template_object_name`` is - ``foo``, the variable will be ``foo_list``. - ``day`` - The given day (a datetime.datetime object) - ``previous_day`` - The previous day (a datetime.datetime object) - ``next_day`` - The next day (a datetime.datetime object), or None if the given - day is today +``django.views.generic.date_based.archive_month`` +------------------------------------------------- -``archive_today`` - List of objects for today. Exactly the same as ``archive_day``, except - the year/month/day arguments are not given, and today's date is used - instead. +**Description:** -``object_detail`` - Individual object page. Requires ``year``/``month``/``day`` arguments like - ``archive_day``. This function can be used with two types of URLs: either - ``/year/month/day/slug/`` or ``/year/month/day/object_id/``. +A monthly archive page showing all objects in a given month. Objects with a +date in the *future* are not displayed. - If you're using the slug-style URLs, you'll need to have a ``slug`` item in - your URLconf, and you'll need to pass a ``slug_field`` key in your info - dictionary to indicate the name of the slug field. +**Required arguments:** - If you're using the object_id-style URLs, you'll just need to give the URL - pattern an ``object_id`` field. + * ``year``: The four-digit year for which the archive serves (a string). - You can also pass the ``template_name_field`` argument to indicate that the - the object stores the name of its template in a field on the object itself. + * ``month``: The month for which the archive serves, formatted according to + the ``month_format`` argument. - As in ``archive_day``, ``object_detail`` takes optional ``month_format`` - and ``day_format`` parameters. + * ``queryset``: A ``QuerySet`` of objects for which the archive serves. - **New in Django development version:** Takes an optional - ``template_object_name`` parameter, which designates the name of the - template variable to use. Default is ``'object'``. + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. + +**Optional arguments:** + + * ``month_format``: A format string that regulates what format the + ``month`` parameter uses. This should be in the syntax accepted by + Python's ``time.strftime``. (See the `strftime docs`_.) It's set to + ``"%b"`` by default, which is a three-letter month abbreviation. To + change it to use numbers, use ``"%m"``. + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``False``. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. The + view will append ``'_list'`` to the value of this parameter in + determining the variable's name. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_archive_month.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``month``: A ``datetime.date`` object representing the given month. + + * ``next_month``: A ``datetime.date`` object representing the first day of + the next month. If the next month is in the future, this will be + ``None``. + + * ``previous_month``: A ``datetime.date`` object representing the first day + of the previous month. Unlike ``next_month``, this will never be + ``None``. + + * ``object_list``: A list of objects available for the given month. This + variable's name depends on the ``template_object_name`` parameter, which + is ``'object'`` by default. If ``template_object_name`` is ``'foo'``, + this variable's name will be ``foo_list``. .. _strftime docs: http://www.python.org/doc/current/lib/module-time.html#l2h-1941 -Using list/detail generic views -=============================== +``django.views.generic.date_based.archive_week`` +------------------------------------------------ + +**Description:** + +A weekly archive page showing all objects in a given week. Objects with a date +in the *future* are not displayed. + +**Required arguments:** + + * ``year``: The four-digit year for which the archive serves (a string). + + * ``week``: The week of the year for which the archive serves (a string). + Weeks start with Sunday. + + * ``queryset``: A ``QuerySet`` of objects for which the archive serves. + + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. + +**Optional arguments:** + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``True``. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. The + view will append ``'_list'`` to the value of this parameter in + determining the variable's name. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_archive_week.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``week``: A ``datetime.date`` object representing the first day of the + given week. + + * ``object_list``: A list of objects available for the given week. This + variable's name depends on the ``template_object_name`` parameter, which + is ``'object'`` by default. If ``template_object_name`` is ``'foo'``, + this variable's name will be ``foo_list``. + +``django.views.generic.date_based.archive_day`` +----------------------------------------------- + +**Description:** + +A day archive page showing all objects in a given day. Days in the future throw +a 404 error, regardless of whether any objects exist for future days. + +**Required arguments:** + + * ``year``: The four-digit year for which the archive serves (a string). + + * ``month``: The month for which the archive serves, formatted according to + the ``month_format`` argument. + + * ``day``: The day for which the archive serves, formatted according to the + ``day_format`` argument. + + * ``queryset``: A ``QuerySet`` of objects for which the archive serves. + + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the date-based archive should use to + determine the objects on the page. + +**Optional arguments:** + + * ``month_format``: A format string that regulates what format the + ``month`` parameter uses. This should be in the syntax accepted by + Python's ``time.strftime``. (See the `strftime docs`_.) It's set to + ``"%b"`` by default, which is a three-letter month abbreviation. To + change it to use numbers, use ``"%m"``. + + * ``day_format``: Like ``month_format``, but for the ``day`` parameter. + It defaults to ``"%d"`` (day of the month as a decimal number, 01-31). + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``False``. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. The + view will append ``'_list'`` to the value of this parameter in + determining the variable's name. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_archive_day.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``day``: A ``datetime.date`` object representing the given day. + + * ``next_day``: A ``datetime.date`` object representing the next day. If + the next day is in the future, this will be ``None``. + + * ``previous_day``: A ``datetime.date`` object representing the given day. + Unlike ``next_day``, this will never be ``None``. + + * ``object_list``: A list of objects available for the given day. This + variable's name depends on the ``template_object_name`` parameter, which + is ``'object'`` by default. If ``template_object_name`` is ``'foo'``, + this variable's name will be ``foo_list``. + +``django.views.generic.date_based.archive_today`` +------------------------------------------------- + +**Description:** + +A day archive page showing all objects for *today*. This is exactly the same as +``archive_day``, except the ``year``/``month``/``day`` arguments are not used, +and today's date is used instead. + +``django.views.generic.date_based.object_detail`` +------------------------------------------------- + +**Description:** + +A page representing an individual object. + +**Required arguments:** + + * ``year``: The object's four-digit year (a string). + + * ``month``: The object's month , formatted according to the + ``month_format`` argument. + + * ``day``: The object's day , formatted according to the ``day_format`` + argument. + + * ``queryset``: A ``QuerySet`` that contains the object. + + * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in + the ``QuerySet``'s model that the generic view should use to look up the + object according to ``year``, ``month`` and ``day``. + + * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required. + + If you provide ``object_id``, it should be the value of the primary-key + field for the object being displayed on this page. + + Otherwise, ``slug`` should be the slug of the given object, and + ``slug_field`` should be the name of the slug field in the ``QuerySet``'s + model. + +**Optional arguments:** + + * ``month_format``: A format string that regulates what format the + ``month`` parameter uses. This should be in the syntax accepted by + Python's ``time.strftime``. (See the `strftime docs`_.) It's set to + ``"%b"`` by default, which is a three-letter month abbreviation. To + change it to use numbers, use ``"%m"``. + + * ``day_format``: Like ``month_format``, but for the ``day`` parameter. + It defaults to ``"%d"`` (day of the month as a decimal number, 01-31). + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_name_field``: The name of a field on the object whose value is + the template name to use. This lets you store template names in the data. + In other words, if your object has a field ``'the_template'`` that + contains a string ``'foo.html'``, and you set ``template_name_field`` to + ``'the_template'``, then the generic view for this object will use the + template ``'foo.html'``. + + It's a bit of a brain-bender, but it's useful in some cases. + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_detail.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``object``: The object. This variable's name depends on the + ``template_object_name`` parameter, which is ``'object'`` by default. If + ``template_object_name`` is ``'foo'``, this variable's name will be + ``foo``. + +List/detail generic views +========================= The list-detail generic-view framework (in the ``django.views.generic.list_detail`` module) is similar to the date-based one, except the former simply has two views: a list of objects and an individual object page. -All these views take the same four optional arguments as the date-based ones --- and, clearly, they don't accept the ``date_field`` argument. +``django.views.generic.list_detail.object_list`` +------------------------------------------------ + +**Description:** + +A page representing a list of objects. + +**Required arguments:** + + * ``queryset``: A ``QuerySet`` that represents the objects. + +**Optional arguments:** + + * ``paginate_by``: An integer specifying how many objects should be + displayed per page. If this is given, the view will paginate objects with + ``paginate_by`` objects per page. The view will expect a ``page`` query + string (GET) parameter containing a zero-indexed page number. + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``allow_empty``: A boolean specifying whether to display the page if no + objects are available. If this is ``False`` and no objects are available, + the view will raise a 404 instead of displaying an empty page. By + default, this is ``False``. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. The + view will append ``'_list'`` to the value of this parameter in + determining the variable's name. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_list.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``object_list``: The list of objects. This variable's name depends on the + ``template_object_name`` parameter, which is ``'object'`` by default. If + ``template_object_name`` is ``'foo'``, this variable's name will be + ``foo_list``. + + * ``is_paginated``: A boolean representing whether the results are + paginated. Specifically, this is set to ``False`` if the number of + available objects is less than or equal to ``paginate_by``. + +If the results are paginated, the context will contain these extra variables: + + * ``results_per_page``: The number of objects per page. (Same as the + ``paginate_by`` parameter.) + + * ``has_next``: A boolean representing whether there's a next page. + + * ``has_previous``: A boolean representing whether there's a previous page. + + * ``page``: The current page number, as an integer. This is 1-based. + + * ``next``: The next page number, as an integer. If there's no next page, + this will still be an integer representing the theoretical next-page + number. This is 1-based. + + * ``previous``: The previous page number, as an integer. This is 1-based. + + * ``pages``: The total number of pages, as an integer. + + * ``hits``: The total number of objects across *all* pages, not just this + page. + +``django.views.generic.list_detail.object_detail`` +-------------------------------------------------- + +A page representing an individual object. + +**Description:** + +A page representing an individual object. + +**Required arguments:** + + * ``queryset``: A ``QuerySet`` that contains the object. + + * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required. + + If you provide ``object_id``, it should be the value of the primary-key + field for the object being displayed on this page. + + Otherwise, ``slug`` should be the slug of the given object, and + ``slug_field`` should be the name of the slug field in the ``QuerySet``'s + model. + +**Optional arguments:** -Individual views are: + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). -``object_list`` - List of objects. + * ``template_name_field``: The name of a field on the object whose value is + the template name to use. This lets you store template names in the data. + In other words, if your object has a field ``'the_template'`` that + contains a string ``'foo.html'``, and you set ``template_name_field`` to + ``'the_template'``, then the generic view for this object will use the + template ``'foo.html'``. - Takes the following optional arguments: + It's a bit of a brain-bender, but it's useful in some cases. - ======================== ================================================= - Argument Description - ======================== ================================================= - ``paginate_by`` If set to an integer, the view will paginate - objects with ``paginate_by`` objects per page. - The view will expect a ``page`` GET param with - the (zero-indexed) page number. + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. - ``allow_empty`` If ``False`` and there are no objects to display, - the view will raise a 404 instead of displaying - an empty index page. ``False`` is default. + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. - ``template_object_name`` **New in Django development version.** Designates - the name of the object template variable. Default - is ``'object'``. - ======================== ================================================= + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. - Uses the template ``app_label/module_name_list`` by default. + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. - Has the following template context: +**Template name:** - ``object_list`` - List of objects. In the Django development version, you can change - this variable name from ``object_list`` by using the - ``template_object_name`` parameter. (See above.) For example, if - ``template_object_name`` is ``foo``, the variable will be - ``foo_list``. - ``is_paginated`` - Are the results paginated? Either True or False +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_detail.html`` by default. - If the results are paginated, the context will have some extra variables: +**Template context:** - ``results_per_page`` - Number of objects per page - ``has_next`` - Is there a next page? - ``has_previous`` - Is there a previous page? - ``page`` - The current page number - ``next`` - The next page number - ``previous`` - The previous page - ``pages`` - Number of pages total - ``hits`` - Total number of objects +In addition to ``extra_context``, the template's context will be: -``object_detail`` - Object detail page. This works like and takes the same arguments as - the date-based ``object_detail`` above, except this one, obviously, - does not take the year/month/day arguments. + * ``object``: The object. This variable's name depends on the + ``template_object_name`` parameter, which is ``'object'`` by default. If + ``template_object_name`` is ``'foo'``, this variable's name will be + ``foo``. -Using create/update/delete generic views -======================================== +Create/update/delete generic views +================================== The ``django.views.generic.create_update`` module contains a set of functions -for creating, editing and deleting objects. These views take the same global -arguments as the above sets of generic views. They also have a -``login_required`` argument which, if ``True``, requires the user to be logged -in to have access to the page. (``login_required`` defaults to ``False``.) +for creating, editing and deleting objects. + +``django.views.generic.create_update.create_object`` +---------------------------------------------------- + +**Description:** + +A page that displays a form for creating an object, redisplaying the form with +validation errors (if there are any) and saving the object. This uses the +automatic manipulators that come with Django models. + +**Required arguments:** + + * ``model``: The Django model class of the object that the form will + create. + +**Optional arguments:** + + * ``post_save_redirect``: A URL to which the view will redirect after + saving the object. By default, it's ``object.get_absolute_url()``. + + ``post_save_redirect`` may contain dictionary string formatting, which + will be interpolated against the object's field attributes. For example, + you could use ``post_save_redirect="/polls/%(slug)s/"``. + + * ``login_required``: A boolean that designates whether a user must be + logged in, in order to see the page and save changes. This hooks into the + Django `authentication system`_. By default, this is ``False``. + + If this is ``True``, and a non-logged-in user attempts to visit this page + or save the form, Django will redirect the request to ``/accounts/login/``. + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_form.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``form``: A ``django.forms.FormWrapper`` instance representing the form + for editing the object. This lets you refer to form fields easily in the + template system. + + For example, if ``model`` has two fields, ``name`` and ``address``:: + + <form action="" method="post"> + <p><label for="id_name">Name:</label> {{ form.name }}</p> + <p><label for="id_address">Address:</label> {{ form.address }}</p> + </form> + + See the `manipulator and formfield documentation`_ for more information + about using ``FormWrapper`` objects in templates. + +.. _authentication system: http://www.djangoproject.com/documentation/authentication/ +.. _manipulator and formfield documentation: http://www.djangoproject.com/documentation/forms/ + +``django.views.generic.create_update.update_object`` +---------------------------------------------------- + +**Description:** + +A page that displays a form for editing an existing object, redisplaying the +form with validation errors (if there are any) and saving changes to the +object. This uses the automatic manipulators that come with Django models. + +**Required arguments:** + + * ``model``: The Django model class of the object that the form will + create. + + * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required. + + If you provide ``object_id``, it should be the value of the primary-key + field for the object being displayed on this page. + + Otherwise, ``slug`` should be the slug of the given object, and + ``slug_field`` should be the name of the slug field in the ``QuerySet``'s + model. + +**Optional arguments:** + + * ``post_save_redirect``: A URL to which the view will redirect after + saving the object. By default, it's ``object.get_absolute_url()``. + + ``post_save_redirect`` may contain dictionary string formatting, which + will be interpolated against the object's field attributes. For example, + you could use ``post_save_redirect="/polls/%(slug)s/"``. + + * ``login_required``: A boolean that designates whether a user must be + logged in, in order to see the page and save changes. This hooks into the + Django `authentication system`_. By default, this is ``False``. + + If this is ``True``, and a non-logged-in user attempts to visit this page + or save the form, Django will redirect the request to ``/accounts/login/``. + + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). + + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. + + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. + + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. + + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. + +**Template name:** + +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_form.html`` by default. + +**Template context:** + +In addition to ``extra_context``, the template's context will be: + + * ``form``: A ``django.forms.FormWrapper`` instance representing the form + for editing the object. This lets you refer to form fields easily in the + template system. + + For example, if ``model`` has two fields, ``name`` and ``address``:: + + <form action="" method="post"> + <p><label for="id_name">Name:</label> {{ form.name }}</p> + <p><label for="id_address">Address:</label> {{ form.address }}</p> + </form> + + See the `manipulator and formfield documentation`_ for more information + about using ``FormWrapper`` objects in templates. + + * ``object``: The original object being edited. This variable's name + depends on the ``template_object_name`` parameter, which is ``'object'`` + by default. If ``template_object_name`` is ``'foo'``, this variable's + name will be ``foo``. + +``django.views.generic.create_update.delete_object`` +---------------------------------------------------- + +**Description:** -The create/update/delete views are: +A view that displays a confirmation page and deletes an existing object. The +given object will only be deleted if the request method is ``POST``. If this +view is fetched via ``GET``, it will display a confirmation page that should +contain a form that POSTs to the same URL. -``create_object`` - Create a new object. Has an extra optional argument, ``post_save_redirect``, - which is a URL to which the view will redirect after saving the object. - It defaults to ``object.get_absolute_url()``. +**Required arguments:** - ``post_save_redirect`` may contain dictionary string formatting, which will - be interpolated against the object's field attributes. For example, you - could use ``post_save_redirect="/polls/%(slug)s/"``. + * ``model``: The Django model class of the object that the form will + create. - Uses the template ``app_label/module_name_form`` by default. This is the - same template as the ``update_object`` view below. Your template can tell - the difference by the presence or absence of ``{{ object }}`` in the - context. + * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required. - Has the following template context: + If you provide ``object_id``, it should be the value of the primary-key + field for the object being displayed on this page. - form - The form wrapper for the object + Otherwise, ``slug`` should be the slug of the given object, and + ``slug_field`` should be the name of the slug field in the ``QuerySet``'s + model. - .. admonition:: Note + * ``post_delete_redirect``: A URL to which the view will redirect after + deleting the object. - See the `manipulator and formfield documentation`_ for more information - about using form wrappers in templates. +**Optional arguments:** -.. _`manipulator and formfield documentation`: http://www.djangoproject.com/documentation/forms/ + * ``login_required``: A boolean that designates whether a user must be + logged in, in order to see the page and save changes. This hooks into the + Django `authentication system`_. By default, this is ``False``. -``update_object`` - Edit an existing object. Has the same extra slug/ID parameters as - ``list_detail.object_detail`` does (see above), and the same - ``post_save_redirect`` as ``create_object`` does. + If this is ``True``, and a non-logged-in user attempts to visit this page + or save the form, Django will redirect the request to ``/accounts/login/``. - **New in Django development version:** Takes an optional - ``template_object_name`` parameter, which designates the name of the - template variable to use. Default is ``'object'``. + * ``template_name``: The full name of a template to use in rendering the + page. This lets you override the default template name (see below). - Uses the template ``app_label/module_name_form`` by default. + * ``template_loader``: The template loader to use when loading the + template. By default, it's ``django.template.loader``. - Has the following template context: + * ``extra_context``: A dictionary of values to add to the template context. + If a value in the dictionary is callable, the generic view will call it + just before rendering the template. By default, this is an empty + dictionary. - form - The form wrapper for the object - object - The original object being edited. - In the Django development version, you can change this variable - name from ``object`` by using the ``template_object_name`` - parameter. (See above.) For example, if ``template_object_name`` is - ``foo``, the variable will be ``foo`` instead of ``object``. + * ``context_processors``: A list of template-context processors to apply to + the view's template. See the `RequestContext docs`_. -``delete_object`` - Delete an existing object. The given object will only actually be deleted - if the request method is POST. If this view is fetched with GET, it will - display a confirmation page that should contain a form that POSTs to the - same URL. + * ``template_object_name``: Designates the name of the template variable + to use in the template context. By default, this is ``'object'``. - You must provide the ``post_delete_redirect`` argument to this function, so - that the view knows where to go after the object is deleted. +**Template name:** - If fetched with GET, it uses the template - ``app_label/module_name_confirm_delete`` by default. It uses no template - if POSTed -- it simply deletes the object and redirects. +If ``template_name`` isn't specified, this view will use the template +``<app_label>/<model_name>_confirm_delete.html`` by default. - **New in Django development version:** Takes an optional - ``template_object_name`` parameter, which designates the name of the - template variable to use. Default is ``'object'``. +**Template context:** - Has the following template context: +In addition to ``extra_context``, the template's context will be: - object - The object about to be deleted - In the Django development version, you can change this variable - name from ``object`` by using the ``template_object_name`` - parameter. (See above.) For example, if ``template_object_name`` is - ``foo``, the variable will be ``foo`` instead of ``object``. + * ``object``: The original object that's about to be deleted. This + variable's name depends on the ``template_object_name`` parameter, which + is ``'object'`` by default. If ``template_object_name`` is ``'foo'``, + this variable's name will be ``foo``. diff --git a/docs/i18n.txt b/docs/i18n.txt index 4282b0aeea..9199a74295 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -150,14 +150,14 @@ If you don't like the verbose name ``gettext_lazy``, you can just alias it as Always use lazy translations in `Django models`_. And it's a good idea to add translations for the field names and table names, too. This means writing -explicit ``verbose_name`` and ``verbose_name_plural`` options in the ``META`` +explicit ``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class, though:: from django.utils.translation import gettext_lazy as _ class MyThing(meta.Model): name = meta.CharField(_('name'), help_text=_('This is the help text')) - class META: + class Meta: verbose_name = _('my thing') verbose_name_plural = _('mythings') @@ -224,14 +224,14 @@ To pluralize, specify both the singular and plural forms with the Internally, all block and inline translations use the appropriate ``gettext`` / ``ngettext`` call. -Each ``DjangoContext`` has access to two translation-specific variables: +Each ``RequestContext`` has access to two translation-specific variables: * ``LANGUAGES`` is a list of tuples in which the first element is the language code and the second is the language name (in that language). * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. Example: ``en-us``. (See "How language preference is discovered", below.) -If you don't use the ``DjangoContext`` extension, you can get those values with +If you don't use the ``RequestContext`` extension, you can get those values with two tags:: {% get_current_language as LANGUAGE_CODE %} @@ -404,7 +404,7 @@ should follow these guidelines: For example, your ``MIDDLEWARE_CLASSES`` might look like this:: MIDDLEWARE_CLASSES = ( - 'django.middleware.sessions.SessionMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', ) diff --git a/docs/install.txt b/docs/install.txt index 54b792464f..51746e001d 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -77,9 +77,9 @@ It's easy either way. Installing the official version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Download Django-0.91.tar.gz from our `download page`_. -2. ``tar xzvf Django-0.91.tar.gz`` -3. ``cd Django-0.91`` +1. Download Django-0.92.tar.gz from our `download page`_. +2. ``tar xzvf Django-0.92.tar.gz`` +3. ``cd Django-0.92`` 4. ``sudo python setup.py install`` Note that the last command will automatically download and install setuptools_ diff --git a/docs/legacy_databases.txt b/docs/legacy_databases.txt index f1b8f85970..66cb1a2ef4 100644 --- a/docs/legacy_databases.txt +++ b/docs/legacy_databases.txt @@ -18,6 +18,7 @@ You'll need to tell Django what your database connection parameters are, and what the name of the database is. Do that by editing these settings in your `settings file`_: + * `DATABASE_NAME` * `DATABASE_ENGINE`_ * `DATABASE_USER`_ * `DATABASE_PASSWORD`_ @@ -26,6 +27,7 @@ what the name of the database is. Do that by editing these settings in your * `DATABASE_PORT`_ .. _settings file: http://www.djangoproject.com/documentation/settings/ +.. _DATABASE_NAME: http://www.djangoproject.com/documentation/settings/#database-name .. _DATABASE_ENGINE: http://www.djangoproject.com/documentation/settings/#database-engine .. _DATABASE_USER: http://www.djangoproject.com/documentation/settings/#database-user .. _DATABASE_PASSWORD: http://www.djangoproject.com/documentation/settings/#database-password @@ -39,57 +41,29 @@ Auto-generate the models Django comes with a utility that can create models by introspecting an existing database. You can view the output by running this command:: - django-admin.py inspectdb [databasename] --settings=path.to.settings - -...where "[databasename]" is the name of your database. + django-admin.py inspectdb --settings=path.to.settings Save this as a file by using standard Unix output redirection:: - django-admin.py inspectdb [databasename] --settings=path.to.settings > appname.py + django-admin.py inspectdb --settings=path.to.settings > models.py This feature is meant as a shortcut, not as definitive model generation. See the `django-admin.py documentation`_ for more information. -Once you've cleaned up the model, put the module in the ``models`` directory of -your app, and add it to your ``INSTALLED_APPS`` setting. +Once you've cleaned up your models, name the file ``models.py`` and put it in +the Python package that holds your app. Then add the app to your +``INSTALLED_APPS`` setting. .. _django-admin.py documentation: http://www.djangoproject.com/documentation/django_admin/ Install the core Django tables ============================== -Next, run the ``django-admin.py init`` command to install Django's core tables -in your database:: +Next, run the ``manage.py syncdb`` command to install any extra needed database +records such as admin permissions and content types:: django-admin.py init --settings=path.to.settings -This won't work if your database already contains tables that have any of the -following names: - - * ``sites`` - * ``packages`` - * ``content_types`` - * ``core_sessions`` - * ``auth_permissions`` - * ``auth_groups`` - * ``auth_users`` - * ``auth_messages`` - * ``auth_groups_permissions`` - * ``auth_users_groups`` - * ``auth_users_user_permissions`` - -If that's the case, try renaming one of your tables to resolve naming -conflicts. Currently, there's no way of customizing the names of Django's -database tables without editing Django's source code itself. - -Install metadata about your app -=============================== - -Django has a couple of database tables that contain metadata about your apps. -You'll need to execute the SQL output by this command:: - - django-admin.py sqlinitialdata [appname] --settings=path.to.settings - See whether it worked ===================== diff --git a/docs/middleware.txt b/docs/middleware.txt index b55d8a1696..1fec98a39f 100644 --- a/docs/middleware.txt +++ b/docs/middleware.txt @@ -24,6 +24,8 @@ name. For example, here's the default ``MIDDLEWARE_CLASSES`` created by MIDDLEWARE_CLASSES = ( "django.middleware.common.CommonMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", "django.middleware.doc.XViewMiddleware", ) @@ -95,13 +97,37 @@ Handles conditional GET operations. If the response has a ``ETag`` or Also removes the content from any response to a HEAD request and sets the ``Date`` and ``Content-Length`` response-headers. -django.middleware.sessions.SessionMiddleware --------------------------------------------- +django.contrib.sessions.middleware.SessionMiddleware +---------------------------------------------------- Enables session support. See the `session documentation`_. .. _`session documentation`: http://www.djangoproject.com/documentation/sessions/ +django.contrib.auth.middleware.AuthenticationMiddleware +------------------------------------------------------- + +Adds the ``user`` attribute, representing the currently-logged-in user, to +every incoming ``HttpRequest`` object. See `Authentication in Web requests`_. + +.. _Authentication in Web requests: http://www.djangoproject.com/documentation/authentication/#authentication-in-web-requests + +django.middleware.transaction.TransactionMiddleware +--------------------------------------------------- + +Binds commit and rollback to the request/response phase. If a view function runs +successfully, a commit is done. If it fails with an exception, a rollback is +done. + +The order of this middleware in the stack is important: middleware modules +running outside of it run with commit-on-save - the default Django behavior. +Middleware modules running inside it (coming later in the stack) will be under +the same transaction control as the view functions. + +See the `transaction management documentation`_. + +.. _`transaction management documentation`: http://www.djangoproject.com/documentation/transaction/ + Writing your own middleware =========================== @@ -176,8 +202,8 @@ Guidelines to it. * Feel free to look at Django's available middleware for examples. The - default Django middleware classes are in ``django/middleware/`` in the - Django distribution. + core Django middleware classes are in ``django/middleware/`` in the + Django distribution. The session middleware is in ``django/contrib/sessions``. * If you write a middleware component that you think would be useful to other people, contribute to the community! Let us know, and we'll diff --git a/docs/model-api.txt b/docs/model-api.txt index 5d61d5ba7e..44253f301b 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -8,465 +8,617 @@ model maps to a single database table. The basics: - * Each model is a Python class that subclasses ``django.core.meta.Model``. + * Each model is a Python class that subclasses ``django.db.models.Model``. * Each attribute of the model represents a database field. - * Model metadata (non-field information) goes in an inner class named ``META``. + * Model metadata (non-field information) goes in an inner class named + ``Meta``. + * Metadata used for Django's admin site goes into an inner class named + ``Admin``. + * With all of this, Django gives you an automatically-generated + database-access API, which is explained in the `Database API reference`_. A companion to this document is the `official repository of model examples`_. -.. _`official repository of model examples`: http://www.djangoproject.com/documentation/models/ +.. _Database API reference: http://www.djangoproject.com/documentation/db_api/ +.. _official repository of model examples: http://www.djangoproject.com/documentation/models/ -Field objects +Quick example ============= -The most important part of a model is the list of database fields it defines. -Fields are defined by class attributes. Each class attribute in a model, aside -from the optional inner ``class META``, should be an instance of a -``meta.Field`` subclass. +This example model defines a ``Person``, which has a ``first_name`` and +``last_name``:: -In this example, there are two fields, ``first_name`` and ``last_name`` :: + from django.db import models - class Person(meta.Model): - first_name = meta.CharField(maxlength=30) - last_name = meta.CharField(maxlength=30) + class Person(models.Model): + first_name = models.CharField(maxlength=30) + last_name = models.CharField(maxlength=30) -Django will use ``first_name`` and ``last_name`` as the database column names. +``first_name`` and ``last_name`` are *fields* of the model. Each field is +specified as a class attribute, and each attribute maps to a database column. -Each field type, except for ``ForeignKey``, ``ManyToManyField`` and -``OneToOneField``, takes an optional first positional argument -- a -human-readable name. If the human-readable name isn't given, Django will -automatically create the human-readable name by using the machine-readable -name, converting underscores to spaces. +The above ``Person`` model would create an SQL table like this:: -In this example, the human-readable name is ``"Person's first name"``:: + CREATE TABLE myapp_person ( + "id" serial NOT NULL PRIMARY KEY, + "first_name" varchar(30) NOT NULL, + "last_name" varchar(30) NOT NULL + ); - first_name = meta.CharField("Person's first name", maxlength=30) +Three technical notes: -In this example, the human-readable name is ``"first name"``:: + * The name of the table, ``myapp_person``, is automatically derived from + some model metadata but can be overridden. See _`Table names` below. + * An ``id`` field is added automatically, but this behavior can be + overriden. See _`Automatic primary key fields` below. + * The ``CREATE TABLE`` SQL in this example is formatted using PostgreSQL + syntax, but it's worth noting Django uses SQL tailored to the database + backend specified in your `settings file`_. - first_name = meta.CharField(maxlength=30) +.. _settings file: http://www.djangoproject.com/documentation/settings/ -``ForeignKey``, ``ManyToManyField`` and ``OneToOneField`` require the first -argument to be a model class, so use the ``verbose_name`` keyword argument to -specify the human-readable name:: +Fields +====== - poll = meta.ForeignKey(Poll, verbose_name="the related poll") - sites = meta.ManyToManyField(Site, verbose_name="list of sites") - place = meta.OneToOneField(Place, verbose_name="related place") +The most important part of a model -- and the only required part of a model -- +is the list of database fields it defines. Fields are specified by class +attributes. -Convention is not to capitalize the first letter of the ``verbose_name``. -Django will automatically capitalize the first letter where it needs to. +Example:: -General field options ---------------------- + class Musician(models.Model): + first_name = models.CharField(maxlength=50) + last_name = models.CharField(maxlength=50) + instrument = models.CharField(maxlength=100) -The following arguments are available to all field types. All are optional. + class Album(models.Model): + artist = models.ForeignKey(Musician) + name = models.CharField(maxlength=100) + release_date = models.DateField() + num_stars = models.IntegerField() -``null`` - If ``True``, Django will store empty values as ``NULL`` in the database. - Default is ``False``. +Field name restrictions +----------------------- - Note that empty string values will always get stored as empty strings, not - as ``NULL`` -- so use ``null=True`` for non-string fields such as integers, - booleans and dates. +Django places only two restrictions on model field names: - Avoid using ``null`` on string-based fields such as ``CharField`` and - ``TextField`` unless you have an excellent reason. If a string-based field - has ``null=True``, that means it has two possible values for "no data": - ``NULL``, and the empty string. In most cases, it's redundant to have two - possible values for "no data;" Django convention is to use the empty - string, not ``NULL``. + 1. A field name cannot be a Python reserved word, because that would result + in a Python syntax error. For example:: -``blank`` - If ``True``, the field is allowed to be blank. + class Example(models.Model): + pass = models.IntegerField() # 'pass' is a reserved word! - Note that this is different than ``null``. ``null`` is purely - database-related, whereas ``blank`` is validation-related. If a field has - ``blank=True``, validation on Django's admin site will allow entry of an - empty value. If a field has ``blank=False``, the field will be required. + 2. A field name cannot contain more than one underscore in a row, due to + the way Django's query lookup syntax works. For example:: -``choices`` - A list of 2-tuples to use as choices for this field. + class Example(models.Model): + foo__bar = models.IntegerField() 'foo__bar' has two underscores! - If this is given, Django's admin will use a select box instead of the - standard text field and will limit choices to the choices given. +These limitations can be worked around, though, because your field name doesn't +necessarily have to match your database column name. See `db_column`_ below. - A choices list looks like this:: +SQL reserved words, such as ``join``, ``where`` or ``select`, *are* allowed as +model field names, because Django escapes all database table names and column +names in every underlying SQL query. It uses the quoting syntax of your +particular database engine. - YEAR_IN_SCHOOL_CHOICES = ( - ('FR', 'Freshman'), - ('SO', 'Sophomore'), - ('JR', 'Junior'), - ('SR', 'Senior'), - ('GR', 'Graduate'), - ) +Field types +----------- - The first element in each tuple is the actual value to be stored. The - second element is the human-readable name for the option. +Each field in your model should be an instance of the appropriate ``Field`` +class. Django uses the field class types to determine a few things: - Define the choices list **outside** of your model class, not inside it. - For example, this is not valid:: + * The database column type (e.g. ``INTEGER``, ``VARCHAR``). + * The widget to use in Django's admin interface, if you care to use it + (e.g. ``<input type="text">``, ``<select>``). + * The minimal validation requirements, used in Django's admin and in + manipulators. - class Foo(meta.Model): - GENDER_CHOICES = ( - ('M', 'Male'), - ('F', 'Female'), - ) - gender = meta.CharField(maxlength=1, choices=GENDER_CHOICES) +Here are all available field types: - But this is valid:: +``AutoField`` +~~~~~~~~~~~~~ - GENDER_CHOICES = ( - ('M', 'Male'), - ('F', 'Female'), - ) - class Foo(meta.Model): - gender = meta.CharField(maxlength=1, choices=GENDER_CHOICES) +An ``IntegerField`` that automatically increments according to available IDs. +You usually won't need to use this directly; a primary key field will +automatically be added to your model if you don't specify otherwise. See +_`Automatic primary key fields`. -``core`` - For objects that are edited inline to a related object. +``BooleanField`` +~~~~~~~~~~~~~~~~ - In the Django admin, if all "core" fields in an inline-edited object are - cleared, the object will be deleted. +A true/false field. - It is an error to have an inline-editable relation without at least one - ``core=True`` field. +The admin represents this as a checkbox. -``db_column`` - The name of the database column to use for this field. If this isn't given, - Django will use the field's name. +``CharField`` +~~~~~~~~~~~~~ - If your database column name is an SQL reserved word, or contains - characters that aren't allowed in Python variable names -- notably, the - hyphen -- that's OK. Django quotes column and table names behind the - scenes. +A string field, for small- to large-sized strings. -``db_index`` - If ``True``, ``django-admin.py sqlindexes`` will output a ``CREATE INDEX`` - statement for this field. +For large amounts of text, use ``TextField``. -``default`` - The default value for the field. +The admin represents this as an ``<input type="text">`` (a single-line input). -``editable`` - If ``False``, the field will not be editable in the admin. Default is ``True``. +``CharField`` has an extra required argument, ``maxlength``, the maximum length +(in characters) of the field. The maxlength is enforced at the database level +and in Django's validation. -``help_text`` - Extra "help" text to be displayed under the field on the object's admin - form. It's useful for documentation even if your object doesn't have an - admin form. +``CommaSeparatedIntegerField`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``primary_key`` - If ``True``, this field is the primary key for the model. +A field of integers separated by commas. As in ``CharField``, the ``maxlength`` +argument is required. - If you don't specify ``primary_key=True`` for any fields in your model, - Django will automatically add this field:: +``DateField`` +~~~~~~~~~~~~~ - id = meta.AutoField('ID', primary_key=True) +A date field. Has a few extra optional arguments: - Thus, you don't need to set ``primary_key=True`` on any of your fields - unless you want to override the default primary-key behavior. + ====================== =================================================== + Argument Description + ====================== =================================================== + ``auto_now`` Automatically set the field to now every time the + object is saved. Useful for "last-modified" + timestamps. - ``primary_key=True`` implies ``blank=False``, ``null=False`` and - ``unique=True``. Only one primary key is allowed on an object. + ``auto_now_add`` Automatically set the field to now when the object + is first created. Useful for creation of + timestamps. + ====================== =================================================== -``radio_admin`` - By default, Django's admin uses a select-box interface (<select>) for - fields that are ``ForeignKey`` or have ``choices`` set. If ``radio_admin`` - is set to ``True``, Django will use a radio-button interface instead. +The admin represents this as an ``<input type="text">`` with a JavaScript +calendar and a shortcut for "Today." - Don't use this for a field unless it's a ``ForeignKey`` or has ``choices`` - set. +``DateTimeField`` +~~~~~~~~~~~~~~~~~ -``unique`` - If ``True``, this field must be unique throughout the table. +A date and time field. Takes the same extra options as ``DateField``. - This is enforced at the database level and at the Django admin-form level. +The admin represents this as two ``<input type="text">`` fields, with +JavaScript shortcuts. -``unique_for_date`` - Set this to the name of a ``DateField`` or ``DateTimeField`` to require - that this field be unique for the value of the date field. +``EmailField`` +~~~~~~~~~~~~~~ - For example, if you have a field ``title`` that has - ``unique_for_date="pub_date"``, then Django wouldn't allow the entry of - two records with the same ``title`` and ``pub_date``. +A ``CharField`` that checks that the value is a valid e-mail address. +This doesn't accept ``maxlength``. - This is enforced at the Django admin-form level but not at the database level. +``FileField`` +~~~~~~~~~~~~~ -``unique_for_month`` - Like ``unique_for_date``, but requires the field to be unique with respect - to the month. +A file-upload field. -``unique_for_year`` - Like ``unique_for_date`` and ``unique_for_month``. +Has an extra required argument, ``upload_to``, a local filesystem path to +which files should be upload. This path may contain `strftime formatting`_, +which will be replaced by the date/time of the file upload (so that +uploaded files don't fill up the given directory). -``validator_list`` - A list of extra validators to apply to the field. Each should be a callable - that takes the parameters ``field_data, all_data`` and raises - ``django.core.validators.ValidationError`` for errors. (See the - `validator docs`_.) +The admin represents this as an ``<input type="file">`` (a file-upload widget). - Django comes with quite a few validators. They're in ``django.core.validators``. +Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few +steps: -.. _validator docs: http://www.djangoproject.com/documentation/forms/#validators + 1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the + full path to a directory where you'd like Django to store uploaded + files. (For performance, these files are not stored in the database.) + Define ``MEDIA_URL`` as the base public URL of that directory. Make + sure that this directory is writable by the Web server's user + account. -Field types ------------ + 2. Add the ``FileField`` or ``ImageField`` to your model, making sure + to define the ``upload_to`` option to tell Django to which + subdirectory of ``MEDIA_ROOT`` it should upload files. -Each field in your model should be an instance of the appropriate ``Field`` -class. Django uses the field class types to determine a few things: + 3. All that will be stored in your database is a path to the file + (relative to ``MEDIA_ROOT``). You'll must likely want to use the + convenience ``get_<fieldname>_url`` function provided by Django. For + example, if your ``ImageField`` is called ``mug_shot``, you can get + the absolute URL to your image in a template with ``{{ + object.get_mug_shot_url }}``. - * The database column type (e.g. ``INTEGER``, ``VARCHAR``). - * The widget to use in Django's admin (e.g. ``<input type="text">``, ``<select>``). - * The minimal validation requirements, used in Django's admin and in manipulators. +.. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 -Here are all available field types: +``FilePathField`` +~~~~~~~~~~~~~~~~~ -``AutoField`` - An ``IntegerField`` that automatically increments according to available - IDs. You usually won't need to use this directly; a primary key field will - automatically be added to your model if you don't specify otherwise. (See - ``primary_key`` in ``General field options`` above.) +A field whose choices are limited to the filenames in a certain directory +on the filesystem. Has three special arguments, of which the first is +required: -``BooleanField`` - A true/false field. + ====================== =================================================== + Argument Description + ====================== =================================================== + ``path`` Required. The absolute filesystem path to a + directory from which this ``FilePathField`` should + get its choices. Example: ``"/home/images"``. - The admin represents this as a checkbox. + ``match`` Optional. A regular expression, as a string, that + ``FilePathField`` will use to filter filenames. + Note that the regex will be applied to the + base filename, not the full path. Example: + ``"foo.*\.txt^"``, which will match a file called + ``foo23.txt`` but not ``bar.txt`` or ``foo23.gif``. -``CharField`` - A string field, for small- to large-sized strings. + ``recursive`` Optional. Either ``True`` or ``False``. Default is + ``False``. Specifies whether all subdirectories of + ``path`` should be included. + ====================== =================================================== - For large amounts of text, use ``TextField``. +Of course, these arguments can be used together. - The admin represents this as an ``<input type="text">`` (a single-line input). +The one potential gotcha is that ``match`` applies to the base filename, +not the full path. So, this example:: - ``CharField`` has an extra required argument, ``maxlength``, the maximum - length (in characters) of the field. The maxlength is enforced at the - database level and in Django's validation. + FilePathField(path="/home/images", match="foo.*", recursive=True) -``CommaSeparatedIntegerField`` - A field of integers separated by commas. As in ``CharField``, the - ``maxlength`` argument is required. +...will match ``/home/images/foo.gif`` but not ``/home/images/foo/bar.gif`` +because the ``match`` applies to the base filename (``foo.gif`` and +``bar.gif``). -``DateField`` - A date field. Has a few extra optional arguments: +``FloatField`` +~~~~~~~~~~~~~~ - ====================== =================================================== - Argument Description - ====================== =================================================== - ``auto_now`` Automatically set the field to now every time the - object is saved. Useful for "last-modified" - timestamps. +A floating-point number. Has two **required** arguments: - ``auto_now_add`` Automatically set the field to now when the object - is first created. Useful for creation of - timestamps. - ====================== =================================================== + ====================== =================================================== + Argument Description + ====================== =================================================== + ``max_digits`` The maximum number of digits allowed in the number. - The admin represents this as an ``<input type="text">`` with a JavaScript - calendar and a shortcut for "Today." + ``decimal_places`` The number of decimal places to store with the + number. + ====================== =================================================== -``DateTimeField`` - A date and time field. Takes the same extra options as ``DateField``. +For example, to store numbers up to 999 with a resolution of 2 decimal places, +you'd use:: - The admin represents this as two ``<input type="text">`` fields, with - JavaScript shortcuts. + models.FloatField(..., max_digits=5, decimal_places=2) -``EmailField`` - A ``CharField`` that checks that the value is a valid e-mail address. - This doesn't accept ``maxlength``. +And to store numbers up to approximately one billion with a resolution of 10 +decimal places:: -``FileField`` - A file-upload field. + models.FloatField(..., max_digits=19, decimal_places=10) - Has an extra required argument, ``upload_to``, a local filesystem path to - which files should be upload. This path may contain `strftime formatting`_, - which will be replaced by the date/time of the file upload (so that - uploaded files don't fill up the given directory). +The admin represents this as an ``<input type="text">`` (a single-line input). - The admin represents this as an ``<input type="file">`` (a file-upload widget). +``ImageField`` +~~~~~~~~~~~~~~ - Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few - steps: +Like ``FileField``, but validates that the uploaded object is a valid +image. Has two extra optional arguments, ``height_field`` and +``width_field``, which, if set, will be auto-populated with the height and +width of the image each time a model instance is saved. - 1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the - full path to a directory where you'd like Django to store uploaded - files. (For performance, these files are not stored in the database.) - Define ``MEDIA_URL`` as the base public URL of that directory. Make - sure that this directory is writable by the Web server's user - account. +Requires the `Python Imaging Library`_. - 2. Add the ``FileField`` or ``ImageField`` to your model, making sure - to define the ``upload_to`` option to tell Django to which - subdirectory of ``MEDIA_ROOT`` it should upload files. +.. _Python Imaging Library: http://www.pythonware.com/products/pil/ - 3. All that will be stored in your database is a path to the file - (relative to ``MEDIA_ROOT``). You'll must likely want to use the - convenience ``get_<fieldname>_url`` function provided by Django. For - example, if your ``ImageField`` is called ``mug_shot``, you can get - the absolute URL to your image in a template with ``{{ - object.get_mug_shot_url }}``. +``IntegerField`` +~~~~~~~~~~~~~~~~ - .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 +An integer. -``FilePathField`` - A field whose choices are limited to the filenames in a certain directory - on the filesystem. Has three special arguments, of which the first is - required: +The admin represents this as an ``<input type="text">`` (a single-line input). - ====================== =================================================== - Argument Description - ====================== =================================================== - ``path`` Required. The absolute filesystem path to a - directory from which this ``FilePathField`` should - get its choices. Example: ``"/home/images"``. +``IPAddressField`` +~~~~~~~~~~~~~~~~~~ - ``match`` Optional. A regular expression, as a string, that - ``FilePathField`` will use to filter filenames. - Note that the regex will be applied to the - base filename, not the full path. Example: - ``"foo.*\.txt^"``, which will match a file called - ``foo23.txt`` but not ``bar.txt`` or ``foo23.gif``. +An IP address, in string format (i.e. "24.124.1.30"). - ``recursive`` Optional. Either ``True`` or ``False``. Default is - ``False``. Specifies whether all subdirectories of - ``path`` should be included. - ====================== =================================================== +The admin represents this as an ``<input type="text">`` (a single-line input). - Of course, these arguments can be used together. +``NullBooleanField`` +~~~~~~~~~~~~~~~~~~~~ - The one potential gotcha is that ``match`` applies to the base filename, - not the full path. So, this example:: +Like a ``BooleanField``, but allows ``NULL`` as one of the options. Use this +instead of a ``BooleanField`` with ``null=True``. - FilePathField(path="/home/images", match="foo.*", recursive=True) +The admin represents this as a ``<select>`` box with "Unknown", "Yes" and "No" choices. - ...will match ``/home/images/foo.gif`` but not ``/home/images/foo/bar.gif`` - because the ``match`` applies to the base filename (``foo.gif`` and - ``bar.gif``). +``PhoneNumberField`` +~~~~~~~~~~~~~~~~~~~~ -``FloatField`` - A floating-point number. Has two **required** arguments: +A ``CharField`` that checks that the value is a valid U.S.A.-style phone +number (in the format ``XXX-XXX-XXXX``). - ====================== =================================================== - Argument Description - ====================== =================================================== - ``max_digits`` The maximum number of digits allowed in the number. +``PositiveIntegerField`` +~~~~~~~~~~~~~~~~~~~~~~~~ - ``decimal_places`` The number of decimal places to store with the - number. - ====================== =================================================== +Like an ``IntegerField``, but must be positive. - For example, to store numbers up to 999 with a resolution of 2 decimal places, - you'd use:: +``PositiveSmallIntegerField`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - meta.FloatField(..., max_digits=5, decimal_places=2) +Like a ``PositiveIntegerField``, but only allows values under a certain +(database-dependent) point. - And to store numbers up to approximately one billion with a resolution of 10 - decimal places:: +``SlugField`` +~~~~~~~~~~~~~ - meta.FloatField(..., max_digits=19, decimal_places=10) +"Slug" is a newspaper term. A slug is a short label for something, +containing only letters, numbers, underscores or hyphens. They're generally +used in URLs. - The admin represents this as an ``<input type="text">`` (a single-line input). +In the Django development version, you can specify ``maxlength``. If +``maxlength`` is not specified, Django will use a default length of 50. In +previous Django versions, there's no way to override the length of 50. -``ImageField`` - Like ``FileField``, but validates that the uploaded object is a valid - image. Has two extra optional arguments, ``height_field`` and - ``width_field``, which, if set, will be auto-populated with the height and - width of the image each time a model instance is saved. +Implies ``db_index=True``. - Requires the `Python Imaging Library`_. +Accepts an extra option, ``prepopulate_from``, which is a list of fields +from which to auto-populate the slug, via JavaScript, in the object's admin +form:: - .. _Python Imaging Library: http://www.pythonware.com/products/pil/ + models.SlugField(prepopulate_from=("pre_name", "name")) -``IntegerField`` - An integer. +``prepopulate_from`` doesn't accept DateTimeFields. - The admin represents this as an ``<input type="text">`` (a single-line input). +The admin represents ``SlugField`` as an ``<input type="text">`` (a +single-line input). -``IPAddressField`` - An IP address, in string format (i.e. "24.124.1.30"). +``SmallIntegerField`` +~~~~~~~~~~~~~~~~~~~~~ - The admin represents this as an ``<input type="text">`` (a single-line input). +Like an ``IntegerField``, but only allows values under a certain +(database-dependent) point. -``NullBooleanField`` - Like a ``BooleanField``, but allows ``NULL`` as one of the options. Use this - instead of a ``BooleanField`` with ``null=True``. +``TextField`` +~~~~~~~~~~~~~ - The admin represents this as a ``<select>`` box with "Unknown", "Yes" and "No" choices. +A large text field. -``PhoneNumberField`` - A ``CharField`` that checks that the value is a valid U.S.A.-style phone - number (in the format ``XXX-XXX-XXXX``). +The admin represents this as a ``<textarea>`` (a multi-line input). -``PositiveIntegerField`` - Like an ``IntegerField``, but must be positive. +``TimeField`` +~~~~~~~~~~~~~ -``PositiveSmallIntegerField`` - Like a ``PositiveIntegerField``, but only allows values under a certain - (database-dependent) point. +A time. Accepts the same auto-population options as ``DateField`` and +``DateTimeField``. -``SlugField`` - "Slug" is a newspaper term. A slug is a short label for something, - containing only letters, numbers, underscores or hyphens. They're generally - used in URLs. +The admin represents this as an ``<input type="text">`` with some +JavaScript shortcuts. - In the Django development version, you can specify ``maxlength``. If - ``maxlength`` is not specified, Django will use a default length of 50. In - previous Django versions, there's no way to override the length of 50. +``URLField`` +~~~~~~~~~~~~ - Implies ``db_index=True``. +A field for a URL. If the ``verify_exists`` option is ``True`` (default), +the URL given will be checked for existence (i.e., the URL actually loads +and doesn't give a 404 response). - Accepts an extra option, ``prepopulate_from``, which is a list of fields - from which to auto-populate the slug, via JavaScript, in the object's admin - form:: +The admin represents this as an ``<input type="text">`` (a single-line input). - meta.SlugField(prepopulate_from=("pre_name", "name")) +``USStateField`` +~~~~~~~~~~~~~~~~ - ``prepopulate_from`` doesn't accept DateTimeFields. +A two-letter U.S. state abbreviation. - The admin represents ``SlugField`` as an ``<input type="text">`` (a - single-line input). +The admin represents this as an ``<input type="text">`` (a single-line input). -``SmallIntegerField`` - Like an ``IntegerField``, but only allows values under a certain - (database-dependent) point. +``XMLField`` +~~~~~~~~~~~~ -``TextField`` - A large text field. +A ``TextField`` that checks that the value is valid XML that matches a +given schema. Takes one required argument, ``schema_path``, which is the +filesystem path to a RelaxNG_ schema against which to validate the field. - The admin represents this as a ``<textarea>`` (a multi-line input). +.. _RelaxNG: http://www.relaxng.org/ -``TimeField`` - A time. Accepts the same auto-population options as ``DateField`` and - ``DateTimeField``. +Field options +------------- - The admin represents this as an ``<input type="text">`` with some - JavaScript shortcuts. +The following arguments are available to all field types. All are optional. -``URLField`` - A field for a URL. If the ``verify_exists`` option is ``True`` (default), - the URL given will be checked for existence (i.e., the URL actually loads - and doesn't give a 404 response). +``null`` +~~~~~~~~ - The admin represents this as an ``<input type="text">`` (a single-line input). +If ``True``, Django will store empty values as ``NULL`` in the database. +Default is ``False``. -``USStateField`` - A two-letter U.S. state abbreviation. +Note that empty string values will always get stored as empty strings, not +as ``NULL`` -- so use ``null=True`` for non-string fields such as integers, +booleans and dates. - The admin represents this as an ``<input type="text">`` (a single-line input). +Avoid using ``null`` on string-based fields such as ``CharField`` and +``TextField`` unless you have an excellent reason. If a string-based field +has ``null=True``, that means it has two possible values for "no data": +``NULL``, and the empty string. In most cases, it's redundant to have two +possible values for "no data;" Django convention is to use the empty +string, not ``NULL``. -``XMLField`` - A ``TextField`` that checks that the value is valid XML that matches a - given schema. Takes one required argument, ``schema_path``, which is the - filesystem path to a RelaxNG_ schema against which to validate the field. +``blank`` +~~~~~~~~~ + +If ``True``, the field is allowed to be blank. + +Note that this is different than ``null``. ``null`` is purely +database-related, whereas ``blank`` is validation-related. If a field has +``blank=True``, validation on Django's admin site will allow entry of an +empty value. If a field has ``blank=False``, the field will be required. + +``choices`` +~~~~~~~~~~~ + +A list of 2-tuples to use as choices for this field. + +If this is given, Django's admin will use a select box instead of the +standard text field and will limit choices to the choices given. - .. _RelaxNG: http://www.relaxng.org/ +A choices list looks like this:: + + YEAR_IN_SCHOOL_CHOICES = ( + ('FR', 'Freshman'), + ('SO', 'Sophomore'), + ('JR', 'Junior'), + ('SR', 'Senior'), + ('GR', 'Graduate'), + ) + +The first element in each tuple is the actual value to be stored. The +second element is the human-readable name for the option. + +The choices list can be defined either as part of your model class:: + + class Foo(models.Model): + GENDER_CHOICES = ( + ('M', 'Male'), + ('F', 'Female'), + ) + gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + +or outside your model class altogether:: + + GENDER_CHOICES = ( + ('M', 'Male'), + ('F', 'Female'), + ) + class Foo(models.Model): + gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + +``core`` +~~~~~~~~ + +For objects that are edited inline to a related object. + +In the Django admin, if all "core" fields in an inline-edited object are +cleared, the object will be deleted. + +It is an error to have an inline-editable relation without at least one +``core=True`` field. + +``db_column`` +~~~~~~~~~~~~~ + +The name of the database column to use for this field. If this isn't given, +Django will use the field's name. + +If your database column name is an SQL reserved word, or contains +characters that aren't allowed in Python variable names -- notably, the +hyphen -- that's OK. Django quotes column and table names behind the +scenes. + +``db_index`` +~~~~~~~~~~~~ + +If ``True``, ``django-admin.py sqlindexes`` will output a ``CREATE INDEX`` +statement for this field. + +``default`` +~~~~~~~~~~~ + +The default value for the field. + +``editable`` +~~~~~~~~~~~~ + +If ``False``, the field will not be editable in the admin. Default is ``True``. + +``help_text`` +~~~~~~~~~~~~~ + +Extra "help" text to be displayed under the field on the object's admin +form. It's useful for documentation even if your object doesn't have an +admin form. + +``primary_key`` +~~~~~~~~~~~~~~~ + +If ``True``, this field is the primary key for the model. + +If you don't specify ``primary_key=True`` for any fields in your model, +Django will automatically add this field:: + + id = models.AutoField('ID', primary_key=True) + +Thus, you don't need to set ``primary_key=True`` on any of your fields +unless you want to override the default primary-key behavior. + +``primary_key=True`` implies ``blank=False``, ``null=False`` and +``unique=True``. Only one primary key is allowed on an object. + +``radio_admin`` +~~~~~~~~~~~~~~~ + +By default, Django's admin uses a select-box interface (<select>) for +fields that are ``ForeignKey`` or have ``choices`` set. If ``radio_admin`` +is set to ``True``, Django will use a radio-button interface instead. + +Don't use this for a field unless it's a ``ForeignKey`` or has ``choices`` +set. + +``unique`` +~~~~~~~~~~ + +If ``True``, this field must be unique throughout the table. + +This is enforced at the database level and at the Django admin-form level. + +``unique_for_date`` +~~~~~~~~~~~~~~~~~~~ + +Set this to the name of a ``DateField`` or ``DateTimeField`` to require +that this field be unique for the value of the date field. + +For example, if you have a field ``title`` that has +``unique_for_date="pub_date"``, then Django wouldn't allow the entry of +two records with the same ``title`` and ``pub_date``. + +This is enforced at the Django admin-form level but not at the database level. + +``unique_for_month`` +~~~~~~~~~~~~~~~~~~~~ + +Like ``unique_for_date``, but requires the field to be unique with respect +to the month. + +``unique_for_year`` +~~~~~~~~~~~~~~~~~~~ + +Like ``unique_for_date`` and ``unique_for_month``. + +``validator_list`` +~~~~~~~~~~~~~~~~~~ + +A list of extra validators to apply to the field. Each should be a callable +that takes the parameters ``field_data, all_data`` and raises +``django.core.validators.ValidationError`` for errors. (See the +`validator docs`_.) + +Django comes with quite a few validators. They're in ``django.core.validators``. + +.. _validator docs: http://www.djangoproject.com/documentation/forms/#validators + +Verbose field names +------------------- + +Each field type, except for ``ForeignKey``, ``ManyToManyField`` and +``OneToOneField``, takes an optional first positional argument -- a +verbose name. If the verbose name isn't given, Django will automatically create +it using the field's attribute name, converting underscores to spaces. + +In this example, the verbose name is ``"Person's first name"``:: + + first_name = models.CharField("Person's first name", maxlength=30) + +In this example, the verbose name is ``"first name"``:: + + first_name = models.CharField(maxlength=30) + +``ForeignKey``, ``ManyToManyField`` and ``OneToOneField`` require the first +argument to be a model class, so use the ``verbose_name`` keyword argument:: + + poll = models.ForeignKey(Poll, verbose_name="the related poll") + sites = models.ManyToManyField(Site, verbose_name="list of sites") + place = models.OneToOneField(Place, verbose_name="related place") + +Convention is not to capitalize the first letter of the ``verbose_name``. +Django will automatically capitalize the first letter where it needs to. Relationships ------------- Clearly, the power of relational databases lies in relating tables to each -other. Django offers ways to define the most common types of database +other. Django offers ways to define the three most common types of database relationships: Many-to-one, many-to-many and one-to-one. Many-to-one relationships @@ -479,23 +631,34 @@ any other ``Field`` type: by including it as a class attribute of your model. related. For example, if a ``Place`` model is in a ``City`` -- that is, a ``City`` -contains multiple places but each ``Place`` is only in one ``City`` -- here's -how you'd represent that:: +contains multiple places but each ``Place`` is only in one ``City`` -- use the +following definitions:: - class City(meta.Model): + class City(models.Model): # ... - class Place(meta.Model): + class Place(models.Model): # ... - city = meta.ForeignKey(City) + city = models.ForeignKey(City) To create a recursive relationship -- an object that has a many-to-one -relationship with itself -- use ``meta.ForeignKey("self")``. +relationship with itself -- use ``models.ForeignKey('self')``. + +If you need to create a relationship on a model that has not yet been defined, +you can use the name of the model, rather than the model object itself:: + + class Place(models.Model): + # ... + city = models.ForeignKey("City") + + class City(models.Model): + # ... The name of a ``ForeignKey`` (``city`` in the example above) generally should -be the name of the model, singular. Behind the scenes, Django appends "_id" to -the field name to create its database column name. But your code should never -have to deal with the database column name, unless you write custom SQL. +be the name of the model, in singular form. Behind the scenes, Django appends +"_id" to the field name to create its database column name. However, your code +should never have to deal with the database column name, unless you write +custom SQL. See the `Many-to-one relationship model example`_ for a full example. @@ -510,7 +673,7 @@ relationship should work. All are optional: ``edit_inline`` If not ``False``, this related object is edited "inline" on the related object's page. This means that the object will not have its own admin - interface. Use either ``meta.TABULAR`` or ``meta.STACKED``, + interface. Use either ``models.TABULAR`` or ``models.STACKED``, which, respectively, designate whether the inline-editable objects are displayed as a table or as a "stack" of fieldsets. @@ -518,10 +681,10 @@ relationship should work. All are optional: ``limit_choices_to`` A dictionary of lookup arguments and values (see the `Database API reference`_) that limit the available admin choices for this object. Use this - with ``meta.LazyDate`` to limit choices of objects + with ``models.LazyDate`` to limit choices of objects by date. For example:: - limit_choices_to = {'pub_date__lte' : meta.LazyDate()} + limit_choices_to = {'pub_date__lte' : models.LazyDate()} only allows the choice of related objects with a ``pub_date`` before the current date/time to be @@ -565,20 +728,18 @@ relationship should work. All are optional: object back to this one. For example, when if ``Topping`` has this field:: - meta.ForeignKey(Pizza) + models.ForeignKey(Pizza) - the ``related_name`` will be "topping" (taken from + the ``related_name`` will be "topping_set" (taken from the class name), which will in turn give ``Pizza`` - the methods ``get_topping_list()`` and - ``get_topping_count()``. + a ``topping_set`` Object Set Descriptor. If you instead were to use:: - meta.ForeignKey(Pizza, related_name="munchie") + models.ForeignKey(Pizza, related_name="munchies") - then the methods would be called - ``get_munchie_list()``, ``get_munchie_count()``, - etc. + then the Object Set Descriptor on ``Topping`` would + be called ``munchies``. This is only really useful when you have a single object that relates to the same object more than @@ -587,12 +748,12 @@ relationship should work. All are optional: fields, to make sure that the ``Category`` objects have the correct methods, you'd use fields like:: - meta.ForeignKey(Category, related_name="primary_story") - meta.ForeignKey(Category, related_name="secondary_story") + models.ForeignKey(Category, related_name="primary_stories") + models.ForeignKey(Category, related_name="secondary_stories") - ...which would give the ``Category`` objects - methods named ``get_primary_story_list()`` and - ``get_secondary_story_list()``. + ...which would give ``Category`` objects two Object Set + descriptors - one called ``primary_stories`` and one + called ``secondary_stories``. ``to_field`` The field on the related object that the relation is to. By default, Django uses the primary key of @@ -615,15 +776,19 @@ For example, if a ``Pizza`` has multiple ``Topping`` objects -- that is, a ``Topping`` can be on multiple pizzas and each ``Pizza`` has multiple toppings -- here's how you'd represent that:: - class Topping(meta.Model): + class Topping(models.Model): # ... - class Pizza(meta.Model): + class Pizza(models.Model): # ... - toppings = meta.ManyToManyField(Topping) + toppings = models.ManyToManyField(Topping) -The name of a ``ManyToManyField`` (``toppings`` in the example above) generally -should be the name of the model, plural. +As with ``ForeignKey``, a relationship to self can be defined by using the +string ``"self"`` instead of the model name; references to as-yet undefined +models can be made by using a string containing the model name. + +The name of a ``ManyToManyField`` (``toppings`` in the example above) should +generally be a plural describing the set of related model objects. Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. @@ -654,7 +819,7 @@ the relationship should work. All are optional: ``filter_interface`` Use a nifty unobtrusive Javascript "filter" interface instead of the usability-challenged ``<select multiple>`` in the admin form for this object. The value should be - ``meta.HORIZONTAL`` or ``meta.VERTICAL`` (i.e. + ``models.HORIZONTAL`` or ``models.VERTICAL`` (i.e. should the interface be stacked horizontally or vertically). @@ -667,6 +832,24 @@ the relationship should work. All are optional: version of the class being linked to. Use the singular parameter to change this, which is if you want one model to have multiple ``ManyToMany`` relationships to another model. + + ``symmetrical`` Only used in the definition of ManyToManyFields on self. + Consider the following model: + + class Person(models.Model): + friends = models.ManyToManyField("self") + + When Django processes this model, it identifies that it has + a ManyToManyField on itself, and as a result, it doesn't add + a ``person_set`` attribute to the Person class. Instead, the + ManyToManyField is assumed to be symmetrical - that is, if + I am your friend, then you are my friend. + + If you do not want symmetry in ManyToMany relationships with + self, set ``symmetrical`` to False. This will force Django to + add the descriptor for the reverse relationship, allow + ManyToMany relationships to be non-symmetrical. + ======================= ============================================================ One-to-one relationships @@ -689,171 +872,178 @@ repeating yourself and replicating those fields in the ``Restaurant`` model, you could make ``Restaurant`` have a ``OneToOneField`` to ``Place`` (because a restaurant "is-a" place). -This ``OneToOneField`` will actually replace the primary key ``id`` field -(since one-to-one relations share the same primary key), and has a few -differences in the admin interface: - - * No ``Place`` selection interface is displayed on ``Restaurant`` pages. - There will be one (and only one) ``Restaurant`` for each ``Place``. +As with ``ForeignKey``, a relationship to self can be defined by using the +string ``"self"`` instead of the model name; references to as-yet undefined +models can be made by using a string containing the model name. - * On the ``Restaurant`` change list, every ``Place`` -- whether it has an - associated ``Restaurant`` or not -- will be displayed. Adding a - ``Restaurant`` to a ``Place`` just means filling out the required - ``Restaurant`` fields. +This ``OneToOneField`` will actually replace the primary key ``id`` field +(since one-to-one relations share the same primary key), and will be displayed +as a read-only field when you edit an object in the admin interface: See the `One-to-one relationship model example`_ for a full example. .. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/ -META options +Meta options ============ -Give your model metadata by using an inner ``"class META"``, like so:: +Give your model metadata by using an inner ``class Meta``, like so:: - class Foo(meta.Model): - bar = meta.CharField(maxlength=30) - # ... - class META: - admin = meta.Admin() - # ... + class Foo(models.Model): + bar = models.CharField(maxlength=30) -Model metadata is "anything that's not a field" -- ordering options, admin -options, etc. + class Meta: + # ... -Here's a list of all possible ``META`` options. No options are required. Adding -``class META`` to a model is completely optional. +Model metadata is "anything that's not a field", such as ordering options, etc. -``admin`` - A ``meta.Admin`` object; see `Admin options`_. If this field is given, the - object will have an admin interface. If it isn't given, the object won't - have one. +Here's a list of all possible ``Meta`` options. No options are required. Adding +``class Meta`` to a model is completely optional. ``db_table`` - The name of the database table to use for the module:: +------------ - db_table = "pizza_orders" +The name of the database table to use for the module:: - If this isn't given, Django will use ``app_label + '_' + module_name``. + db_table = "pizza_orders" - If your database table name is an SQL reserved word, or contains characters - that aren't allowed in Python variable names -- notably, the hyphen -- - that's OK. Django quotes column and table names behind the scenes. +If this isn't given, Django will use ``app_label + '_' + model_class_name``. -``exceptions`` - Names of extra exception subclasses to include in the generated module. - These exceptions are available from instance methods and from module-level - methods:: - - exceptions = ("DisgustingToppingsException", "BurntCrust") +If your database table name is an SQL reserved word, or contains characters +that aren't allowed in Python variable names -- notably, the hyphen -- +that's OK. Django quotes column and table names behind the scenes. ``get_latest_by`` - The name of a ``DateField`` or ``DateTimeField``. If given, the module will - have a ``get_latest()`` function that fetches the "latest" object according - to that field:: - - get_latest_by = "order_date" - - See `Getting the "latest" object`_ for a full example. - - .. _Getting the "latest" object: http://www.djangoproject.com/documentation/models/get_latest/ +----------------- -``module_constants`` - A dictionary of names/values to use as extra module-level constants:: +The name of a ``DateField`` or ``DateTimeField``. If given, the module will +have a ``get_latest()`` function that fetches the "latest" object according +to that field:: - module_constants = { - 'MEAT_TYPE_PEPPERONI' : 1, - 'MEAT_TYPE_SAUSAGE' : 2, - } + get_latest_by = "order_date" -``module_name`` - The name of the module:: +See `Getting the "latest" object`_ for a full example. - module_name = "pizza_orders" - - If this isn't given, Django will use a lowercased version of the class - name, plus ``"s"``. This "poor man's pluralization" is intentional: Any - other level of magic pluralization would get confusing. +.. _Getting the "latest" object: http://www.djangoproject.com/documentation/models/get_latest/ ``order_with_respect_to`` - Marks this object as "orderable" with respect to the given field. This is - almost always used with related objects to allow them to be ordered with - respect to a parent object. For example, if a ``PizzaToppping`` relates to - a ``Pizza`` object, you might use:: +------------------------- + +Marks this object as "orderable" with respect to the given field. This is +almost always used with related objects to allow them to be ordered with +respect to a parent object. For example, if a ``PizzaToppping`` relates to +a ``Pizza`` object, you might use:: - order_with_respect_to = 'pizza' + order_with_respect_to = 'pizza' - to allow the toppings to be ordered with respect to the associated pizza. +...to allow the toppings to be ordered with respect to the associated pizza. ``ordering`` - The default ordering for the object, for use by ``get_list`` and the admin:: +------------ + +The default ordering for the object, for use when obtaining lists of objects:: - ordering = ['-order_date'] + ordering = ['-order_date'] - This is a tuple or list of strings. Each string is a field name with an - optional "-" prefix, which indicates descending order. Fields without a - leading "-" will be ordered ascending. Use the string "?" to order randomly. +This is a tuple or list of strings. Each string is a field name with an +optional "-" prefix, which indicates descending order. Fields without a +leading "-" will be ordered ascending. Use the string "?" to order randomly. - For example, to order by a ``pub_date`` field ascending, use this:: +For example, to order by a ``pub_date`` field ascending, use this:: - ordering = ['pub_date'] + ordering = ['pub_date'] - To order by ``pub_date`` descending, use this:: +To order by ``pub_date`` descending, use this:: - ordering = ['-pub_date'] + ordering = ['-pub_date'] - To order by ``pub_date`` descending, then by ``author`` ascending, use this:: +To order by ``pub_date`` descending, then by ``author`` ascending, use this:: - ordering = ['-pub_date', 'author'] + ordering = ['-pub_date', 'author'] - See `Specifying ordering`_ for more examples. +See `Specifying ordering`_ for more examples. - Note that, regardless of how many fields are in ``ordering``, the admin - site uses only the first field. +Note that, regardless of how many fields are in ``ordering``, the admin +site uses only the first field. - .. _Specifying ordering: http://www.djangoproject.com/documentation/models/ordering/ +.. _Specifying ordering: http://www.djangoproject.com/documentation/models/ordering/ ``permissions`` - Extra permissions to enter into the permissions table when creating this - object. Add, delete and change permissions are automatically created for - each object that has ``admin`` set. This example specifies an extra - permission, ``can_deliver_pizzas``:: +--------------- - permissions = (("can_deliver_pizzas", "Can deliver pizzas"),) +Extra permissions to enter into the permissions table when creating this +object. Add, delete and change permissions are automatically created for +each object that has ``admin`` set. This example specifies an extra +permission, ``can_deliver_pizzas``:: - This is a list or tuple of 2-tuples in the format - ``(permission_code, human_readable_permission_name)``. + permissions = (("can_deliver_pizzas", "Can deliver pizzas"),) + +This is a list or tuple of 2-tuples in the format +``(permission_code, human_readable_permission_name)``. ``unique_together`` - Sets of field names that, taken together, must be unique:: +------------------- - unique_together = (("driver", "restaurant"),) +Sets of field names that, taken together, must be unique:: - This is a list of lists of fields that must be unique when considered - together. It's used in the Django admin and is enforced at the database - level (i.e., the appropriate ``UNIQUE`` statements are included in the - ``CREATE TABLE`` statement). + unique_together = (("driver", "restaurant"),) + +This is a list of lists of fields that must be unique when considered +together. It's used in the Django admin and is enforced at the database +level (i.e., the appropriate ``UNIQUE`` statements are included in the +``CREATE TABLE`` statement). ``verbose_name`` - A human-readable name for the object, singular:: +---------------- + +A human-readable name for the object, singular:: - verbose_name = "pizza" + verbose_name = "pizza" - If this isn't given, Django will use a munged version of the class name: - ``CamelCase`` becomes ``camel case``. +If this isn't given, Django will use a munged version of the class name: +``CamelCase`` becomes ``camel case``. ``verbose_name_plural`` - The plural name for the object:: +----------------------- + +The plural name for the object:: + + verbose_name_plural = "stories" - verbose_name_plural = "stories" +If this isn't given, Django will use ``verbose_name + "s"``. + + + +======================================== +THE REST OF THIS HAS NOT YET BEEN EDITED +======================================== + + + +Table names +=========== + +Automatic primary key fields +============================ - If this isn't given, Django will use ``verbose_name + "s"``. Admin options ============= -The ``admin`` field in the model tells Django how to construct the admin -interface for the object. The field is an instance of the ``meta.Admin`` -object, which takes the following parameters. All are optional. +If you want your model to be visible to the automatic Administration +system, your model must have an inner ``"class Admin"``, like so:: + + class Foo(models.Model): + bar = models.CharField(maxlength=30) + # ... + class Admin: + # ... + +The Admin class gives instructions to Django on how to display the Model +to the Administration system. + +Here's a list of all possible ``Admin`` options. No options are required. Adding +``class Admin`` to a model is completely optional. ``date_hierarchy`` To allow filtering of objects in the admin by date, set ``date_hierarchy`` @@ -885,24 +1075,31 @@ object, which takes the following parameters. All are optional. "click to expand" link. Fieldsets with the ``wide`` style will be given extra horizontal space. + ``description`` + Optional extra text to be displayed at the top of each fieldset, + underneath the heading of the fieldset. It is used verbatim, + so you can use any HTML and you must escape any special HTML + characters (such as ampersand) yourself. + For example (taken from the ``django.contrib.flatpages`` model):: - fields = ( - (None, { - 'fields': ('url', 'title', 'content', 'sites') - }), - ('Advanced options', { - 'classes': 'collapse', - 'fields' : ('enable_comments', 'registration_required', 'template_name') - }), - ), + class Admin: + ... + fields = ( + (None, { + 'fields': ('url', 'title', 'content', 'sites') + }), + ('Advanced options', { + 'classes': 'collapse', + 'fields' : ('enable_comments', 'registration_required', 'template_name') + }), + ) results in an admin that looks like: .. image:: http://media.djangoproject.com/img/doc/flatfiles_admin.png - If ``fields`` isn't given but a model does define ``admin`` as a - ``meta.Admin`` object, Django will default to displaying each field that + If ``fields`` isn't given Django will default to displaying each field that isn't an ``AutoField`` and has ``editable=True``, in a single fieldset, in the same order as the fields are defined in the model. @@ -931,9 +1128,9 @@ object, which takes the following parameters. All are optional. ``short_description`` function attribute, for use as the header for the field. - * Use the string ``"__repr__"`` to output the representation of the - object, according to your model's ``__repr__()`` function. If you - don't define ``list_display``, Django will use the ``__repr__`` by + * Use the string ``"__str__"`` to output the representation of the + object, according to your model's ``__str__()`` function. If you + don't define ``list_display``, Django will use the ``__str__`` by default. See the example below. @@ -945,8 +1142,10 @@ object, which takes the following parameters. All are optional. Here's an example of how ``list_display`` and ``list_filter`` work (taken from the ``auth.user`` model):: - list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff'), - list_filter = ('is_staff', 'is_superuser'), + class Admin: + #... + list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') + list_filter = ('is_staff', 'is_superuser') The above code results in an admin that looks like this: @@ -963,7 +1162,7 @@ object, which takes the following parameters. All are optional. if one of the ``list_display`` fields is a ``ForeignKey``. ``ordering`` - A list or tuple (see the `META options`_, above) that gives a + A list or tuple (see the `Meta options`_, above) that gives a different ordering for the admin change list. If this isn't given, the model's default ordering will be used. @@ -985,6 +1184,84 @@ object, which takes the following parameters. All are optional. obviously, be some kind of text field, such as ``CharField`` or ``TextField``. +Managers +======== + +The Manager is the interface through which database query operations +are provided to Django applications. At least one Manager exists for +every model in a Django application. + +By default, Django will add a Manager with the name of ``objects`` to +every Django model. However, if you wish to use ``objects`` as a field +name, or if you wish to use a name other than ``objects`` for the Manager, +you can rename the Manager on a per-model basis. To rename the Manager +for a given class, define a class attribute of type models.Manager() +on that model. For example:: + + from django.db import models + + class Person(models.Model): + #... + people = models.Manager() + +In this example, ``Person.objects.all()`` will generate an error, but +``Person.people.all()`` will provide a list of all ``Person`` objects. + +Managers can also be customized. This is achieved by extending the +base Manager class, and instantiating the new Manager on your model. +There are two reasons that you may want to customize a Manager: firstly, +to add utility methods to the Manager, and secondly, to modify the +initial Query Set provided by the Manager. + +To modify the initial Query Set provided by a Manager, override the +``get_query_set()`` method to return a Query Set with the properties +you require. For example:: + + class PersonManager(models.Manager): + # Add some custom behavior to the Manager + def move_house(self): + # Some logic to help a person move house + + # Modify the initial Query Set provided by the manager + def get_query_set(self): + return super(Manager, self).get_query_set().filter(name__startswith="Fred") + + class Person(models.Model): + #... + objects = PersonManager() + +In this example, ``Person.objects.all()`` will only return people whose name starts +with "Fred"; ``Person.objects.move_house()`` will also be available. + +If required, you can add multiple Managers to a model. Every Manager attribute +added to a model can be accessed and used as a manager. This is an easy way +to define common filters types for your models. For example, the model:: + + class MaleManager(models.Manager): + def get_query_set(self): + return super(Manager, self).get_query_set().filter(sex='M') + + class FemaleManager(models.Manager): + def get_query_set(self): + return super(Manager, self).get_query_set().filter(sex='F') + + class Person(models.Model): + #... + people = models.Manager() + men = MaleManager() + women = FemaleManager() + +... will allow end users to request ``Person.men.all()``, ``Person.women.all()``, +and ``Person.people.all()``, yielding predictable results. + +If you are going to install a customized Manager, be warned that the first +Manager that Django encounters in a model definition has special status. +Django interprets the first Manager defined in a class as the default Manager. +Certain operations use the default Manager to obtain lists of objects, so it +is generally a good idea for the first Manager to be relatively unfiltered. +In the last example, ``people`` is defined first - so the default Manager +will include everyone. + Model methods ============= @@ -992,11 +1269,11 @@ There are a number of methods you can define on model objects to control the object's behavior. First, any methods you define will be available as methods of object instances. For example:: - class Pizza(meta.Model): + class Pizza(models.Model): # ... def is_disgusting(self): - return "anchovies" in [topping.name for topping in self.get_topping_list()] + return "anchovies" in [topping.name for topping in self.toppings.all()] Now, every ``Pizza`` object will have a ``is_disgusting()`` method. @@ -1016,16 +1293,16 @@ See `Giving models custom methods`_ for a full example. A few object methods have special meaning: -``__repr__`` - Django uses ``repr(obj)`` in a number of places, most notably as the value +``__str__`` + Django uses ``str(obj)`` in a number of places, most notably as the value inserted into a template when it displays an object. Thus, you should always - return a nice, human-readable string for the object's ``__repr__``. + return a nice, human-readable string for the object's ``__str__``. - Although defining ``__repr__()`` isn't required, it's strongly encouraged. + Although defining ``__str__()`` isn't required, it's strongly encouraged. - See `Adding repr`_ for a full example. + See `Adding str`_ for a full example. - .. _Adding repr: http://www.djangoproject.com/documentation/models/repr/ + .. _Adding str: http://www.djangoproject.com/documentation/models/repr/ ``get_absolute_url`` Define a ``get_absolute_url`` method to tell Django how to calculate the @@ -1041,49 +1318,34 @@ A few object methods have special meaning: It's good practice to use ``get_absolute_url()`` in templates, instead of hard-coding your objects' URLs. -``_pre_save`` - This method is called just before an object is saved to the database. For - example, you can use it to calculate aggregate values from other fields - before the object is saved. - - See `Adding hooks before/after saving and deleting`_ for a full example. - - .. _Adding hooks before/after saving and deleting: http://www.djangoproject.com/documentation/models/save_delete_hooks/ - -``_post_save`` - This method is called just after the object is saved to the database. This - could be used to update other tables, update cached information, etc. - -``_pre_delete`` - Like ``_pre_save``, but for deletion. - -``_post_delete`` - Like ``_post_save``, but for deletion. - Module-level methods -------------------- -Since each data class effectively turns into a "magic" Python module under -``django.models``, there are times you'll want to write methods that live in -that module. Any model method that begins with "_module_" is turned into a -module-level function:: +If you want to add a method to the Model, rather than instances of the model, +you can use the Python ``staticmethod`` and ``classmethod`` operators. For +example:: - class Pizza(meta.Model): + class Pizza(models.Model): # ... - def _module_get_pizzas_to_deliver(): + def get_pizzas_to_deliver(): return get_list(delivered__exact=False) + get_pizzas_to_deliver = staticmethod(get_pizzas_to_deliver) + +Or, using Python 2.4 decorators:: + + # ... + @staticmethod + def get_pizzas_to_deliver(): + # ... This will make the top-level ``pizzas`` module have a ``get_pizzas_to_deliver()`` method:: - >>> from django.models.pizza_hut import pizzas - >>> pizzas.get_pizzas_to_deliver() + >>> from pizza_hut.models import Pizza + >>> Pizza.get_pizzas_to_deliver() [ ... ] -Note that the scope of these methods is modified to be the same as the module -scope. These methods do NOT have access to globals within your model's module. - Manipulator methods ------------------- @@ -1092,7 +1354,7 @@ that being with "_manipulator_". This is most useful for providing custom validators for certain fields, because manipulators automatically call any method that begins with "validate":: - class Pizza(meta.Model): + class Pizza(models.Model): # ... def _manipulator_validate_customer_id(self, field_data, all_data): @@ -1106,14 +1368,15 @@ Executing custom SQL -------------------- Feel free to write custom SQL statements in custom model methods and -module-level methods. Each custom method automatically has access to the -variable ``db``, which is the current database connection. To use it, call -``db.cursor()`` to get a cursor object. Then, call ``cursor.execute(sql, [params])`` +module-level methods. The object ``django.db.connection`` object represents +the current database connection. To use it, call ``connection.cursor()`` to +get a cursor object. Then, call ``cursor.execute(sql, [params])`` to execute the SQL and ``cursor.fetchone()`` or ``cursor.fetchall()`` to return the resulting rows. Example:: def my_custom_sql(self): - cursor = db.cursor() + from django.db import connection + cursor = connection.cursor() cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) row = cursor.fetchone() return row @@ -1122,11 +1385,12 @@ If your custom SQL statement alters the data in your database -- for example, via a ``DELETE`` or ``UPDATE`` -- you'll need to call ``db.commit()``. Example:: def my_custom_sql2(self): - cursor = db.cursor() + from django.db import connection + cursor = connection.cursor() cursor.execute("DELETE FROM bar WHERE baz = %s", [self.baz]) - db.commit() + connection.commit() -``db`` and ``cursor`` simply use the standard `Python DB-API`_. If you're not +``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If you're not familiar with the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters directly within the SQL. If you use this technique, the underlying database @@ -1138,83 +1402,34 @@ just the ``where``, ``tables`` and ``params`` arguments to the standard lookup API. See `Other lookup options`_. .. _Python DB-API: http://www.python.org/peps/pep-0249.html -.. _Other lookup options: http://www.djangoproject.com/documentation/db_api/#other-lookup-options +.. _Other lookup options: http://www.djangoproject.com/documentation/db_api/#extra-params-select-where-tables Using models ============ -Once you've defined a model, you'll need to "enable" it in Django. This section -explains how Django searches for available models. - -Save your models in a normal Python module. Put this module within a package -called "models", which should itself be a subpackage of some other package on -your Python path. The ``__init__.py`` in your ``models`` package should contain -an ``__all__`` variable that is set to a list of all model module names within -the ``models`` directory. - -If this sounds confusing, just use ``django-admin.py startapp`` -- it'll create -the proper directory structure and ``__init__.py`` files. (See the -`django-admin.py documentation`_ .) - -For example, if you save your models in a module called ``mymodels.py``, here's -a directory layout you might use:: - - myapp/ - __init__.py # Empty file - models/ - __init__.py # Contains "__all__ = ['mymodels']" - mymodels.py # Contains your models - -Then, you'll have to tell Django that the ``myapp`` application is installed. -Do this by editing your settings file and adding ``"myapp"`` to the -``INSTALLED_APPS`` tuple. - -Again, if this sounds confusing, use ``django-admin.py startapp`` to take care -of package creation for you. This documentation exists only to explain how -Django works. +Once you have created your model, you have to tell Django about your new application. +This is done by editing your settings file and adding the name of the module that +contains your models module to the ``INSTALLED_APPS`` tuple. -Once you've added your app to ``INSTALLED_APPS``, you can open a Python -interactive interpreter and play with your model:: +For example, if the models for your application are contained in the module +``project.myapp.models`` (the package structure that is created for an application +by the ``django-admin.py startapp`` script), ``INSTALLED_APPS`` should read, in part:: - >>> from django.models.mymodels import pizzas - >>> pizzas.get_list() - -Note that the import is from ``django.models``, not ``myapp.models``. Django -creates a "magic" module within ``django.models`` for every installed -application. Each of those magic modules has a dynamic API. See the -`database API reference`_ for full information on how to use this API. - -.. admonition:: Why is the INSTALLED_APPS setting necessary? - - Model relationships work both ways, and the dynamically-generated Django API - creates API lookups in both directions. Thus, for Django to figure out all - the other models related to a particular model, it has to know the complete - spectrum of installed apps. - -.. _`django-admin.py documentation`: http://www.djangoproject.com/documentation/django_admin/ -.. _`database API reference`: http://www.djangoproject.com/documentation/db_api/ + INSTALLED_APPS = ( + #... + project.myapp, + #... + ) Models across files =================== It's perfectly OK to relate a model to one from another module. To do this, -just import the model module at the top of your model module, like so:: +just import the model module at the top of your model module. Then, just +refer to the other model class wherever needed. For example:: - from django.models import core + from myproject.otherapp import Site -Make sure you're importing from ``django.models``, not directly from your model -module. - -Then, just refer to the other model class wherever needed. For example:: - - class MyModel(meta.Model): + class MyModel(models.Model): # ... - sites = meta.ManyToManyField(core.Site) - -Models in multiple files -======================== - -If you want to have multiple model modules in a ``"models"`` directory, make -sure you edit ``"models/__init__.py"`` and add the name of your model module -to the ``__all__`` variable. If your ``models`` package doesn't have your model -module in ``__all__``, Django won't see any of the models in that module. + sites = models.ManyToManyField(Site) diff --git a/docs/modpython.txt b/docs/modpython.txt index 447bd70573..2b57d0514c 100644 --- a/docs/modpython.txt +++ b/docs/modpython.txt @@ -31,11 +31,11 @@ Then edit your ``httpd.conf`` file and add the following:: <Location "/mysite/"> SetHandler python-program PythonHandler django.core.handlers.modpython - SetEnv DJANGO_SETTINGS_MODULE myproject.settings + SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonDebug On </Location> -...and replace ``myproject.settings`` with the Python path to your settings file. +...and replace ``mysite.settings`` with the Python path to your settings file. This tells Apache: "Use mod_python for any URL at or under '/mysite/', using the Django mod_python handler." It passes the value of ``DJANGO_SETTINGS_MODULE`` @@ -71,13 +71,13 @@ instance. Just use ``VirtualHost`` for that, like so:: <VirtualHost *> ServerName www.example.com # ... - SetEnv DJANGO_SETTINGS_MODULE myproject.settings + SetEnv DJANGO_SETTINGS_MODULE mysite.settings </VirtualHost> <VirtualHost *> ServerName www2.example.com # ... - SetEnv DJANGO_SETTINGS_MODULE myproject.other_settings + SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings </VirtualHost> If you need to put two Django installations within the same ``VirtualHost``, @@ -89,13 +89,13 @@ mess things up. Use the ``PythonInterpreter`` directive to give different ServerName www.example.com # ... <Location "/something"> - SetEnv DJANGO_SETTINGS_MODULE myproject.settings - PythonInterpreter myproject + SetEnv DJANGO_SETTINGS_MODULE mysite.settings + PythonInterpreter mysite </Location> <Location "/otherthing"> - SetEnv DJANGO_SETTINGS_MODULE myproject.other_settings - PythonInterpreter myproject_other + SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings + PythonInterpreter mysite_other </Location> </VirtualHost> @@ -153,7 +153,7 @@ the ``media`` subdirectory and any URL that ends with ``.jpg``, ``.gif`` or <Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython - SetEnv DJANGO_SETTINGS_MODULE myproject.settings + SetEnv DJANGO_SETTINGS_MODULE mysite.settings </Location> <Location "media"> diff --git a/docs/outputting_csv.txt b/docs/outputting_csv.txt index 3f95b3600d..1970261891 100644 --- a/docs/outputting_csv.txt +++ b/docs/outputting_csv.txt @@ -30,7 +30,7 @@ and Django's ``HttpResponse`` objects are file-like objects. Here's an example:: import csv - from django.utils.httpwrappers import HttpResponse + from django.http import HttpResponse def some_view(request): # Create the HttpResponse object with the appropriate CSV header. @@ -49,10 +49,10 @@ mention: * The response gets a special mimetype, ``text/csv``. This tells browsers that the document is a CSV file, rather than an HTML file. If you leave this off, browsers will probably interpret the output as HTML, - which would result in ugly, scary gobbledygook in the browser window. + which will result in ugly, scary gobbledygook in the browser window. * The response gets an additional ``Content-Disposition`` header, which - contains the name of the CSV file. This filename is arbitrary: Call it + contains the name of the CSV file. This filename is arbitrary; call it whatever you want. It'll be used by browsers in the "Save as..." dialogue, etc. @@ -79,8 +79,8 @@ template output the commas in a ``{% for %}`` loop. Here's an example, which generates the same CSV file as above:: - from django.utils.httpwrappers import HttpResponse - from django.core.template import loader, Context + from django.http import HttpResponse + from django.template import loader, Context def some_view(request): # Create the HttpResponse object with the appropriate CSV header. @@ -94,7 +94,7 @@ Here's an example, which generates the same CSV file as above:: ('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"), ) - t = loader.get_template('my_template_name') + t = loader.get_template('my_template_name.txt') c = Context({ 'data': csv_data, }) @@ -105,7 +105,7 @@ The only difference between this example and the previous example is that this one uses template loading instead of the CSV module. The rest of the code -- such as the ``mimetype='text/csv'`` -- is the same. -Then, create the template ``my_template_name``, with this template code:: +Then, create the template ``my_template_name.txt``, with this template code:: {% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}" {% endfor %} diff --git a/docs/outputting_pdf.txt b/docs/outputting_pdf.txt index 9f3d6b26eb..a58cf2c217 100644 --- a/docs/outputting_pdf.txt +++ b/docs/outputting_pdf.txt @@ -48,7 +48,7 @@ objects. Here's a "Hello World" example:: from reportlab.pdfgen import canvas - from django.utils.httpwrappers import HttpResponse + from django.http import HttpResponse def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. diff --git a/docs/overview.txt b/docs/overview.txt index 11fa7d1fa9..544a897ac6 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -16,34 +16,39 @@ to start a project. Design your model ================= -Start by describing your database layout in Python code. Django's data-model API -offers many rich ways of representing your models -- so far, it's been -solving two years' worth of database-schema problems. Here's a quick example:: +Although you can use Django without a database, it comes with an +object-relational mapper in which you describe your database layout in Python +code. - class Reporter(meta.Model): - full_name = meta.CharField(maxlength=70) +The data-model syntax offers many rich ways of representing your models -- so +far, it's been solving two years' worth of database-schema problems. Here's a +quick example:: - def __repr__(self): + class Reporter(models.Model): + full_name = models.CharField(maxlength=70) + + def __str__(self): return self.full_name - class Article(meta.Model): - pub_date = meta.DateTimeField() - headline = meta.CharField(maxlength=200) - article = meta.TextField() - reporter = meta.ForeignKey(Reporter) + class Article(models.Model): + pub_date = models.DateTimeField() + headline = models.CharField(maxlength=200) + article = models.TextField() + reporter = models.ForeignKey(Reporter) - def __repr__(self): + def __str__(self): return self.headline Install it ========== -Next, run the Django command-line utility. It'll create the database tables for -you automatically, in the database specified in your Django settings. Django -works best with PostgreSQL, although we've recently added beta MySQL -support and other database adapters are on the way:: +Next, run the Django command-line utility to create the database tables +automatically:: + + manage.py syncdb - django-admin.py install news +The ``syncdb`` command looks at all your available models and creates tables +in your database for whichever tables don't already exist. Enjoy the free API ================== @@ -51,16 +56,14 @@ Enjoy the free API With that, you've got a free, and rich, Python API to access your data. The API is created on the fly: No code generation necessary:: - # Modules are dynamically created within django.models. - # Their names are plural versions of the model class names. - >>> from django.models.news import reporters, articles + >>> from mysite.models import Reporter, Article # No reporters are in the system yet. - >>> reporters.get_list() + >>> Reporter.objects.all() [] # Create a new Reporter. - >>> r = reporters.Reporter(full_name='John Smith') + >>> r = Reporter(full_name='John Smith') # Save the object into the database. You have to call save() explicitly. >>> r.save() @@ -70,52 +73,48 @@ is created on the fly: No code generation necessary:: 1 # Now the new reporter is in the database. - >>> reporters.get_list() + >>> Reporter.objects.all() [John Smith] # Fields are represented as attributes on the Python object. >>> r.full_name 'John Smith' - # Django provides a rich database lookup API that's entirely driven by keyword arguments. - >>> reporters.get_object(id__exact=1) + # Django provides a rich database lookup API. + >>> Reporter.objects.get(id=1) John Smith - >>> reporters.get_object(full_name__startswith='John') + >>> Reporter.objects.get(full_name__startswith='John') John Smith - >>> reporters.get_object(full_name__contains='mith') + >>> Reporter.objects.get(full_name__contains='mith') John Smith - >>> reporters.get_object(id__exact=2) + >>> Reporter.objects.get(id=2) Traceback (most recent call last): ... - django.models.news.ReporterDoesNotExist: Reporter does not exist for {'id__exact': 2} - - # Lookup by a primary key is the most common case, so Django provides a - # shortcut for primary-key exact lookups. - # The following is identical to reporters.get_object(id__exact=1). - >>> reporters.get_object(pk=1) - John Smith + DoesNotExist: Reporter does not exist for {'id__exact': 2} # Create an article. >>> from datetime import datetime - >>> a = articles.Article(pub_date=datetime.now(), headline='Django is cool', article='Yeah.', reporter_id=1) + >>> a = Article(pub_date=datetime.now(), headline='Django is cool', + ... article='Yeah.', reporter=r) >>> a.save() # Now the article is in the database. - >>> articles.get_list() + >>> Article.objects.all() [Django is cool] # Article objects get API access to related Reporter objects. - >>> r = a.get_reporter() + >>> r = a.reporter >>> r.full_name 'John Smith' # And vice versa: Reporter objects get API access to Article objects. - >>> r.get_article_list() + >>> r.article_set.all() [Django is cool] - # The API follows relationships as far as you need. - # Find all articles by a reporter whose name starts with "John". - >>> articles.get_list(reporter__full_name__startswith="John") + # The API follows relationships as far as you need, performing efficient + # JOINs for you behind the scenes. + # This finds all articles by a reporter whose name starts with "John". + >>> Article.objects.filter(reporter__full_name__startswith="John") [Django is cool] # Change an object by altering its attributes and calling save(). @@ -128,61 +127,64 @@ is created on the fly: No code generation necessary:: A dynamic admin interface: It's not just scaffolding -- it's the whole house ============================================================================ -Once your models are defined, Django can automatically create an administrative -interface -- a Web site that lets authenticated users add, change and -delete objects. It's as easy as adding an extra ``admin`` attribute to your -model classes:: +Once your models are defined, Django can automatically create a professional, +production ready administrative interface -- a Web site that lets authenticated +users add, change and delete objects. It's as easy as adding a line of code to +your model classes:: - class Article(meta.Model): - pub_date = meta.DateTimeField() - headline = meta.CharField(maxlength=200) - article = meta.TextField() - reporter = meta.ForeignKey(Reporter) - class META: - admin = meta.Admin() + class Article(models.Model): + pub_date = models.DateTimeField() + headline = models.CharField(maxlength=200) + article = models.TextField() + reporter = models.ForeignKey(Reporter) + class Admin: pass The philosophy here is that your site is edited by a staff, or a client, or maybe just you -- and you don't want to have to deal with creating backend interfaces just to manage content. -Our typical workflow at World Online is to create models and get the admin sites -up and running as fast as possible, so our staff journalists can start -populating data. Then we develop the way data is presented to the public. +One typical workflow in creating Django apps is to create models and get the +admin sites up and running as fast as possible, so your staff (or clients) can +start populating data. Then, develop the way data is presented to the public. Design your URLs ================ A clean, elegant URL scheme is an important detail in a high-quality Web -application. Django lets you design URLs however you want, with no framework -limitations. +application. Django encourages beautiful URL design and doesn't put any cruft +in URLs, like ``.php`` or ``.asp``. -To design URLs for an app, you create a Python module. For the above -Reporter/Article example, here's what that might look like:: +To design URLs for an app, you create a Python module called a URLconf. A table +of contents for your app, it contains a simple mapping between URL patterns and +Python callback functions. URLconfs also serve to decouple URLs from Python +code. + +Here's what a URLconf might look like for the above ``Reporter``/``Article`` +example above:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^/articles/(?P<year>\d{4})/$', 'myproject.news.views.year_archive'), - (r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'myproject.news.views.month_archive'), - (r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<article_id>\d+)/$', 'myproject.news.views.article_detail'), + (r'^/articles/(\d{4})/$', 'mysite.views.year_archive'), + (r'^/articles/(\d{4})/(\d{2})/$', 'mysite.views.month_archive'), + (r'^/articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.views.article_detail'), ) -The code above maps URLs, as regular expressions, to the location of Python -callback functions (views). The regular expressions use parenthesis to "capture" -values from the URLs. When a user requests a page, Django runs through each -regular expression, in order, and stops at the first one that matches the -requested URL. (If none of them matches, Django calls a special 404 view.) This -is blazingly fast, because the regular expressions are compiled at load time. +The code above maps URLs, as simple regular expressions, to the location of +Python callback functions ("views"). The regular expressions use parenthesis to +"capture" values from the URLs. When a user requests a page, Django runs +through each pattern, in order, and stops at the first one that matches the +requested URL. (If none of them matches, Django calls a special-case 404 view.) +This is blazingly fast, because the regular expressions are compiled at load +time. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. Each view gets passed a request object -- -which contains request metadata and lets you access GET and POST data as simple -dictionaries -- and the values captured in the regex, via keyword -arguments. +which contains request metadata -- and the values captured in the regex. For example, if a user requested the URL "/articles/2005/05/39323/", Django would call the function ``myproject.news.views.article_detail(request, -year='2005', month='05', article_id='39323')``. +'2005', '05', '39323')``. Write your views ================ @@ -193,29 +195,29 @@ raising an exception such as ``Http404``. The rest is up to you. Generally, a view retrieves data according to the parameters, loads a template and renders the template with the retrieved data. Here's an example view for -article_detail from above:: +``year_archive`` from above:: - def article_detail(request, year, month, article_id): - # Use the Django API to find an object matching the URL criteria. - a = get_object_or_404(articles, pub_date__year=year, pub_date__month=month, pk=article_id) - return render_to_response('news/article_detail', {'article': a}) + def year_archive(request, year): + a_list = Article.objects.filter(pub_date__year=year) + return render_to_response('news/year_archive.html', {'article_list': a_list}) -This example uses Django's template system, which has several key features. +This example uses Django's template system, which has several powerful +features but strives to stay simple enough for non-programmers to use. Design your templates ===================== -The code above loads the ``news/article_detail`` template. +The code above loads the ``news/year_archive.html`` template. Django has a template search path, which allows you to minimize redundancy among templates. In your Django settings, you specify a list of directories to check for templates. If a template doesn't exist in the first directory, it checks the second, and so on. -Let's say the ``news/article_detail`` template was found. Here's what that might -look like:: +Let's say the ``news/article_detail.html`` template was found. Here's what that +might look like:: - {% extends "base" %} + {% extends "base.html" %} {% block title %}{{ article.headline }}{% endblock %} @@ -226,12 +228,10 @@ look like:: {{ article.article }} {% endblock %} - -It should look straightforward. Variables are surrounded by double-curly braces. -``{{ article.headline }}`` means "Output the value of the article's headline -attribute." But dots aren't used only for attribute lookup: They also can do -dictionary-key lookup, index lookup and function calls (as is the case with -``article.get_reporter``). +Variables are surrounded by double-curly braces. ``{{ article.headline }}`` +means "Output the value of the article's headline attribute." But dots aren't +used only for attribute lookup: They also can do dictionary-key lookup, index +lookup and function calls (as is the case with ``article.get_reporter``). Note ``{{ article.pub_date|date:"F j, Y" }}`` uses a Unix-style "pipe" (the "|" character). This is called a template filter, and it's a way to filter the value @@ -243,13 +243,13 @@ You can chain together as many filters as you'd like. You can write custom filters. You can write custom template tags, which run custom Python code behind the scenes. -Finally, Django uses the concept of template inheritance: That's what the ``{% -extends "base" %}`` does. It means "First load the template called 'base', which -has defined a bunch of blocks, and fill the blocks with the following blocks." -In short, that lets you dramatically cut down on redundancy in templates: Each -template has to define only what's unique to that template. +Finally, Django uses the concept of "template inheritance": That's what the +``{% extends "base.html" %}`` does. It means "First load the template called +'base', which has defined a bunch of blocks, and fill the blocks with the +following blocks." In short, that lets you dramatically cut down on redundancy +in templates: Each template has to define only what's unique to that template. -Here's what the "base" template might look like:: +Here's what the "base.html" template might look like:: <html> <head> @@ -265,13 +265,18 @@ Simplistically, it defines the look-and-feel of the site (with the site's logo), and provides "holes" for child templates to fill. This makes a site redesign as easy as changing a single file -- the base template. +It also lets you create multiple versions of a site, with different base +templates, while reusing child templates. Django's creators have used this +technique to create strikingly different cell-phone editions of sites -- simply +by creating a new base template. + Note that you don't have to use Django's template system if you prefer another system. While Django's template system is particularly well-integrated with Django's model layer, nothing forces you to use it. For that matter, you don't -have to use Django's API, either. You can use another database abstraction -layer, you can read XML files, you can read files off disk, or anything you -want. Each piece of Django -- models, views, templates -- is decoupled -from the next. +have to use Django's database API, either. You can use another database +abstraction layer, you can read XML files, you can read files off disk, or +anything you want. Each piece of Django -- models, views, templates -- is +decoupled from the next. This is just the surface ======================== diff --git a/docs/redirects.txt b/docs/redirects.txt index 08fae8a8dc..e0bcb2f1fa 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -8,12 +8,12 @@ redirects in a database and handles the redirecting for you. Installation ============ -To install the redirects app, follow these two steps: +To install the redirects app, follow these steps: - 1. Add ``"django.contrib.redirects"`` to your INSTALLED_APPS_ setting. - 2. Add ``"django.contrib.redirects.middleware.RedirectFallbackMiddleware"`` + 1. Add ``'django.contrib.redirects'`` to your INSTALLED_APPS_ setting. + 2. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'`` to your MIDDLEWARE_CLASSES_ setting. - 3. Run the command ``django-admin.py install redirects``. + 3. Run the command ``manage.py syncdb``. .. _INSTALLED_APPS: http://www.djangoproject.com/documentation/settings/#installed-apps .. _MIDDLEWARE_CLASSES: http://www.djangoproject.com/documentation/settings/#middleware-classes @@ -21,9 +21,8 @@ To install the redirects app, follow these two steps: How it works ============ -``django-admin.py install redirects`` creates a ``django_redirects`` table in -your database. This is a simple lookup table with ``site_id``, ``old_path`` and -``new_path`` fields. +``manage.py syncdb`` creates a ``django_redirect`` table in your database. This +is a simple lookup table with ``site_id``, ``old_path`` and ``new_path`` fields. The ``RedirectFallbackMiddleware`` does all of the work. Each time any Django application raises a 404 error, this middleware checks the redirects database diff --git a/docs/request_response.txt b/docs/request_response.txt index fc78a3459b..6fa4311f61 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -37,6 +37,8 @@ All attributes except ``session`` should be considered read-only. A dictionary-like object containing all given HTTP POST parameters. See the ``QueryDict`` documentation below. + Note: ``POST`` does *not* include file-upload information. See ``FILES``. + ``REQUEST`` For convenience, a dictionary-like object that searches ``POST`` first, then ``GET``. Inspired by PHP's ``$_REQUEST``. @@ -86,9 +88,9 @@ All attributes except ``session`` should be considered read-only. * ``SERVER_PORT`` -- The port of the server. ``user`` - A ``django.models.auth.users.User`` object representing the currently + A ``django.contrib.auth.models.User`` object representing the currently logged-in user. If the user isn't currently logged in, ``user`` will be set - to an instance of ``django.parts.auth.anonymoususers.AnonymousUser``. You + to an instance of ``django.contrib.auth.models.AnonymousUser``. You can tell them apart with ``is_anonymous()``, like so:: if request.user.is_anonymous(): @@ -96,6 +98,12 @@ All attributes except ``session`` should be considered read-only. else: # Do something for logged-in users. + ``user`` is only available if your Django installation has the + ``AuthenticationMiddleware`` activated. For more, see + `Authentication in Web requests`_. + + .. Authentication in Web requests: http://www.djangoproject.com/documentation/authentication/#authentication-in-web-requests + ``session`` A readable-and-writable, dictionary-like object that represents the current session. This is only available if your Django installation has session @@ -131,10 +139,10 @@ QueryDict objects ----------------- In an ``HttpRequest`` object, the ``GET`` and ``POST`` attributes are instances -of ``django.utils.httpwrappers.QueryDict``. ``QueryDict`` is a dictionary-like +of ``django.http.QueryDict``. ``QueryDict`` is a dictionary-like class customized to deal with multiple values for the same key. This is -necessary because some HTML form elements, notably ``<select multiple>``, pass -multiple values for the same key. +necessary because some HTML form elements, notably +``<select multiple="multiple">``, pass multiple values for the same key. ``QueryDict`` instances are immutable, unless you create a ``copy()`` of them. That means you can't change attributes of ``request.POST`` and ``request.GET`` @@ -269,11 +277,14 @@ In contrast to ``HttpRequest`` objects, which are created automatically by Django, ``HttpResponse`` objects are your responsibility. Each view you write is responsible for instantiating, populating and returning an ``HttpResponse``. -The ``HttpResponse`` class lives at ``django.utils.httpwrappers.HttpResponse``. +The ``HttpResponse`` class lives at ``django.http.HttpResponse``. Usage ----- +Passing strings +~~~~~~~~~~~~~~~ + Typical usage is to pass the contents of the page, as a string, to the ``HttpResponse`` constructor:: @@ -297,16 +308,27 @@ You can add and delete headers using dictionary syntax:: Note that ``del`` doesn't raise ``KeyError`` if the header doesn't exist. +Passing iterators +~~~~~~~~~~~~~~~~~ + +Finally, you can pass ``HttpResponse`` an iterator rather than passing it +hard-coded strings. If you use this technique, follow these guidelines: + + * The iterator should return strings. + * If an ``HttpResponse`` has been initialized with an iterator as its + content, you can't use the ``HttpResponse`` instance as a file-like + object. Doing so will raise ``Exception``. + Methods ------- ``__init__(content='', mimetype=DEFAULT_MIME_TYPE)`` Instantiates an ``HttpResponse`` object with the given page content (a - string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``"text/html"``. + string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``'text/html'``. - **New in Django development version:** ``content`` can be an iterator - instead of a string. This iterator should return strings, and those strings - will be joined together to form the content of the response. + ``content`` can be an iterator or a string. If it's an iterator, it should + return strings, and those strings will be joined together to form the + content of the response. ``__setitem__(header, value)`` Sets the given header name to the given value. Both ``header`` and @@ -343,14 +365,10 @@ Methods Deletes the cookie with the given key. Fails silently if the key doesn't exist. -``get_content_as_string(encoding)`` - Returns the content as a Python string, encoding it from a Unicode object - if necessary. **Removed in Django development version.** - ``content`` - **New in Django development version.** Returns the content as a Python - string, encoding it from a Unicode object if necessary. Note this is a - property, not a method, so use ``r.content`` instead of ``r.content()``. + Returns the content as a Python string, encoding it from a Unicode object + if necessary. Note this is a property, not a method, so use ``r.content`` + instead of ``r.content()``. ``write(content)``, ``flush()`` and ``tell()`` These methods make an ``HttpResponse`` instance a file-like object. @@ -360,12 +378,12 @@ HttpResponse subclasses Django includes a number of ``HttpResponse`` subclasses that handle different types of HTTP responses. Like ``HttpResponse``, these subclasses live in -``django.utils.httpwrappers``. +``django.http``. ``HttpResponseRedirect`` The constructor takes a single argument -- the path to redirect to. This - can be a fully qualified URL (e.g. ``"http://www.yahoo.com/search/"``) or an - absolute URL with no domain (e.g. ``"/search/"``). Note that this returns + can be a fully qualified URL (e.g. ``'http://www.yahoo.com/search/'``) or an + absolute URL with no domain (e.g. ``'/search/'``). Note that this returns an HTTP status code 302. ``HttpResponsePermanentRedirect`` diff --git a/docs/sessions.txt b/docs/sessions.txt index 6a208a1461..10d94cd4fd 100644 --- a/docs/sessions.txt +++ b/docs/sessions.txt @@ -10,33 +10,30 @@ Cookies contain a session ID -- not the data itself. Enabling sessions ================= -Session functionality is enabled by default. +Sessions are implemented via middleware_. -You can turn session functionality on and off by editing the -``MIDDLEWARE_CLASSES`` setting. To activate sessions, make sure -``MIDDLEWARE_CLASSES`` contains ``"django.middleware.sessions.SessionMiddleware"``. +Turn session functionality on and off by editing the ``MIDDLEWARE_CLASSES`` +setting. To activate sessions, make sure ``MIDDLEWARE_CLASSES`` contains +``"django.contrib.sessions.middleware.SessionMiddleware"``. -If you're dealing with an admin site, make sure the ``SessionMiddleware`` line -appears before the ``AdminUserRequired`` line. (The middleware classes are -applied in order, and the admin middleware requires that the session middleware -come first.) +The default ``settings.py`` created by ``django-admin.py startproject`` has +``SessionMiddleware`` activated. If you don't want to use sessions, you might as well remove the ``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES``. It'll save you a small bit of overhead. +.. _middleware: http://www.djangoproject.com/documentation/middleware/ + Using sessions in views ======================= -Each ``HttpRequest`` object -- the first argument to any Django view function -- -has a ``session`` attribute, which is a dictionary-like object. You can read -it and write to it. +When ``SessionMiddleware`` is activated, each ``HttpRequest`` object -- the +first argument to any Django view function -- will have a ``session`` +attribute, which is a dictionary-like object. You can read it and write to it. It implements the following standard dictionary methods: - * ``__contains__(key)`` - Example: ``'fav_color' in request.session`` - * ``__getitem__(key)`` Example: ``fav_color = request.session['fav_color']`` @@ -47,14 +44,15 @@ It implements the following standard dictionary methods: Example: ``del request.session['fav_color']``. This raises ``KeyError`` if the given ``key`` isn't already in the session. + * ``__contains__(key)`` + Example: ``'fav_color' in request.session`` + * ``get(key, default=None)`` Example: ``fav_color = request.session.get('fav_color', 'red')`` * ``keys()`` - **New in Django development version.** * ``items()`` - **New in Django development version.** It also has these three methods: @@ -146,17 +144,17 @@ Here's a typical usage example:: else: return HttpResponse("Please enable cookies and try again.") request.session.set_test_cookie() - return render_to_response('foo/login_form') + return render_to_response('foo/login_form.html') Using sessions out of views =========================== Internally, each session is just a normal Django model. The ``Session`` model -is defined in ``django/models/core.py``. Because it's a normal model, you can -access sessions using the normal Django database API:: +is defined in ``django/contrib/sessions/models.py``. Because it's a normal +model, you can access sessions using the normal Django database API:: - >>> from django.models.core import sessions - >>> s = sessions.get_object(pk='2b1189a188b44ad18c35e113ac6ceead') + >>> from django.contrib.sessions.models import Session + >>> s = Session.objects.get_object(pk='2b1189a188b44ad18c35e113ac6ceead') >>> s.expire_date datetime.datetime(2005, 8, 20, 13, 35, 12) @@ -244,7 +242,7 @@ Technical details * The session dictionary should accept any pickleable Python object. See `the pickle module`_ for more information. - * Session data is stored in a database table named ``core_sessions`` . + * Session data is stored in a database table named ``django_session`` . * Django only sends a cookie if it needs to. If you don't set any session data, it won't send a session cookie. diff --git a/docs/settings.txt b/docs/settings.txt index 25c07785fd..d4666468fc 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -19,7 +19,7 @@ Here are a couple of example settings:: Because a settings file is a Python module, the following apply: - * It shouldn't have Python syntax errors. + * It doesn't allow for Python syntax errors. * It can assign settings dynamically using normal Python syntax. For example:: @@ -34,7 +34,7 @@ When you use Django, you have to tell it which settings you're using. Do this by using an environment variable, ``DJANGO_SETTINGS_MODULE``. The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g. -``"myproject.settings"``. Note that the settings module should be on the +``mysite.settings``. Note that the settings module should be on the Python `import search path`_. .. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html @@ -47,17 +47,17 @@ once, or explicitly pass in the settings module each time you run the utility. Example (Unix Bash shell):: - export DJANGO_SETTINGS_MODULE=myproject.settings + export DJANGO_SETTINGS_MODULE=mysite.settings django-admin.py runserver Example (Windows shell):: - set DJANGO_SETTINGS_MODULE=myproject.settings + set DJANGO_SETTINGS_MODULE=mysite.settings django-admin.py runserver Use the ``--settings`` command-line argument to specify the settings manually:: - django-admin.py runserver --settings=myproject.settings + django-admin.py runserver --settings=mysite.settings .. _django-admin.py: http://www.djangoproject.com/documentation/django_admin/ @@ -70,7 +70,7 @@ settings file to use. Do that with ``SetEnv``:: <Location "/mysite/"> SetHandler python-program PythonHandler django.core.handlers.modpython - SetEnv DJANGO_SETTINGS_MODULE myproject.settings + SetEnv DJANGO_SETTINGS_MODULE mysite.settings </Location> Read the `Django mod_python documentation`_ for more information. @@ -93,6 +93,17 @@ Here's the algorithm Django uses in compiling settings: Note that a settings file should *not* import from ``global_settings``, because that's redundant. +Seeing which settings you've changed +------------------------------------ + +There's an easy way to view which of your settings deviate from the default +settings. The command ``python manage.py diffsettings`` displays differences +between the current settings file and Django's default settings. + +For more, see the `diffsettings documentation`_. + +.. _diffsettings documentation: http://www.djangoproject.com/documentation/django_admin/#diffsettings + Using settings in Python code ============================= @@ -107,6 +118,8 @@ In your Django apps, use settings by importing them from Note that your code should *not* import from either ``global_settings`` or your own settings file. ``django.conf.settings`` abstracts the concepts of default settings and site-specific settings; it presents a single interface. +It also decouples the code that uses settings from the location of your +settings. Altering settings at runtime ============================ @@ -156,6 +169,9 @@ Default: ``()`` (Empty list) Used for admin-site settings modules, this should be a tuple of settings modules (in the format ``'foo.bar.baz'``) for which this site is an admin. +The admin site uses this in its automatically-introspected documentation of +models, views and template tags. + ADMIN_MEDIA_PREFIX ------------------ @@ -228,6 +244,14 @@ Default: ``''`` (Empty string) Which host to use when connecting to the database. An empty string means localhost. Not used with SQLite. +If this value starts with a forward slash (``'/'``) and you're using MySQL, +MySQL will connect via a Unix socket to the specified socket. For example:: + + DATABASE_HOST = '/var/run/mysql' + +If you're using MySQL and this value *doesn't* start with a forward slash, then +this value is assumed to be the host. + DATABASE_NAME ------------- @@ -341,8 +365,6 @@ EMAIL_HOST_PASSWORD Default: ``''`` (Empty string) -**New in Django development version.** - Username to use for the SMTP server defined in ``EMAIL_HOST``. If empty, Django won't attempt authentication. @@ -353,8 +375,6 @@ EMAIL_HOST_USER Default: ``''`` (Empty string) -**New in Django development version.** - Username to use for the SMTP server defined in ``EMAIL_HOST``. If empty, Django won't attempt authentication. @@ -365,8 +385,6 @@ EMAIL_PORT Default: ``25`` -**New in Django development version.** - Port to use for the SMTP server defined in ``EMAIL_HOST``. EMAIL_SUBJECT_PREFIX @@ -383,8 +401,6 @@ ENABLE_PSYCO Default: ``False`` -**New in Django development version.** - Whether to enable Psyco, which optimizes Python code. Requires Psyco_. .. _Psyco: http://psyco.sourceforge.net/ @@ -509,7 +525,8 @@ MIDDLEWARE_CLASSES Default:: - ("django.middleware.sessions.SessionMiddleware", + ("django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.doc.XViewMiddleware") @@ -598,9 +615,9 @@ SITE_ID Default: Not defined -The ID, as an integer, of the current site in the ``sites`` database. This is -used so that application data can hook into specific site(s) and a single -database can manage content for multiple sites. +The ID, as an integer, of the current site in the ``django_site`` database +table. This is used so that application data can hook into specific site(s) +and a single database can manage content for multiple sites. TEMPLATE_CONTEXT_PROCESSORS --------------------------- @@ -611,7 +628,7 @@ Default:: "django.core.context_processors.debug", "django.core.context_processors.i18n") -A tuple of callables that are used to populate the context in ``DjangoContext``. +A tuple of callables that are used to populate the context in ``RequestContext``. These callables take a request object as their argument and return a dictionary of items to be merged into the context. @@ -625,8 +642,8 @@ error page will display a detailed report for any ``TemplateSyntaxError``. This report contains the relevant snippet of the template, with the appropriate line highlighted. -Note that Django only displays fancy error pages if ``DEBUG`` is ``True``, so you'll -want to set that to take advantage of this setting. +Note that Django only displays fancy error pages if ``DEBUG`` is ``True``, so +you'll want to set that to take advantage of this setting. See also DEBUG. @@ -640,18 +657,10 @@ these paths should use Unix-style forward slashes, even on Windows. See the `template documentation`_. -TEMPLATE_FILE_EXTENSION ------------------------ - -Default: ``'.html'`` - -The file extension to append to all template names when searching for -templates. See the `template documentation`_. - TEMPLATE_LOADERS ---------------- -Default: ``('django.core.template.loaders.filesystem.load_template_source',)`` +Default: ``('django.template.loaders.filesystem.load_template_source',)`` A tuple of callables (as strings) that know how to import templates from various sources. See the `template documentation`_. @@ -661,8 +670,6 @@ TEMPLATE_STRING_IF_INVALID Default: ``''`` (Empty string) -**New in Django development version.** - Output, as a string, that the template system should use for invalid (e.g. misspelled) variables. See `How invalid variables are handled`_. diff --git a/docs/static_files.txt b/docs/static_files.txt index 333bb12e22..d8d90e52d5 100644 --- a/docs/static_files.txt +++ b/docs/static_files.txt @@ -31,7 +31,7 @@ How to do it Just put this in your URLconf_:: - (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}), + (r'^site_media/(.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}), ...where ``site_media`` is the URL where your media will be rooted, and ``/path/to/media`` is the filesystem root for your media. @@ -60,7 +60,7 @@ listings for directories. Example:: - (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}), + (r'^site_media/(.*)$', 'django.views.static.serve', {'document_root': '/path/to/media', 'show_indexes': True}), You can customize the index view by creating a template called ``static/directory_index``. That template gets two objects in its context: @@ -100,7 +100,7 @@ Do this by wrapping an ``if DEBUG`` statement around the ``django.views.static.serve`` inclusion. Here's a full example URLconf:: from django.conf.urls.defaults import * - from django.conf.settings import DEBUG + from django.conf import settings urlpatterns = patterns('', (r'^/articles/2003/$', 'news.views.special_case_2003'), @@ -109,15 +109,15 @@ Do this by wrapping an ``if DEBUG`` statement around the (r'^/articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), ) - if DEBUG: + if settings.DEBUG: urlpatterns += patterns('', (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/media'}), ) -This code is straightforward. It imports the `DEBUG setting`_ and checks its -value. If it evaluates to ``True``, then ``site_media`` will be associated with -the ``django.views.static.serve`` view. If not (``DEBUG == False``), then the -view won't be made available. +This code is straightforward. It imports the settings and checks the value of +the ``DEBUG`` setting. If it evaluates to ``True``, then ``site_media`` will be +associated with the ``django.views.static.serve`` view. If not +(``DEBUG == False``), then the view won't be made available. Of course, the catch here is that you'll have to remember to set ``DEBUG=False`` in your production settings file. But you should be doing that anyway. diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt index d234c2b7ec..b7b0a9047b 100644 --- a/docs/syndication_feeds.txt +++ b/docs/syndication_feeds.txt @@ -93,7 +93,7 @@ This simple example, taken from `chicagocrime.org`_, describes a feed of the latest five news items:: from django.contrib.syndication.feeds import Feed - from django.models.chicagocrime import newsitems + from chicagocrime.models import NewsItem class SiteNewsFeed(Feed): title = "Chicagocrime.org site news" @@ -101,7 +101,7 @@ latest five news items:: description = "Updates on changes and additions to chicagocrime.org." def items(self): - return newsitems.get_list(order_by=('-pub_date',), limit=5) + return NewsItem.objects.order_by('-pub_date')[:5] Note: @@ -120,10 +120,11 @@ One thing's left to do. In an RSS feed, each ``<item>`` has a ``<title>``, put into those elements. * To specify the contents of ``<title>`` and ``<description>``, create - `Django templates`_ called ``feeds/sitenews_title`` and - ``feeds/sitenews_description``, where ``sitenews`` is the ``slug`` - specified in the URLconf for the given feed. The RSS system renders that - template for each item, passing it two template context variables: + `Django templates`_ called ``feeds/sitenews_title.html`` and + ``feeds/sitenews_description.html``, where ``sitenews`` is the ``slug`` + specified in the URLconf for the given feed. Note the ``.html`` extension + is required. The RSS system renders that template for each item, passing + it two template context variables: * ``{{ obj }}`` -- The current object (one of whichever objects you returned in ``items()``). @@ -175,7 +176,7 @@ An example makes this clear. Here's the code for these beat-specific feeds:: # check that bits has only one member. if len(bits) != 1: raise ObjectDoesNotExist - return beats.get_object(beat__exact=bits[0]) + return Beat.objects.get(beat__exact=bits[0]) def title(self, obj): return "Chicagocrime.org: Crimes for beat %s" % obj.beat @@ -187,7 +188,7 @@ An example makes this clear. Here's the code for these beat-specific feeds:: return "Crimes recently reported in police beat %s" % obj.beat def items(self, obj): - return crimes.get_list(beat__id__exact=obj.id, order_by=(('-crime_date'),), limit=30) + return Crime.objects.filter(beat__id__exact=obj.id).order_by('-crime_date')[:30] Here's the basic algorithm the RSS framework follows, given this class and a request to the URL ``/rss/beats/0613/``: @@ -203,8 +204,8 @@ request to the URL ``/rss/beats/0613/``: the beat. Note that ``get_object()`` should raise ``django.core.exceptions.ObjectDoesNotExist`` if given invalid parameters. There's no ``try``/``except`` around the - ``beats.get_object()`` call, because it's not necessary; that function - raises ``BeatDoesNotExist`` on failure, and ``BeatDoesNotExist`` is a + ``Beat.objects.get()`` call, because it's not necessary; that function + raises ``Beat.DoesNotExist`` on failure, and ``Beat.DoesNotExist`` is a subclass of ``ObjectDoesNotExist``. Raising ``ObjectDoesNotExist`` in ``get_object()`` tells Django to produce a 404 error for that request. * To generate the feed's ``<title>``, ``<link>`` and ``<description>``, @@ -292,7 +293,7 @@ URLconf to add the extra versions. Here's a full example:: from django.contrib.syndication.feeds import Feed - from django.models.chicagocrime import newsitems + from chicagocrime.models import NewsItem from django.utils.feedgenerator import Atom1Feed class RssSiteNewsFeed(Feed): @@ -301,7 +302,7 @@ Here's a full example:: description = "Updates on changes and additions to chicagocrime.org." def items(self): - return newsitems.get_list(order_by=('-pub_date',), limit=5) + return NewsItem.objects.order_by('-pub_date')[:5] class AtomSiteNewsFeed(RssSiteNewsFeed): feed_type = Atom1Feed @@ -328,7 +329,6 @@ Feed class reference This example illustrates all possible attributes and methods for a ``Feed`` class:: - from django.contrib.syndication.feeds import Feed from django.utils import feedgenerator diff --git a/docs/templates.txt b/docs/templates.txt index 22c10caf15..6cc99e93e3 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -13,9 +13,8 @@ or CheetahTemplate_, you should feel right at home with Django's templates. Templates ========= -A template is simply a text file. All Django templates, by convention, have -".html" extensions, but they can generate any text-based format (HTML, XML, -CSV, etc.). +A template is simply a text file. It can generate any text-based format (HTML, +XML, CSV, etc.). A template contains **variables**, which get replaced with values when the template is evaluated, and **tags**, which control the logic of the template. @@ -23,7 +22,7 @@ template is evaluated, and **tags**, which control the logic of the template. Below is a minimal template that illustrates a few basics. Each element will be explained later in this document.:: - {% extends "base_generic" %} + {% extends "base_generic.html" %} {% block title %}{{ section.title }}{% endblock %} @@ -48,6 +47,8 @@ explained later in this document.:: JavaScript and CSV. You can use the template language for any text-based format. + Oh, and one more thing: Making humans edit XML is masochistic! + Variables ========= @@ -70,32 +71,27 @@ Use a dot (``.``) to access attributes of a variable. In the above example, ``{{ section.title }}`` will be replaced with the ``title`` attribute of the ``section`` object. -In Django 0.91, if you use a variable that doesn't exist, it will be silently -ignored; the variable will be replaced by nothingness. In the Django -development version, if a variable doesn't exist, the template system inserts +If you use a variable that doesn't exist, the template system will insert the value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty string) by default. -If you use a variable that doesn't exist, it will be silently ignored. The -variable will be replaced by nothingness. - See `Using the built-in reference`_, below, for help on finding what variables are available in a given template. -You can modify variables for display by using **filters**. - Filters ======= +You can modify variables for display by using **filters**. + Filters look like this: ``{{ name|lower }}``. This displays the value of the ``{{ name }}`` variable after being filtered through the ``lower`` filter, which converts text to lowercase. Use a pipe (``|``) to apply a filter. -Filters can be "chained." The output of one filter applied to the next: -``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents -and then converting line breaks to ``<p>`` tags. +Filters can be "chained." The output of one filter is applied to the next. +``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents, +then converting line breaks to ``<p>`` tags. -Certain filters take arguments. A filter argument looks like this: +Some filters take arguments. A filter argument looks like this: ``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the ``bio`` variable. Filter arguments always are in double quotes. @@ -156,7 +152,7 @@ engine that a child template may override those portions of the template. A child template might look like this:: - {% extends "base" %} + {% extends "base.html" %} {% block title %}My amazing blog{% endblock %} @@ -169,12 +165,12 @@ A child template might look like this:: The ``{% extends %}`` tag is the key here. It tells the template engine that this template "extends" another template. When the template system evaluates -this template, first it locates the parent -- in this case, "base" (note the -lack of an ".html" extension in the ``{% extends %}`` tag). +this template, first it locates the parent -- in this case, "base.html". -At that point, the template engine will notice the three blocks in -``base.html`` and replace those blocks with the contents of the child template. -Depending on the value of ``blog_entries``, the output might look like:: +At that point, the template engine will notice the three ``{% block %}`` tags +in ``base.html`` and replace those blocks with the contents of the child +template. Depending on the value of ``blog_entries``, the output might look +like:: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> @@ -205,29 +201,36 @@ Note that since the child template didn't define the ``sidebar`` block, the value from the parent template is used instead. Content within a ``{% block %}`` tag in a parent template is always used as a fallback. -Template inheritance isn't limited to a single level. Multi-level inheritance -is possible and, indeed, quite useful. +You can use as many levels of inheritance as needed. One common way of using +inheritance is the following three-level approach: + + * Create a ``base.html`` template that holds the main look-and-feel of your + site. + * Create a ``base_SECTIONNAME.html`` template for each "section" of your + site. For example, ``base_news.html``, ``base_sports.html``. These + templates all extend ``base.html`` and include section-specific + styles/design. + * Create individual templates for each type of page, such as a news + article or blog entry. These templates extend the appropriate section + template. + +This approach maximizes code reuse and makes it easy to add items to shared +content areas, such as section-wide navigation. Here are some tips for working with inheritance: * If you use ``{% extends %}`` in a template, it must be the first template - tag in that template. + tag in that template. Template inheritance won't work, otherwise. * More ``{% block %}`` tags in your base templates are better. Remember, child templates don't have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, then only define the ones - you need later. + you need later. It's better to have more hooks than fewer hooks. * If you find yourself duplicating content in a number of templates, it probably means you should move that content to a ``{% block %}`` in a parent template. - * The recommended template layout is to use three levels: a single base - template for the entire site, a set of mid-level templates for each - section of the site, and then the individual templates for each view. - This maximizes code reuse and makes it easier to add items to shared - content areas (such as section-wide navigation). - * If you need to get the content of the block from the parent template, the ``{{ block.super }}`` variable will do the trick. This is useful if you want to add to the contents of a parent block instead of @@ -243,17 +246,11 @@ wouldn't know which one of the blocks' content to use. Using the built-in reference ============================ -Because Django can be used to develop any sort of site, the tags, filters and -variables available are different depending on the application. To make it -easy to figure out what's available in a given site, the admin interface has a -complete reference of all the template goodies available to that site. To get -that reference, go to your Django admin interface and append ``'doc'`` onto the -admin URL. Example: ``http://127.0.0.1/admin/doc/``. In the Django development -version, you'll see a "Documentation" link in the upper right of every -admin-site page. +Django's admin interface includes a complete reference of all template tags and +filters available for a given site. To see it, go to your admin interface and +click the "Documentation" link in the upper right of the page. -The reference is integrated into the administration interface for your site(s) -and is divided into 4 sections: tags, filters, models, and views. +The reference is divided into 4 sections: tags, filters, models, and views. The **tags** and **filters** sections describe all the built-in tags (in fact, the tag and filter references below come directly from those pages) as well as @@ -264,13 +261,13 @@ entry here, and clicking on a URL will show you: * The name of the view function that generates that view. * A short description of what the view does. - * The **context**, or a list of variables available in the view. + * The **context**, or a list of variables available in the view's template. * The name of the template or templates that are used for that view. Each view documentation page also has a bookmarklet that you can use to jump from any page to the documentation page for that view. -Because Django generally revolves around database objects, the **models** +Because Django-powered sites usually use database objects, the **models** section of the documentation page describes each type of object in the system along with all the fields available on that object. @@ -304,9 +301,9 @@ available to the current template -- not any parent or child templates along the template-inheritance path. For example, if a template ``foo.html`` has ``{% load comments %}``, a child -template (e.g., one that has ``{% extends foo %}`` will *not* have access to -the comments template tags and filters. The child template is responsible for -its own ``{% load comments %}``. +template (e.g., one that has ``{% extends "foo.html" %}``) will *not* have +access to the comments template tags and filters. The child template is +responsible for its own ``{% load comments %}``. This is a feature for the sake of maintainability and sanity. @@ -366,10 +363,10 @@ extends Signal that this template extends a parent template. -This tag may be used in two ways: ``{% extends "base" %}`` (with quotes) uses -the literal value "base" as the name of the parent template to extend, or ``{% -extends variable %}`` uses the value of ``variable`` as the name of the parent -template to extend. +This tag may be used in two ways: ``{% extends "base.html" %}`` (with quotes) +uses the literal value "base.html" as the name of the parent template to +extend, or ``{% extends variable %}`` uses the value of ``variable`` as the +name of the parent template to extend. See `Template inheritance`_ for more information. @@ -489,7 +486,7 @@ ifchanged Check if a value has changed from the last iteration of a loop. -The 'ifchanged' block tag is used within a loop. It checks its own rendered +The ``ifchanged`` block tag is used within a loop. It checks its own rendered contents against its previous state and only displays its content if the value has changed:: @@ -533,9 +530,9 @@ Loads a template and renders it with the current context. This is a way of The template name can either be a variable or a hard-coded (quoted) string, in either single or double quotes. -This example includes the contents of the template ``"foo/bar"``:: +This example includes the contents of the template ``"foo/bar.html"``:: - {% include "foo/bar" %} + {% include "foo/bar.html" %} This example includes the contents of the template whose name is contained in the variable ``template_name``:: @@ -548,9 +545,9 @@ including it. This example produces the output ``"Hello, John"``: * Context: variable ``person`` is set to ``"john"``. * Template:: - {% include "name_snippet" %} + {% include "name_snippet.html" %} - * The ``name_snippet`` template:: + * The ``name_snippet.html`` template:: Hello, {{ person }} @@ -693,8 +690,6 @@ i.e.:: spaceless ~~~~~~~~~ -**New in Django development version.** - Normalizes whitespace between HTML tags to a single space. This includes tab characters and newlines. @@ -769,7 +764,7 @@ to a maximum value, and then applies that ratio to a constant. For example:: - <img src='bar.gif' height='10' width='{% widthratio this_value max_value 100 %}' /> + <img src="bar.gif" height="10" width="{% widthratio this_value max_value 100 %}" /> Above, if ``this_value`` is 175 and ``max_value`` is 200, the the image in the above example will be 88 pixels wide (because 175/200 = .875; .875 * 100 = 87.5 @@ -844,13 +839,14 @@ Escapes a string's HTML. Specifically, it makes these replacements: * ``"&"`` to ``"&"`` * ``<`` to ``"<"`` * ``>`` to ``">"`` - * ``'"'`` (double quote) to ``"""`` + * ``'"'`` (double quote) to ``'"'`` + * ``"'"`` (single quote) to ``'''`` filesizeformat ~~~~~~~~~~~~~~ -Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102 -bytes, etc). +Format the value like a 'human-readable' file size (i.e. ``'13 KB'``, +``'4.1 MB'``, ``'102 bytes'``, etc). first ~~~~~ @@ -898,12 +894,12 @@ Returns a boolean of whether the value's length is the argument. linebreaks ~~~~~~~~~~ -Converts newlines into <p> and <br />s. +Converts newlines into ``<p>`` and ``<br />``s. linebreaksbr ~~~~~~~~~~~~ -Converts newlines into <br />s. +Converts newlines into ``<br />``s. linenumbers ~~~~~~~~~~~ @@ -941,7 +937,11 @@ any string. pluralize ~~~~~~~~~ -Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'. +Returns ``'s'`` if the value is not 1. + +Example:: + + You have {{ num_messages }} message{{ num_messages|pluralize }}. pprint ~~~~~~ diff --git a/docs/templates_python.txt b/docs/templates_python.txt index b1d968cd47..21ae595624 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -55,13 +55,13 @@ Compiling a string ------------------ The easiest way to create a ``Template`` object is by instantiating it -directly. The class lives at ``django.core.template.Template``. The constructor +directly. The class lives at ``django.template.Template``. The constructor takes one argument -- the raw template code:: - >>> from django.core.template import Template + >>> from django.template import Template >>> t = Template("My name is {{ my_name }}.") >>> print t - <django.core.template.Template instance> + <django.template.Template instance> .. admonition:: Behind the scenes @@ -77,12 +77,12 @@ Rendering a context Once you have a compiled ``Template`` object, you can render a context -- or multiple contexts -- with it. The ``Context`` class lives at -``django.core.template.Context``, and the constructor takes one (optional) +``django.template.Context``, and the constructor takes one (optional) argument: a dictionary mapping variable names to variable values. Call the ``Template`` object's ``render()`` method with the context to "fill" the template:: - >>> from django.core.template import Context, Template + >>> from django.template import Context, Template >>> t = Template("My name is {{ my_name }}.") >>> c = Context({"my_name": "Adrian"}) @@ -110,7 +110,7 @@ logic. Here are a few examples:: - >>> from django.core.template import Context, Template + >>> from django.template import Context, Template >>> t = Template("My name is {{ person.first_name }}.") >>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}} >>> t.render(Context(d)) @@ -139,10 +139,10 @@ Method lookups are slightly more complex than the other lookup types. Here are some things to keep in mind: * If, during the method lookup, a method raises an exception, the exception - will be propagated, unless the exception subclasses - ``django.core.template.SilentVariableFailure``. If the exception - subclasses ``SilentVariableFailure``, the variable will render as an - empty string. Example:: + will be propagated, unless the exception has an attribute + ``silent_variable_failure`` whose value is ``True``. If the exception + *does* have a ``silent_variable_failure`` attribute, the variable will + render as an empty string. Example:: >>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: @@ -154,15 +154,21 @@ some things to keep in mind: ... AssertionError: foo - >>> from django.core.template import SilentVariableFailure - >>> class SilentAssertionError(SilentVariableFailure): pass + >>> class SilentAssertionError(Exception): + ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): - ... raise SilentAssertionError, "foo" + ... raise SilentAssertionError >>> p = PersonClass4() >>> t.render(Context({"person": p})) "My name is ." + Note that ``django.core.exceptions.ObjectDoesNotExist``, which is the + base class for all Django database API ``DoesNotExist`` exceptions, has + ``silent_variable_failure = True``. So if you're using Django templates + with Django model objects, any ``DoesNotExist`` exception will fail + silently. + * A method call will only work if the method has no required arguments. Otherwise, the system will move to the next lookup type (list-index lookup). @@ -203,9 +209,9 @@ This applies to any level of lookup:: >>> t.render(c) "My name is Stan ." -In the Django development version, if a variable doesn't exist, the template -system inserts the value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which -is set to ``''`` (the empty string) by default. +If a variable doesn't exist, the template system inserts the value of the +``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty +string) by default. Playing with Context objects ---------------------------- @@ -227,7 +233,7 @@ dictionary syntax:: A ``Context`` object is a stack. That is, you can ``push()`` and ``pop()`` it. If you ``pop()`` too much, it'll raise -``django.core.template.ContextPopException``:: +``django.template.ContextPopException``:: >>> c = Context() >>> c['foo'] = 'first level' @@ -244,20 +250,20 @@ If you ``pop()`` too much, it'll raise >>> c.pop() Traceback (most recent call last): ... - django.core.template.ContextPopException + django.template.ContextPopException Using a ``Context`` as a stack comes in handy in some custom template tags, as you'll see below. -Subclassing Context: DjangoContext ----------------------------------- +Subclassing Context: RequestContext +----------------------------------- Django comes with a special ``Context`` class, -``django.core.extensions.DjangoContext``, that acts slightly differently than -the normal ``django.core.template.Context``. The first difference is that takes +``django.template.RequestContext``, that acts slightly differently than +the normal ``django.template.Context``. The first difference is that takes an `HttpRequest object`_ as its first argument. For example:: - c = DjangoContext(request, { + c = RequestContext(request, { 'foo': 'bar', } @@ -277,16 +283,16 @@ variable to the context and a second processor adds a variable with the same name, the second will override the first. The default processors are explained below. -Also, you can give ``DjangoContext`` a list of additional processors, using the +Also, you can give ``RequestContext`` a list of additional processors, using the optional, third positional argument, ``processors``. In this example, the -``DjangoContext`` instance gets a ``ip_address`` variable:: +``RequestContext`` instance gets a ``ip_address`` variable:: def ip_address_processor(request): return {'ip_address': request.META['REMOTE_ADDR']} def some_view(request): # ... - return DjangoContext(request, { + return RequestContext(request, { 'foo': 'bar', }, [ip_address_processor]) @@ -299,7 +305,7 @@ django.core.context_processors.auth ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every -``DjangoContext`` will contain these three variables: +``RequestContext`` will contain these three variables: * ``user`` -- An ``auth.User`` instance representing the currently logged-in user (or an ``AnonymousUser`` instance, if the client isn't @@ -317,7 +323,7 @@ django.core.context_processors.debug ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every -``DjangoContext`` will contain these two variables -- but only if your +``RequestContext`` will contain these two variables -- but only if your ``DEBUG`` setting is set to ``True`` and the request's IP address (``request.META['REMOTE_ADDR']``) is in the ``INTERNAL_IPS`` setting: @@ -331,7 +337,7 @@ django.core.context_processors.i18n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every -``DjangoContext`` will contain these two variables: +``RequestContext`` will contain these two variables: * ``LANGUAGES`` -- The value of the `LANGUAGES setting`_. * ``LANGUAGE_CODE`` -- ``request.LANGUAGE_CODE``, if it exists. Otherwise, @@ -346,8 +352,6 @@ See the `internationalization docs`_ for more. django.core.context_processors.request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**New in Django development version** - If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every ``DjangoContext`` will contain a variable ``request``, which is the current `HttpRequest object`_. Note that this processor is not enabled by default; @@ -357,15 +361,8 @@ Loading templates ----------------- Generally, you'll store templates in files on your filesystem rather than using -the low-level ``Template`` API yourself. Save templates in a file with an -".html" extension in a directory specified as a **template directory**. - -If you don't like the requirement that templates have an ".html" extension, -change your ``TEMPLATE_FILE_EXTENSION`` setting. It's set to ``".html"`` by -default. - -Also, the .html extension doesn't mean templates can contain only HTML. They -can contain whatever textual content you want. +the low-level ``Template`` API yourself. Save templates in a directory +specified as a **template directory**. The TEMPLATE_DIRS setting ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -380,7 +377,8 @@ that contain full paths to your template directory(ies). Example:: ) Your templates can go anywhere you want, as long as the directories and -templates are readable by the Web server. +templates are readable by the Web server. They can have any extension you want, +such as ``.html`` or ``.txt``, or they can have no extension at all. Note that these paths should use Unix-style forward slashes, even on Windows. @@ -389,23 +387,24 @@ The Python API Django has two ways to load templates from files: -``django.core.template.loader.get_template(template_name)`` +``django.template.loader.get_template(template_name)`` ``get_template`` returns the compiled template (a ``Template`` object) for the template with the given name. If the template doesn't exist, it raises - ``django.core.template.TemplateDoesNotExist``. + ``django.template.TemplateDoesNotExist``. -``django.core.template.loader.select_template(template_name_list)`` +``django.template.loader.select_template(template_name_list)`` ``select_template`` is just like ``get_template``, except it takes a list of template names. Of the list, it returns the first template that exists. -For example, if you call ``get_template("story_detail")`` and have the above -``TEMPLATE_DIRS`` setting, here are the files Django will look for, in order: +For example, if you call ``get_template('story_detail.html')`` and have the +above ``TEMPLATE_DIRS`` setting, here are the files Django will look for, in +order: * ``/home/html/templates/lawrence.com/story_detail.html`` * ``/home/html/templates/default/story_detail.html`` -If you call ``select_template(["story_253_detail", "story_detail"])``, here's -what Django will look for: +If you call ``select_template(['story_253_detail.html', 'story_detail.html'])``, +here's what Django will look for: * ``/home/html/templates/lawrence.com/story_253_detail.html`` * ``/home/html/templates/default/story_253_detail.html`` @@ -416,10 +415,10 @@ When Django finds a template that exists, it stops looking. .. admonition:: Tip - You can use ``select_template`` for super-flexible "templatability." For + You can use ``select_template()`` for super-flexible "templatability." For example, if you've written a news story and want some stories to have custom templates, use something like - ``select_template(["story_%s_detail" % story.id, "story_detail"])``. + ``select_template(['story_%s_detail.html' % story.id, 'story_detail.html'])``. That'll allow you to use a custom template for an individual story, with a fallback template for stories that don't have custom templates. @@ -435,21 +434,30 @@ single directory gets messy. To load a template that's within a subdirectory, just use a slash, like so:: - get_template("news/story_detail") + get_template('news/story_detail.html') + +Using the same ``TEMPLATE_DIRS`` setting from above, this example +``get_template()`` call will attempt to load the following templates: + + * ``/home/html/templates/lawrence.com/news/story_detail.html`` + * ``/home/html/templates/default/news/story_detail.html`` Loader types ~~~~~~~~~~~~ By default, Django uses a filesystem-based template loader, but Django comes -with a few other template loaders. They're disabled by default, but you can -activate them by editing your ``TEMPLATE_LOADERS`` setting. -``TEMPLATE_LOADERS`` should be a tuple of strings, where each string represents -a template loader. Here are the built-in template loaders: +with a few other template loaders, which know how to load templates from other +sources. + +These other loaders are disabled by default, but you can activate them by +editing your ``TEMPLATE_LOADERS`` setting. ``TEMPLATE_LOADERS`` should be a +tuple of strings, where each string represents a template loader. Here are the +template loaders that come with Django: -``django.core.template.loaders.filesystem.load_template_source`` +``django.template.loaders.filesystem.load_template_source`` Loads templates from the filesystem, according to ``TEMPLATE_DIRS``. -``django.core.template.loaders.app_directories.load_template_source`` +``django.template.loaders.app_directories.load_template_source`` Loads templates from Django apps on the filesystem. For each app in ``INSTALLED_APPS``, the loader looks for a ``templates`` subdirectory. If the directory exists, Django looks for templates in there. @@ -461,7 +469,7 @@ a template loader. Here are the built-in template loaders: INSTALLED_APPS = ('myproject.polls', 'myproject.music') - ...then ``get_template("foo")`` will look for templates in these + ...then ``get_template('foo.html')`` will look for templates in these directories, in this order: * ``/path/to/myproject/polls/templates/foo.html`` @@ -471,7 +479,7 @@ a template loader. Here are the built-in template loaders: It caches a list of which ``INSTALLED_APPS`` packages have a ``templates`` subdirectory. -``django.core.template.loaders.eggs.load_template_source`` +``django.template.loaders.eggs.load_template_source`` Just like ``app_directories`` above, but it loads templates from Python eggs rather than from the filesystem. @@ -521,15 +529,15 @@ To be a valid tag library, the module contain a module-level variable named ``register`` that is a ``template.Library`` instance, in which all the tags and filters are registered. So, near the top of your module, put the following:: - from django.core import template + from django import template register = template.Library() .. admonition:: Behind the scenes For a ton of examples, read the source code for Django's default filters - and tags. They're in ``django/core/template/defaultfilters.py`` and - ``django/core/template/defaulttags.py``, respectively. + and tags. They're in ``django/template/defaultfilters.py`` and + ``django/template/defaulttags.py``, respectively. Writing custom template filters ------------------------------- @@ -603,7 +611,7 @@ process: compiling and rendering. To define a custom template tag, you specify how the compilation works and how the rendering works. When Django compiles a template, it splits the raw template text into -''nodes''. Each node is an instance of ``django.core.template.Node`` and has +''nodes''. Each node is an instance of ``django.template.Node`` and has a ``render()`` method. A compiled template is, simply, a list of ``Node`` objects. When you call ``render()`` on a compiled template object, the template calls ``render()`` on each ``Node`` in its node list, with the given context. @@ -632,7 +640,7 @@ else. In our case, let's say the tag should be used like this:: The parser for this function should grab the parameter and create a ``Node`` object:: - from django.core import template + from django import template def do_current_time(parser, token): try: # Splitting by None == splitting by spaces. @@ -652,7 +660,7 @@ Notes: example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``. * This function is responsible for raising - ``django.core.template.TemplateSyntaxError``, with helpful messages, for + ``django.template.TemplateSyntaxError``, with helpful messages, for any syntax error. * The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable. @@ -679,7 +687,7 @@ has a ``render()`` method. Continuing the above example, we need to define ``CurrentTimeNode``:: - from django.core import template + from django import template import datetime class CurrentTimeNode(template.Node): def __init__(self, format_string): @@ -817,7 +825,7 @@ Here's how the standard ``{% comment %}`` tag is implemented:: return '' ``parser.parse()`` takes a tuple of names of block tags ''to parse until''. It -returns an instance of ``django.core.template.NodeList``, which is a list of +returns an instance of ``django.template.NodeList``, which is a list of all ``Node`` objects that the parser encountered ''before'' it encountered any of the tags named in the tuple. @@ -867,4 +875,4 @@ The only new concept here is the ``self.nodelist.render(context)`` in For more examples of complex rendering, see the source code for ``{% if %}``, ``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in -``django/core/template/defaulttags.py``. +``django/template/defaulttags.py``. diff --git a/docs/transactions.txt b/docs/transactions.txt new file mode 100644 index 0000000000..6b2e6fda8f --- /dev/null +++ b/docs/transactions.txt @@ -0,0 +1,146 @@ +============================== +Managing database transactions +============================== + +Django gives you a few ways to control how database transactions are managed. + +Django's default transaction behavior +===================================== + +Django's default behavior is to commit automatically when any built-in, +data-altering model function is called. For example, if you call +``model.save()`` or ``model.delete()``, the change will be committed +immediately. + +This is much like the auto-commit setting for most databases. As soon as you +perform an action that needs to write to the database, Django produces the +``INSERT``/``UPDATE``/``DELETE`` statements and then does the ``COMMIT``. +There's no implicit ``ROLLBACK``. + +Tying transactions to HTTP requests +=================================== + +The recommended way to handle transactions in Web requests is to tie them to +the request and response phases via Django's ``TransactionMiddleware``. + +It works like this: When a request starts, Django starts a transaction. If the +response is produced without problems, Django commits any pending transactions. +If the view function produces an exception, Django rolls back any pending +transactions. + +To activate this feature, just add the ``TransactionMiddleware`` middleware to +your ``MIDDLEWARE_CLASSES`` setting:: + + MIDDLEWARE_CLASSES = ( + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.cache.CacheMiddleware", + "django.middleware.transaction.TransactionMiddleware", + ) + +The order is quite important. The transaction middleware applies not only to +view functions, but also for all middleware modules that come after it. So if +you use the session middleware after the transaction middleware, session +creation will be part of the transaction. + +An exception is ``CacheMiddleware``, which is never affected. The cache +middleware uses its own database cursor (which is mapped to its own database +connection internally). + +Controlling transaction management in views +=========================================== + +For most people, implicit request-based transactions work wonderfully. However, +if you need more fine-grained control over how transactions are managed, you +can use Python decorators to change the way transactions are handled by a +particular view function. + +.. note:: + + Although the examples below use view functions as examples, these + decorators can be applied to non-view functions as well. + +``django.db.transaction.autocommit`` +------------------------------------ + +Use the ``autocommit`` decorator to switch a view function to Django's default +commit behavior, regardless of the global transaction setting. + +Example:: + + from django.db import transaction + + @transaction.autocommit + def viewfunc(request): + .... + +Within ``viewfunc()``, transactions will be committed as soon as you call +``model.save()``, ``model.delete()``, or any other function that writes to the +database. + +``django.db.transaction.commit_on_success`` +------------------------------------------- + +Use the ``commit_on_success`` decorator to use a single transaction for +all the work done in a function:: + + from django.db import transaction + + @transaction.commit_on_success + def viewfunc(request): + .... + +If the function returns successfully, then Django will commit all work done +within the function at that point. If the function raises an exception, though, +Django will roll back the transaction. + +``django.db.transaction.commit_manually`` +----------------------------------------- + +Use the ``commit_manually`` decorator if you need full control over +transactions. It tells Django you'll be managing the transaction on your own. + +If your view changes data and doesn't ``commit()`` or ``rollback()``, Django +will raise a ``TransactionManagementError`` exception. + +Manual transaction management looks like this:: + + from django.db import transaction + + @transaction.commit_manually + def viewfunc(request): + ... + # You can commit/rollback however and whenever you want + transaction.commit() + ... + + # But you've got to remember to do it yourself! + try: + ... + except: + transaction.rollback() + else: + transaction.commit() + +..admonition:: An important note to users of earlier Django releases: + + The database ``connection.commit()`` and ``connection.rollback()`` methods + (called ``db.commit()`` and ``db.rollback()`` in 0.91 and earlier) no longer + exist. They've been replaced by ``transaction.commit()`` and + ``transaction.rollback()``. + +How to globally deactivate transaction management +================================================= + +Control freaks can totally disable all transaction management by setting +``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file. + +If you do this, Django won't provide any automatic transaction management +whatsoever. Middleware will no longer implicitly commit transactions, and +you'll need to roll management yourself. This even requires you to commit +changes done by middleware somewhere else. + +Thus, this is best used in situations where you want to run your own +transaction-controlling middleware or do something really strange. In almost +all situations, you'll be better off using the default behavior, or the +transaction middleware, and only modify selected functions as needed. diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt index 67b4053ef5..02d2795261 100644 --- a/docs/tutorial01.txt +++ b/docs/tutorial01.txt @@ -2,35 +2,41 @@ Writing your first Django app, part 1 ===================================== -By Adrian Holovaty <holovaty@gmail.com> - Let's learn by example. -Throughout this tutorial, we'll walk you through the creation of a simple Web -poll application. +Throughout this tutorial, we'll walk you through the creation of a basic +blogging application. It'll consist of two parts: -* A public site that lets people vote in polls and view poll results. -* An admin site that lets you add, change and delete polls behind the scenes. + * A public site that lets people read your blog entries and submit + comments. + * An admin site that lets you add, change and delete entries and comments. -We'll assume you have `Django installed`_ already. +We'll assume you have `Django installed`_ already. You can tell Django is +installed by running the Python interactive interpreter and typing +``import django``. If that command runs successfully, with no errors, Django is +installed. .. _`Django installed`: http://www.djangoproject.com/documentation/install/ -Initial setup -============= +Creating a project +================== If this is your first time using Django, you'll have to take care of some -initial setup. +initial setup. Namely, you'll need to auto-generate some code that establishes +a Django *project* -- a collection of settings for an instance of Django, +including database configuration, Django-specific options and +application-specific settings. -Run the command ``django-admin.py startproject myproject``. That'll create a -``myproject`` directory in your current directory. +From the command line, ``cd`` into a directory where you'd like to store your +code, then run the command ``django-admin.py startproject mysite``. This +will create a ``mysite`` directory in your current directory. (``django-admin.py`` should be on your system path if you installed Django via -its setup.py utility. If it's not on your path, you can find it in +its ``setup.py`` utility. If it's not on your path, you can find it in ``site-packages/django/bin``; consider symlinking to it from some place -on your path, such as /usr/local/bin.) +on your path, such as ``/usr/local/bin``.) .. admonition:: Where should this code live? @@ -44,11 +50,9 @@ on your path, such as /usr/local/bin.) Put your code in some directory **outside** of the document root, such as ``/home/mycode``. -A project is a collection of settings for an instance of Django -- including -database configuration, Django-specific options and application-specific -settings. Let's look at what ``startproject`` created:: +Let's look at what ``startproject`` created:: - myproject/ + mysite/ __init__.py manage.py settings.py @@ -56,50 +60,62 @@ settings. Let's look at what ``startproject`` created:: These files are: + * ``__init__.py``: An empty file that tells Python that this directory + should be considered a Python package. (Read `more about packages`_ in the + official Python docs if you're a Python beginner.) * ``manage.py``: A command-line utility that lets you interact with this Django project in various ways. * ``settings.py``: Settings/configuration for this Django project. * ``urls.py``: The URL declarations for this Django project; a "table of contents" of your Django-powered site. +.. _more on packages: http://docs.python.org/tut/node8.html#packages + The development server ---------------------- -Change into the ``myproject`` directory, if you haven't already, and run the -command ``python manage.py runserver``. You'll see the following output on the -command line:: +Let's verify this worked. Change into the ``mysite`` directory, if you +haven't already, and run the command ``python manage.py runserver``. You'll see +the following output on the command line:: Validating models... 0 errors found. - Starting server on port 8000 with settings module 'myproject.settings'. - Go to http://127.0.0.1:8000/ for Django. + Django version 0.92, using settings 'mysite.settings' + Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). -(If you get an error about ``DATABASE_ENGINE``, edit your ``settings.py`` file -to change the ``DATABASE_ENGINE`` setting to point to the correct database, and -make sure you have the right database libraries installed -- such as PostgreSQL's -psycopg or MySQL's MySQLdb.) - You've started the Django development server, a lightweight, pure-Python Web -server that builds on the BaseHTTPServer included in Python's standard library. -We've included this with Django so you can develop things rapidly, without -having to deal with configuring Apache until you're ready for production. +server. We've included this with Django so you can develop things rapidly, +without having to deal with configuring a production server -- such as +Apache -- until you're ready for production. + +Now's a good time to note: DON'T use this server in anything resembling a +production environment. It's intended only for use while developing. -DON'T use this server in anything resembling a production environment. It's -intended only for use while developing. +Now that the server's running, visit http://127.0.0.1:8000/ with your Web +browser. You'll see a "Welcome to Django" page, in pleasant, light-blue pastel. +It worked! .. admonition:: Changing the port By default, the ``runserver`` command starts the development server on port 8000. If you want to change the server's port, pass it as a command-line - argument:: + argument. For instance, this command starts the server on port 8080:: python manage.py runserver 8080 -Now that the server's running, visit http://127.0.0.1:8000/ with your Web -browser. You'll see a "Welcome to Django" page, in pleasant, light-blue pastel. -It worked! + Full docs for the development server are at `django-admin documentation`_. + +.. _django-admin documentation: http://www.djangoproject.com/documentation/django_admin/ + +Your first page +--------------- + +Let's create our first Django-powered Web page, a classic "hello world" example. + + + Database setup -------------- @@ -124,30 +140,52 @@ database's connection parameters: point. Do that with "``CREATE DATABASE database_name;``" within your database's interactive prompt. -Run the following command to initialize your database with Django's core -database tables:: +While you're editing ``settings.py``, take note of the ``INSTALLED_APPS`` +setting towards the bottom of the file. That variable holds the names of all +Django applications that are activated in this Django instance. Apps can be +used in multiple projects, and you can package and distribute them for use +by others in their projects. + +By default, ``INSTALLED_APPS`` contains the following apps, all of which come +with Django: + + * ``django.contrib.auth`` -- An authentication system. + * ``django.contrib.contenttypes`` -- A framework for content types. + * ``django.contrib.sessions`` -- A session framework. + * ``django.contrib.sites`` -- A framework for managing multiple sites + with one Django installation. + +These applications are included by default as a convenience for the common case. - python manage.py init +Each of these applications makes use of at least one database table, though, +so we need to create the tables in the database before we can use them. To do +that, run the following command:: -If you don't see any errors, it worked. + python manage.py syncdb + +The ``syncdb`` command looks at the ``INSTALLED_APPS`` setting and creates any +necessary database tables according to the database settings in your +``settings.py`` file. You'll see a message for each database table it creates, +and you'll get a prompt asking you if you'd like to create a superuser account +for the authentication system. Go ahead and do that. If you're interested, run the command-line client for your database and type ``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to display the tables Django created. -.. admonition:: About those database tables +.. admonition:: For the minimalists - The tables created by ``manage.py init`` are for sessions, authentication - and other features Django provides. The next release of Django will have - a "lite" version of the ``init`` command that won't install any database - tables if you don't want them. + Like we said above, the default applications are included for the common + case, but not everybody needs them. If you don't need any or all of them, + feel free to comment-out or delete the appropriate line(s) from + ``INSTALLED_APPS`` before running ``syncdb``. The ``syncdb`` command will + only create tables for apps in ``INSTALLED_APPS``. Creating models =============== Now that your environment -- a "project" -- is set up, you're set to start -doing work. (You won't have to take care of that boring administrative stuff -again.) +doing work. Each application you write in Django consists of a Python package, somewhere on your `Python path`_, that follows a certain convention. Django comes with a @@ -162,12 +200,12 @@ so you can focus on writing code rather than creating directories. configuration and apps for a particular Web site. A project can contain multiple apps. An app can be in multiple projects. -In this tutorial, we'll create our poll app in the ``myproject`` directory, +In this tutorial, we'll create our poll app in the ``mysite`` directory, for simplicity. As a consequence, the app will be coupled to the project -- -that is, Python code within the poll app will refer to ``myproject.polls``. +that is, Python code within the poll app will refer to ``mysite.polls``. Later in this tutorial, we'll discuss decoupling your apps for distribution. -To create your app, make sure you're in the ``myproject`` directory and type +To create your app, make sure you're in the ``mysite`` directory and type this command:: python manage.py startapp polls @@ -176,9 +214,7 @@ That'll create a directory ``polls``, which is laid out like this:: polls/ __init__.py - models/ - __init__.py - polls.py + models.py views.py This directory structure will house the poll application. @@ -198,28 +234,28 @@ a question and a publication date. A choice has two fields: the text of the choice and a vote tally. Each choice is associated with a poll. These concepts are represented by simple Python classes. Edit the -``polls/models/polls.py`` file so it looks like this:: +``polls/models.py`` file so it looks like this:: - from django.core import meta + from django.db import models - class Poll(meta.Model): - question = meta.CharField(maxlength=200) - pub_date = meta.DateTimeField('date published') + class Poll(models.Model): + question = models.CharField(maxlength=200) + pub_date = models.DateTimeField('date published') - class Choice(meta.Model): - poll = meta.ForeignKey(Poll) - choice = meta.CharField(maxlength=200) - votes = meta.IntegerField() + class Choice(models.Model): + poll = models.ForeignKey(Poll) + choice = models.CharField(maxlength=200) + votes = models.IntegerField() The code is straightforward. Each model is represented by a class that -subclasses ``django.core.meta.Model``. Each model has a number of class +subclasses ``django.db.models.Model``. Each model has a number of class variables, each of which represents a database field in the model. -Each field is represented by an instance of a ``meta.*Field`` class -- e.g., -``meta.CharField`` for character fields and ``meta.DateTimeField`` for +Each field is represented by an instance of a ``models.*Field`` class -- e.g., +``models.CharField`` for character fields and ``models.DateTimeField`` for datetimes. This tells Django what type of data each field holds. -The name of each ``meta.*Field`` instance (e.g. ``question`` or ``pub_date`` ) +The name of each ``models.*Field`` instance (e.g. ``question`` or ``pub_date`` ) is the field's name, in machine-friendly format. You'll use this value in your Python code, and your database will use it as the column name. @@ -230,11 +266,11 @@ the machine-readable name. In this example, we've only defined a human-readable name for ``Poll.pub_date``. For all other fields in this model, the field's machine-readable name will suffice as its human-readable name. -Some ``meta.*Field`` classes have required elements. ``meta.CharField``, for -example, requires that you give it a ``maxlength``. That's used not only in the -database schema, but in validation, as we'll soon see. +Some ``Field`` classes have required elements. ``CharField``, for example, +requires that you give it a ``maxlength``. That's used not only in the database +schema, but in validation, as we'll soon see. -Finally, note a relationship is defined, using ``meta.ForeignKey``. That tells +Finally, note a relationship is defined, using ``models.ForeignKey``. That tells Django each Choice is related to a single Poll. Django supports all the common database relationships: many-to-ones, many-to-manys and one-to-ones. @@ -259,28 +295,29 @@ But first we need to tell our project that the ``polls`` app is installed. Django installation. Edit the ``settings.py`` file again, and change the ``INSTALLED_APPS`` setting -to include the string ``'myproject.polls'``. So it'll look like this:: +to include the string ``'mysite.polls'``. So it'll look like this:: INSTALLED_APPS = ( - 'myproject.polls', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'mysite.polls' ) -(Don't forget the trailing comma, because of Python's rule about single-value -tuples: Without a trailing comma, Python wouldn't know this was a tuple.) - -Now Django knows ``myproject`` includes the ``polls`` app. Let's run another command:: +Now Django knows ``mysite`` includes the ``polls`` app. Let's run another command:: python manage.py sql polls You should see the following (the CREATE TABLE SQL statements for the polls app):: BEGIN; - CREATE TABLE "polls_polls" ( + CREATE TABLE "polls_poll" ( "id" serial NOT NULL PRIMARY KEY, "question" varchar(200) NOT NULL, "pub_date" timestamp with time zone NOT NULL ); - CREATE TABLE "polls_choices" ( + CREATE TABLE "polls_choice" ( "id" serial NOT NULL PRIMARY KEY, "poll_id" integer NOT NULL REFERENCES "polls_polls" ("id"), "choice" varchar(200) NOT NULL, @@ -291,12 +328,12 @@ You should see the following (the CREATE TABLE SQL statements for the polls app) Note the following: * Table names are automatically generated by combining the name of the app - (``polls``) with a plural version of the object name (polls and choices). - (You can override this behavior.) + (``polls``) and the lowercase name of the model -- ``poll`` and + ``choice``. (You can override this behavior.) * Primary keys (IDs) are added automatically. (You can override this, too.) - * Django appends ``"_id"`` to the foreign key field name, by convention. + * By convention, Django appends ``"_id"`` to the foreign key field name. Yes, you can override this, as well. * The foreign key relationship is made explicit by a ``REFERENCES`` statement. @@ -306,12 +343,18 @@ Note the following: ``integer primary key`` (SQLite) are handled for you automatically. Same goes for quoting of field names -- e.g., using double quotes or single quotes. The author of this tutorial runs PostgreSQL, so the example - output is inPostgreSQL syntax. + output is in PostgreSQL syntax. + + * The `sql` command doesn't actually run the SQL in your database - it just + prints it to the screen so that you can see what SQL Django thinks is required. + If you wanted to, you could copy and paste this SQL into your database prompt. + However, as we will see shortly, Django provides an easier way of committing + the SQL to the database. If you're interested, also run the following commands: - * ``python manage.py sqlinitialdata polls`` -- Outputs the initial-data - inserts required for Django's admin framework. + * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data + required for Django's admin framework and your models. * ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP TABLE`` statements for this app, according to which tables already exist @@ -320,20 +363,21 @@ If you're interested, also run the following commands: * ``python manage.py sqlindexes polls`` -- Outputs the ``CREATE INDEX`` statements for this app. - * ``python manage.py sqlall polls`` -- A combination of 'sql' and - 'sqlinitialdata'. + * ``python manage.py sqlall polls`` -- A combination of all the SQL from + the 'sql', 'sqlinitialdata', and 'sqlindexes' commands. Looking at the output of those commands can help you understand what's actually happening under the hood. -Now, run this command to create the database tables for the polls app -automatically:: +Now, run ``syncdb`` again to create those model tables in your database:: - python manage.py install polls + python manage.py syncdb -Behind the scenes, all that command does is take the output of -``python manage.py sqlall polls`` and execute it in the database pointed-to by -your Django settings file. +The ``syncdb`` command runs the sql from 'sqlall' on your database for all apps +in ``INSTALLED_APPS`` that don't already exist in your database. This creates +all the tables, initial data and indexes for any apps you have added to your +project since the last time you ran syncdb. ``syncdb`` can be called as often +as you like, and it will only ever create the tables that don't exist. Read the `django-admin.py documentation`_ for full information on what the ``manage.py`` utility can do. @@ -352,10 +396,10 @@ We're using this instead of simply typing "python", because ``manage.py`` sets up the project's environment for you. "Setting up the environment" involves two things: - * Putting ``myproject`` on ``sys.path``. For flexibility, several pieces of + * Putting ``mysite`` on ``sys.path``. For flexibility, several pieces of Django refer to projects in Python dotted-path notation (e.g. - ``'myproject.polls.models'``). In order for this to work, the - ``myproject`` package has to be on ``sys.path``. + ``'mysite.polls.models'``). In order for this to work, the + ``mysite`` package has to be on ``sys.path``. We've already seen one example of this: the ``INSTALLED_APPS`` setting is a list of packages in dotted-path notation. @@ -366,25 +410,24 @@ things: .. admonition:: Bypassing manage.py If you'd rather not use ``manage.py``, no problem. Just make sure - ``myproject`` is at the root level on the Python path (i.e., - ``import myproject`` works) and set the ``DJANGO_SETTINGS_MODULE`` - environment variable to ``myproject.settings``. + ``mysite`` is at the root level on the Python path (i.e., + ``import mysite`` works) and set the ``DJANGO_SETTINGS_MODULE`` + environment variable to ``mysite.settings``. For more information on all of this, see the `django-admin.py documentation`_. Once you're in the shell, explore the database API:: - # Modules are dynamically created within django.models. - # Their names are plural versions of the model class names. - >>> from django.models.polls import polls, choices + # Import the model classes we just wrote. + >>> from mysite.polls.models import Poll, Choice # No polls are in the system yet. - >>> polls.get_list() + >>> Poll.objects.all() [] # Create a new Poll. >>> from datetime import datetime - >>> p = polls.Poll(question="What's up?", pub_date=datetime.now()) + >>> p = Poll(question="What's up?", pub_date=datetime.now()) # Save the object into the database. You have to call save() explicitly. >>> p.save() @@ -406,107 +449,109 @@ Once you're in the shell, explore the database API:: >>> p.pub_date = datetime(2005, 4, 1, 0, 0) >>> p.save() - # get_list() displays all the polls in the database. - >>> polls.get_list() + # objects.all() displays all the polls in the database. + >>> Poll.objects.all() [<Poll object>] + Wait a minute. ``<Poll object>`` is, utterly, an unhelpful representation of this object. Let's fix that by editing the polls model -(in the ``polls/models/polls.py`` file) and adding a ``__repr__()`` method to +(in the ``polls/models.py`` file) and adding a ``__str__()`` method to both ``Poll`` and ``Choice``:: - class Poll(meta.Model): + class Poll(models.Model): # ... - def __repr__(self): + def __str__(self): return self.question - class Choice(meta.Model): + class Choice(models.Model): # ... - def __repr__(self): + def __str__(self): return self.choice -It's important to add ``__repr__()`` methods to your models, not only for your +It's important to add ``__str__()`` methods to your models, not only for your own sanity when dealing with the interactive prompt, but also because objects' representations are used throughout Django's automatically-generated admin. Note these are normal Python methods. Let's add a custom method, just for demonstration:: - class Poll(meta.Model): + import datetime + # ... + class Poll(models.Model): # ... def was_published_today(self): return self.pub_date.date() == datetime.date.today() -Note ``import datetime`` wasn't necessary. Each model method has access to -a handful of commonly-used variables for convenience, including the -``datetime`` module from the Python standard library. +Note the addition of ``import datetime`` to reference Python's standard +``datetime`` module. Let's jump back into the Python interactive shell by running ``python manage.py shell`` again:: - >>> from django.models.polls import polls, choices - # Make sure our __repr__() addition worked. - >>> polls.get_list() + >>> from mysite.polls.models import Poll, Choice + + # Make sure our __str__() addition worked. + >>> Poll.objects.all() [What's up?] # Django provides a rich database lookup API that's entirely driven by # keyword arguments. - >>> polls.get_object(id__exact=1) - What's up? - >>> polls.get_object(question__startswith='What') - What's up? + >>> Poll.objects.filter(id=1) + [What's up?] + >>> Poll.objects.filter(question__startswith='What') + [What's up?] # Get the poll whose year is 2005. Of course, if you're going through this # tutorial in another year, change as appropriate. - >>> polls.get_object(pub_date__year=2005) + >>> Poll.objects.get(pub_date__year=2005) What's up? - >>> polls.get_object(id__exact=2) + >>> Poll.objects.get(id=2) Traceback (most recent call last): ... - PollDoesNotExist: Poll does not exist for {'id__exact': 2} - >>> polls.get_list(question__startswith='What') - [What's up?] + DoesNotExist: Poll does not exist for {'id': 2} # Lookup by a primary key is the most common case, so Django provides a # shortcut for primary-key exact lookups. - # The following is identical to polls.get_object(id__exact=1). - >>> polls.get_object(pk=1) + # The following is identical to Poll.objects.get(id=1). + >>> Poll.objects.get(pk=1) What's up? # Make sure our custom method worked. - >>> p = polls.get_object(pk=1) + >>> p = Poll.objects.get(pk=1) >>> p.was_published_today() False - # Give the Poll a couple of Choices. Each one of these method calls does an - # INSERT statement behind the scenes and returns the new Choice object. - >>> p = polls.get_object(pk=1) - >>> p.add_choice(choice='Not much', votes=0) + # Give the Poll a couple of Choices. The create call constructs a new + # choice object, does the INSERT statement, adds the choice to the set + # of available choices and returns the new Choice object. + >>> p = Poll.objects.get(pk=1) + >>> p.choice_set.create(choice='Not much', votes=0) Not much - >>> p.add_choice(choice='The sky', votes=0) + >>> p.choice_set.create(choice='The sky', votes=0) The sky - >>> c = p.add_choice(choice='Just hacking again', votes=0) + >>> c = p.choice_set.create(choice='Just hacking again', votes=0) # Choice objects have API access to their related Poll objects. - >>> c.get_poll() + >>> c.poll What's up? # And vice versa: Poll objects get access to Choice objects. - >>> p.get_choice_list() + >>> p.choice_set.all() [Not much, The sky, Just hacking again] - >>> p.get_choice_count() + >>> p.choice_set.count() 3 # The API automatically follows relationships as far as you need. # Use double underscores to separate relationships. # This works as many levels deep as you want. There's no limit. # Find all Choices for any poll whose pub_date is in 2005. - >>> choices.get_list(poll__pub_date__year=2005) + >>> Choice.objects.filter(poll__pub_date__year=2005) [Not much, The sky, Just hacking again] # Let's delete one of the choices. Use delete() for that. - >>> c = p.get_choice(choice__startswith='Just hacking') + >>> c = p.choice_set.filter(choice__startswith='Just hacking') >>> c.delete() For full details on the database API, see our `Database API reference`_. diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt index e96be12020..6cdda32fbb 100644 --- a/docs/tutorial02.txt +++ b/docs/tutorial02.txt @@ -2,8 +2,6 @@ Writing your first Django app, part 2 ===================================== -By Adrian Holovaty <holovaty@gmail.com> - This tutorial begins where `Tutorial 1`_ left off. We're continuing the Web-poll application and will focus on Django's automatically-generated admin site. @@ -31,22 +29,13 @@ The Django admin site is not activated by default -- it's an opt-in thing. To activate the admin site for your installation, do these three things: * Add ``"django.contrib.admin"`` to your ``INSTALLED_APPS`` setting. - * Run the command ``python manage.py install admin``. This will create an - extra database table that the admin needs. - * Edit your ``myproject/urls.py`` file and uncomment the line below + * Run ``python manage.py syncdb``. Since you have added a new application + to ``INSTALLED_APPS``, the database tables need to be updated. + * Edit your ``mysite/urls.py`` file and uncomment the line below "Uncomment this for admin:". This file is a URLconf; we'll dig into URLconfs in the next tutorial. For now, all you need to know is that it maps URL roots to applications. -Create a user account -===================== - -Run the following command to create a superuser account for your admin site:: - - python manage.py createsuperuser - -The script will prompt you for a username, e-mail address and password (twice). - Start the development server ============================ @@ -82,26 +71,27 @@ Make the poll app modifiable in the admin But where's our poll app? It's not displayed on the admin index page. Just one thing to do: We need to specify in the ``Poll`` model that ``Poll`` -objects have an admin interface. Edit the ``myproject/polls/models/polls.py`` -file and make the following change to add an inner ``META`` class with an -``admin`` attribute:: +objects have an admin interface. Edit the ``mysite/polls/models/polls.py`` +file and make the following change to add an inner ``Admin`` class:: - class Poll(meta.Model): + class Poll(models.Model): # ... - class META: - admin = meta.Admin() + class Admin: + pass -The ``class META`` contains all `non-field metadata`_ about this model. +The ``class Admin`` will contain all the settings that control how this model +appears in the Django admin. All the settings are optional, however, so +creating an empty class means "give this object an admin interface using +all the default options." Now reload the Django admin page to see your changes. Note that you don't have -to restart the development server -- it auto-reloads code. - -.. _non-field metadata: http://www.djangoproject.com/documentation/model_api/#meta-options +to restart the development server -- the server will auto-reloads your project, +so any modifications code will be seen immediately in your browser. Explore the free admin functionality ==================================== -Now that ``Poll`` has the ``admin`` attribute, Django knows that it should be +Now that ``Poll`` has the inner ``Admin`` class, Django knows that it should be displayed on the admin index page: .. image:: http://media.djangoproject.com/img/doc/tutorial/admin03t.png @@ -125,7 +115,7 @@ Click the "What's up?" poll to edit it: Things to note here: * The form is automatically generated from the Poll model. -* The different model field types (``meta.DateTimeField``, ``meta.CharField``) +* The different model field types (``models.DateTimeField``, ``models.CharField``) correspond to the appropriate HTML input widget. Each type of field knows how to display itself in the Django admin. * Each ``DateTimeField`` gets free JavaScript shortcuts. Dates get a "Today" @@ -157,13 +147,12 @@ Customize the admin form Take a few minutes to marvel at all the code you didn't have to write. Let's customize this a bit. We can reorder the fields by explicitly adding a -``fields`` parameter to ``meta.Admin``:: +``fields`` parameter to ``Admin``:: - admin = meta.Admin( + class Admin: fields = ( (None, {'fields': ('pub_date', 'question')}), - ), - ) + ) That made the "Publication date" show up first instead of second: @@ -176,12 +165,11 @@ of fields, choosing an intuitive order is an important usability detail. And speaking of forms with dozens of fields, you might want to split the form up into fieldsets:: - admin = meta.Admin( + class Admin: fields = ( (None, {'fields': ('question',)}), ('Date information', {'fields': ('pub_date',)}), - ), - ) + ) The first element of each tuple in ``fields`` is the title of the fieldset. Here's what our form looks like now: @@ -195,12 +183,11 @@ You can assign arbitrary HTML classes to each fieldset. Django provides a This is useful when you have a long form that contains a number of fields that aren't commonly used:: - admin = meta.Admin( + class Admin: fields = ( (None, {'fields': ('question',)}), ('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}), - ), - ) + ) .. image:: http://media.djangoproject.com/img/doc/tutorial/admin09.png :alt: Fieldset is initially collapsed @@ -214,13 +201,13 @@ the admin page doesn't display choices. Yet. There are two ways to solve this problem. The first is to give the ``Choice`` -model its own ``admin`` attribute, just as we did with ``Poll``. Here's what +model its own inner ``Admin`` class, just as we did with ``Poll``. Here's what that would look like:: - class Choice(meta.Model): + class Choice(models.Model): # ... - class META: - admin = meta.Admin() + class Admin: + pass Now "Choices" is an available option in the Django admin. The "Add choice" form looks like this: @@ -242,18 +229,18 @@ But, really, this is an inefficient way of adding Choice objects to the system. It'd be better if you could add a bunch of Choices directly when you create the Poll object. Let's make that happen. -Remove the ``admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)`` +Remove the ``Admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)`` field like so:: - poll = meta.ForeignKey(Poll, edit_inline=meta.STACKED, num_in_admin=3) + poll = models.ForeignKey(Poll, edit_inline=models.STACKED, num_in_admin=3) This tells Django: "Choice objects are edited on the Poll admin page. By default, provide enough fields for 3 Choices." Then change the other fields in ``Choice`` to give them ``core=True``:: - choice = meta.CharField(maxlength=200, core=True) - votes = meta.IntegerField(core=True) + choice = models.CharField(maxlength=200, core=True) + votes = models.IntegerField(core=True) This tells Django: "When you edit a Choice on the Poll admin page, the 'choice' and 'votes' fields are required. The presence of at least one of them signifies @@ -277,9 +264,9 @@ One small problem, though. It takes a lot of screen space to display all the fields for entering related Choice objects. For that reason, Django offers an alternate way of displaying inline related objects:: - poll = meta.ForeignKey(Poll, edit_inline=meta.TABULAR, num_in_admin=3) + poll = models.ForeignKey(Poll, edit_inline=models.TABULAR, num_in_admin=3) -With that ``edit_inline=meta.TABULAR`` (instead of ``meta.STACKED``), the +With that ``edit_inline=models.TABULAR`` (instead of ``models.STACKED``), the related objects are displayed in a more compact, table-based format: .. image:: http://media.djangoproject.com/img/doc/tutorial/admin12.png @@ -302,18 +289,16 @@ helpful if we could display individual fields. To do that, use the ``list_display`` option, which is a tuple of field names to display, as columns, on the change list page for the object:: - class Poll(meta.Model): + class Poll(models.Model): # ... - class META: - admin = meta.Admin( - # ... - list_display = ('question', 'pub_date'), - ) + class Admin: + # ... + list_display = ('question', 'pub_date') Just for good measure, let's also include the ``was_published_today`` custom method from Tutorial 1:: - list_display = ('question', 'pub_date', 'was_published_today'), + list_display = ('question', 'pub_date', 'was_published_today') Now the poll change list page looks like this: @@ -336,7 +321,7 @@ method a ``short_description`` attribute:: Let's add another improvement to the Poll change list page: Filters. Add the following line to ``Poll.admin``:: - list_filter = ['pub_date'], + list_filter = ['pub_date'] That adds a "Filter" sidebar that lets people filter the change list by the ``pub_date`` field: @@ -352,7 +337,7 @@ filter options for DateTimeFields: "Any date," "Today," "Past 7 days," This is shaping up well. Let's add some search capability:: - search_fields = ['question'], + search_fields = ['question'] That adds a search box at the top of the change list. When somebody enters search terms, Django will search the ``question`` field. You can use as many @@ -362,7 +347,7 @@ scenes, keep it reasonable, to keep your database happy. Finally, because Poll objects have dates, it'd be convenient to be able to drill down by date. Add this line:: - date_hierarchy = 'pub_date', + date_hierarchy = 'pub_date' That adds hierarchical navigation, by date, to the top of the change list page. At top level, it displays all available years. Then it drills down to months @@ -383,7 +368,7 @@ That's easy to change, though, using Django's template system. The Django admin is powered by Django itself, and its interfaces use Django's own template system. (How meta!) -Open your settings file (``myproject/settings.py``, remember) and look at the +Open your settings file (``mysite/settings.py``, remember) and look at the ``TEMPLATE_DIRS`` setting. ``TEMPLATE_DIRS`` is a tuple of filesystem directories to check when loading Django templates. It's a search path. diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index c5367270ab..6433831a73 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -2,8 +2,6 @@ Writing your first Django app, part 3 ===================================== -By Adrian Holovaty <holovaty@gmail.com> - This tutorial begins where `Tutorial 2`_ left off. We're continuing the Web-poll application and will focus on creating the public interface -- "views." @@ -62,44 +60,46 @@ arguments from the dictionary (an optional third item in the tuple). For more on ``HTTPRequest`` objects, see the `request and response documentation`_. For more details on URLconfs, see the `URLconf documentation`_. -When you ran ``python manage.py startproject myproject`` at the beginning of -Tutorial 1, it created a default URLconf in ``myproject/urls.py``. It also +When you ran ``python manage.py startproject mysite`` at the beginning of +Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also automatically set your ``ROOT_URLCONF`` setting to point at that file:: - ROOT_URLCONF = 'myproject.urls' + ROOT_URLCONF = 'mysite.urls' -Time for an example. Edit ``myproject/urls.py`` so it looks like this:: +Time for an example. Edit ``mysite/urls.py`` so it looks like this:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^polls/$', 'myproject.polls.views.index'), - (r'^polls/(\d+)/$', 'myproject.polls.views.detail'), - (r'^polls/(\d+)/results/$', 'myproject.polls.views.results'), - (r'^polls/(\d+)/vote/$', 'myproject.polls.views.vote'), + (r'^polls/$', 'mysite.polls.views.index'), + (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'), + (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'), + (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), ) This is worth a review. When somebody requests a page from your Web site -- say, "/polls/23/", Django will load this Python module, because it's pointed to by the ``ROOT_URLCONF`` setting. It finds the variable named ``urlpatterns`` and traverses the regular expressions in order. When it finds a regular -expression that matches -- ``r'^polls/(\d+)/$'`` -- it loads the -associated Python package/module: ``myproject.polls.views.detail``. That -corresponds to the function ``detail()`` in ``myproject/polls/views.py``. +expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the +associated Python package/module: ``mysite.polls.views.detail``. That +corresponds to the function ``detail()`` in ``mysite/polls/views.py``. Finally, it calls that ``detail()`` function like so:: detail(request=<HttpRequest object>, poll_id='23') -The ``poll_id='23'`` part comes from ``(\d+)``. Using parenthesis around a +The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a pattern "captures" the text matched by that pattern and sends it as an argument -to the view function. +to the view function; the ``?P<poll_id>`` defines the name that will be used to +identify the matched pattern; and \d+ is a regular experession to match a sequence of +digits (i.e., a number). Because the URL patterns are regular expressions, there really is no limit on what you can do with them. And there's no need to add URL cruft such as ``.php`` -- unless you have a sick sense of humor, in which case you can do something like this:: - (r'^polls/latest\.php$', 'myproject.polls.views.index'), + (r'^polls/latest\.php$', 'mysite.polls.views.index'), But, don't do that. It's silly. @@ -135,20 +135,20 @@ You should get a pleasantly-colored error page with the following message:: ViewDoesNotExist at /polls/ - Tried index in module myproject.polls.views. Error was: 'module' + Tried index in module mysite.polls.views. Error was: 'module' object has no attribute 'index' This error happened because you haven't written a function ``index()`` in the -module ``myproject/polls/views.py``. +module ``mysite/polls/views.py``. Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error messages tell you which view Django tried (and failed to find, because you haven't written any views yet). -Time to write the first view. Open the file ``myproject/polls/views.py`` +Time to write the first view. Open the file ``mysite/polls/views.py`` and put the following Python code in it:: - from django.utils.httpwrappers import HttpResponse + from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the poll index.") @@ -185,11 +185,11 @@ in Tutorial 1. Here's one stab at the ``index()`` view, which displays the latest 5 poll questions in the system, separated by commas, according to publication date:: - from django.models.polls import polls - from django.utils.httpwrappers import HttpResponse + from mysite.polls.models import Poll + from django.http import HttpResponse def index(request): - latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) + latest_poll_list = Poll.objects.all().order_by('-pub_date') output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output) @@ -197,13 +197,13 @@ There's a problem here, though: The page's design is hard-coded in the view. If you want to change the way the page looks, you'll have to edit this Python code. So let's use Django's template system to separate the design from Python:: - from django.core.template import Context, loader - from django.models.polls import polls - from django.utils.httpwrappers import HttpResponse + from django.template import Context, loader + from mysite.polls.models import Poll + from django.http import HttpResponse def index(request): - latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) - t = loader.get_template('polls/index') + latest_poll_list = Poll.objects.all().order_by('-pub_date') + t = loader.get_template('polls/index.html') c = Context({ 'latest_poll_list': latest_poll_list, }) @@ -227,9 +227,8 @@ find templates -- just as you did in the "Customize the admin look and feel" section of Tutorial 2. When you've done that, create a directory ``polls`` in your template directory. -Within that, create a file called ``index.html``. Django requires that -templates have ".html" extension. Note that our -``loader.get_template('polls/index')`` code from above maps to +Within that, create a file called ``index.html``. Note that our +``loader.get_template('polls/index.html')`` code from above maps to "[template_directory]/polls/index.html" on the filesystem. Put the following code in that template:: @@ -254,12 +253,12 @@ It's a very common idiom to load a template, fill a context and return an ``HttpResponse`` object with the result of the rendered template. Django provides a shortcut. Here's the full ``index()`` view, rewritten:: - from django.core.extensions import render_to_response - from django.models.polls import polls + from django.shortcuts import render_to_response + from mysite.polls.models import Poll def index(request): - latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) - return render_to_response('polls/index', {'latest_poll_list': latest_poll_list}) + latest_poll_list = Poll.objects.all().order_by('-pub_date') + return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}) Note that we no longer need to import ``loader``, ``Context`` or ``HttpResponse``. @@ -274,15 +273,16 @@ Raising 404 Now, let's tackle the poll detail view -- the page that displays the question for a given poll. Here's the view:: - from django.core.exceptions import Http404 + from django.http import Http404 + # ... def detail(request, poll_id): try: - p = polls.get_object(pk=poll_id) - except polls.PollDoesNotExist: + p = Poll.objects.get(pk=poll_id) + except Poll.DoesNotExist: raise Http404 - return render_to_response('polls/detail', {'poll': p}) + return render_to_response('polls/detail.html', {'poll': p}) -The new concept here: The view raises the ``django.core.exceptions.Http404`` +The new concept here: The view raises the ``django.http.Http404`` exception if a poll with the requested ID doesn't exist. A shortcut: get_object_or_404() @@ -292,10 +292,11 @@ It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view, rewritten:: - from django.core.extensions import get_object_or_404 + from django.shortcuts import render_to_response, get_object_or_404 + # ... def detail(request, poll_id): - p = get_object_or_404(polls, pk=poll_id) - return render_to_response('polls/detail', {'poll': p}) + p = get_object_or_404(Poll, pk=poll_id) + return render_to_response('polls/detail.html', {'poll': p}) The ``get_object_or_404()`` function takes a Django model module as its first argument and an arbitrary number of keyword arguments, which it passes to the @@ -305,8 +306,8 @@ exist. .. admonition:: Philosophy Why do we use a helper function ``get_object_or_404()`` instead of - automatically catching the ``*DoesNotExist`` exceptions at a higher level, - or having the model API raise ``Http404`` instead of ``*DoesNotExist``? + automatically catching the ``DoesNotExist`` exceptions at a higher level, + or having the model API raise ``Http404`` instead of ``DoesNotExist``? Because that would couple the model layer to the view layer. One of the foremost design goals of Django is to maintain loose coupling. @@ -359,7 +360,7 @@ what the template might look like:: <h1>{{ poll.question }}</h1> <ul> - {% for choice in poll.get_choice_list %} + {% for choice in poll.choice_set.all %} <li>{{ choice.choice }}</li> {% endfor %} </ul> @@ -370,9 +371,9 @@ on the object ``poll``. Failing that, it tries attribute lookup -- which works, in this case. If attribute lookup had failed, it would've tried calling the method ``question()`` on the poll object. -Method-calling happens in the ``{% for %}`` loop: ``poll.get_choice_list`` is -interpreted as the Python code ``poll.get_choice_list()``, which returns a list -of Choice objects and is suitable for iteration via the ``{% for %}`` tag. +Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is +interpreted as the Python code ``poll.choice_set.all()``, which returns an +iterable of Choice objects and is suitable for use in the ``{% for %}`` tag. See the `template guide`_ for full details on how templates work. @@ -385,19 +386,19 @@ Take some time to play around with the views and template system. As you edit the URLconf, you may notice there's a fair bit of redundancy in it:: urlpatterns = patterns('', - (r'^polls/$', 'myproject.polls.views.index'), - (r'^polls/(?P<poll_id>\d+)/$', 'myproject.polls.views.detail'), - (r'^polls/(?P<poll_id>\d+)/results/$', 'myproject.polls.views.results'), - (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'), + (r'^polls/$', 'mysite.polls.views.index'), + (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'), + (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'), + (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), ) -Namely, ``myproject.polls.views`` is in every callback. +Namely, ``mysite.polls.views`` is in every callback. Because this is a common case, the URLconf framework provides a shortcut for common prefixes. You can factor out the common prefixes and add them as the first argument to ``patterns()``, like so:: - urlpatterns = patterns('myproject.polls.views', + urlpatterns = patterns('mysite.polls.views', (r'^polls/$', 'index'), (r'^polls/(?P<poll_id>\d+)/$', 'detail'), (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), @@ -419,15 +420,15 @@ Our poll app is pretty decoupled at this point, thanks to the strict directory structure that ``python manage.py startapp`` created, but one part of it is coupled to the Django settings: The URLconf. -We've been editing the URLs in ``myproject/urls.py``, but the URL design of an +We've been editing the URLs in ``mysite/urls.py``, but the URL design of an app is specific to the app, not to the Django installation -- so let's move the URLs within the app directory. -Copy the file ``myproject/urls.py`` to ``myproject/polls/urls.py``. Then, -change ``myproject/urls.py`` to remove the poll-specific URLs and insert an +Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then, +change ``mysite/urls.py`` to remove the poll-specific URLs and insert an ``include()``:: - (r'^polls/', include('myproject.polls.urls')), + (r'^polls/', include('mysite.polls.urls')), ``include()``, simply, references another URLconf. Note that the regular expression doesn't have a ``$`` (end-of-string match character) but has the @@ -439,14 +440,14 @@ Here's what happens if a user goes to "/polls/34/" in this system: * Django will find the match at ``'^polls/'`` * It will strip off the matching text (``"polls/"``) and send the remaining - text -- ``"34/"`` -- to the 'myproject.polls.urls' urlconf for + text -- ``"34/"`` -- to the 'mysite.polls.urls' urlconf for further processing. Now that we've decoupled that, we need to decouple the -'myproject.polls.urls' urlconf by removing the leading "polls/" from each +'mysite.polls.urls' urlconf by removing the leading "polls/" from each line:: - urlpatterns = patterns('myproject.polls.views', + urlpatterns = patterns('mysite.polls.views', (r'^$', 'index'), (r'^(?P<poll_id>\d+)/$', 'detail'), (r'^(?P<poll_id>\d+)/results/$', 'results'), diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index f6a0abb6d1..67974327a3 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -2,8 +2,6 @@ Writing your first Django app, part 4 ===================================== -By Adrian Holovaty <holovaty@gmail.com> - This tutorial begins where `Tutorial 3`_ left off. We're continuing the Web-poll application and will focus on simple form processing and cutting down our code. @@ -18,7 +16,7 @@ template contains an HTML ``<form>`` element:: {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="/polls/{{ poll.id }}/vote/" method="post"> - {% for choice in poll.get_choice_list %} + {% for choice in poll.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br /> {% endfor %} @@ -41,24 +39,24 @@ A quick rundown: Django; it's just good Web development practice. Now, let's create a Django view that handles the submitted data and does -something with it. Remember, in `Tutorial 3`_, we create a URLconf that -included this line:: - - (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'), +something with it. Remember, in `Tutorial 3`_, we created a URLconf for the +polls application that includes this line:: -So let's create a ``vote()`` function in ``myproject/polls/views.py``:: + (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), - from django.core.extensions import get_object_or_404, render_to_response - from django.models.polls import choices, polls - from django.utils.httpwrappers import HttpResponseRedirect +So let's create a ``vote()`` function in ``mysite/polls/views.py``:: + from django.shortcuts import get_object_or_404, render_to_response + from django.http import HttpResponseRedirect + from mysite.polls.models import Choice, Poll + # ... def vote(request, poll_id): - p = get_object_or_404(polls, pk=poll_id) + p = get_object_or_404(Poll, pk=poll_id) try: - selected_choice = p.get_choice(pk=request.POST['choice']) - except (KeyError, choices.ChoiceDoesNotExist): + selected_choice = p.choice_set.get(pk=request.POST['choice']) + except (KeyError, Choice.DoesNotExist): # Redisplay the poll voting form. - return render_to_response('polls/detail', { + return render_to_response('polls/detail.html', { 'poll': p, 'error_message': "You didn't select a choice.", }) @@ -102,8 +100,8 @@ After somebody votes in a poll, the ``vote()`` view redirects to the results page for the poll. Let's write that view:: def results(request, poll_id): - p = get_object_or_404(polls, pk=poll_id) - return render_to_response('polls/results', {'poll': p}) + p = get_object_or_404(Poll, pk=poll_id) + return render_to_response('polls/results.html', {'poll': p}) This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_. The only difference is the template name. We'll fix this redundancy later. @@ -113,7 +111,7 @@ Now, create a ``results.html`` template:: <h1>{{ poll.question }}</h1> <ul> - {% for choice in poll.get_choice_list %} + {% for choice in poll.choice_set.all %} <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> @@ -153,12 +151,12 @@ conversion. You should know basic math before you start using a calculator. -First, open the polls.py URLconf. It looks like this, according to the tutorial -so far:: +First, open the polls/urls.py URLconf. It looks like this, according to the +tutorial so far:: from django.conf.urls.defaults import * - urlpatterns = patterns('myproject.polls.views', + urlpatterns = patterns('mysite.polls.views', (r'^$', 'index'), (r'^(?P<poll_id>\d+)/$', 'detail'), (r'^(?P<poll_id>\d+)/results/$', 'results'), @@ -168,56 +166,62 @@ so far:: Change it like so:: from django.conf.urls.defaults import * + from mysite.polls.models import Poll info_dict = { - 'app_label': 'polls', - 'module_name': 'polls', + 'queryset': Poll.objects.all(), } urlpatterns = patterns('', (r'^$', 'django.views.generic.list_detail.object_list', info_dict), (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict), - (r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results')), - (r'^(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'), + (r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html')), + (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), ) We're using two generic views here: ``object_list`` and ``object_detail``. Respectively, those two views abstract the concepts of "display a list of objects" and "display a detail page for a particular type of object." - * Each generic view needs to know which ``app_label`` and ``module_name`` - it's acting on. Thus, we've defined ``info_dict``, a dictionary that's - passed to each of the generic views via the third parameter to the URL - tuples. + * Each generic view needs to know what data it will be acting upon. This + data is provided in a dictionary. The ``queryset`` key in this dictionary + points to the list of objects to be manipulated by the generic view. - * The ``object_detail`` generic view expects that the ID value captured - from the URL is called ``"object_id"``, so we've changed ``poll_id`` to + * The ``object_detail`` generic view expects the ID value captured + from the URL to be called ``"object_id"``, so we've changed ``poll_id`` to ``object_id`` for the generic views. By default, the ``object_detail`` generic view uses a template called -``<app_label>/<module_name>_detail``. In our case, it'll use the template -``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to -``polls/polls_detail.html``, and change the ``render_to_response()`` line in +``<app name>/<module name>_detail.html``. In our case, it'll use the template +``"polls/poll_detail.html"``. Thus, rename your ``polls/detail.html`` template to +``polls/poll_detail.html``, and change the ``render_to_response()`` line in ``vote()``. Similarly, the ``object_list`` generic view uses a template called -``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to -``polls/polls_list.html``. +``<app name>/<module name>_list.html``. Thus, rename ``poll/index.html`` to +``polls/poll_list.html``. Because we have more than one entry in the URLconf that uses ``object_detail`` for the polls app, we manually specify a template name for the results view: -``template_name='polls/results'``. Otherwise, both views would use the same +``template_name='polls/results.html'``. Otherwise, both views would use the same template. Note that we use ``dict()`` to return an altered dictionary in place. -The generic views pass ``object`` and ``object_list`` to their templates, so -change your templates so that ``latest_poll_list`` becomes ``object_list`` and -``poll`` becomes ``object``. +In previous versions of the tutorial, the templates have been provided with a context +that contains the ``poll` and ``latest_poll_list`` context variables. However, +the generic views provide the variables ``object`` and ``object_list`` as context. +Therefore, you need to change your templates to match the new context variables. +Go through your templates, and modify any reference to ``latest_poll_list`` to +``object_list``, and change any reference to ``poll`` to ``object``. + +You can now delete the ``index()``, ``detail()`` and ``results()`` views +from ``polls/views.py``. We don't need them anymore -- they have been replaced +by generic views. -In the ``vote()`` view, change the template call from ``polls/detail`` to -``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``. +The ``vote()`` view is still required. However, it must be modified to match +the new templates and context variables. Change the template call from ``polls/detail`` +to ``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``. -Finally, you can delete the ``index()``, ``detail()`` and ``results()`` views -from ``polls/views.py``. We don't need them anymore. +Run the server, and use your new polling app based on generic views. For full details on generic views, see the `generic views documentation`_. diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 66bab747de..3b83a98804 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -32,18 +32,18 @@ How Django processes a request When a user requests a page from your Django-powered site, this is the algorithm the system follows to determine which Python code to execute: - 1. The system looks at the ``ROOT_URLCONF`` setting in your - `settings file`_. This should be a string representing the full Python - import path to your URLconf. For example: ``"mydjangoapps.urls"``. - 2. The system loads that Python module and looks for the variable - ``urlpatterns``. This should be a Python list, in the format returned - by the function ``django.conf.urls.defaults.patterns()``. - 3. The system runs through each URL pattern, in order, and stops at the - first one that matches the requested URL. + 1. Django looks at the ``ROOT_URLCONF`` setting in your `settings file`_. + This should be a string representing the full Python import path to your + URLconf. For example: ``"mydjangoapps.urls"``. + 2. Django loads that Python module and looks for the variable + ``urlpatterns``. This should be a Python list, in the format returned by + the function ``django.conf.urls.defaults.patterns()``. + 3. Django runs through each URL pattern, in order, and stops at the first + one that matches the requested URL. 4. Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. The view gets passed a - `request object`_ and any values captured in the regex as function - arguments. + `request object`_ as its first argument and any values captured in the + regex as remaining arguments. .. _settings file: http://www.djangoproject.com/documentation/settings/ .. _request object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects @@ -64,7 +64,7 @@ Here's a sample URLconf:: Notes: - * ``from django.conf.urls.defaults import *`` makes the ``patterns`` + * ``from django.conf.urls.defaults import *`` makes the ``patterns()`` function available. * To capture a value from the URL, just put parenthesis around it. @@ -72,11 +72,11 @@ Notes: * There's no need to add a leading slash, because every URL has that. For example, it's ``^articles``, not ``^/articles``. - * The ``"r"`` in front of each regular expression string is optional but + * The ``'r'`` in front of each regular expression string is optional but recommended. It tells Python that a string is "raw" -- that nothing in the string should be escaped. See `Dive Into Python's explanation`_. -Examples: +Example requests: * A request to ``/articles/2005/03/`` would match the third entry in the list. Django would call the function @@ -121,8 +121,8 @@ Here's the above example URLconf, rewritten to use named groups:: ) This accomplishes exactly the same thing as the previous example, with one -subtle difference: The captured values are passed as keyword arguments rather -than positional arguments. For example: +subtle difference: The captured values are passed to view functions as keyword +arguments rather than positional arguments. For example: * A request to ``/articles/2005/03/`` would call the function ``news.views.month_archive(request, year='2005', month='03')``, instead @@ -134,7 +134,7 @@ than positional arguments. For example: In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs -- and you can reorder the arguments in your views' function definitions. Of course, these benefits come at the cost of brevity; -some folks find the named-group syntax ugly and too verbose. +some developers find the named-group syntax ugly and too verbose. The matching/grouping algorithm ------------------------------- @@ -160,6 +160,10 @@ will look for ``/myapp/``. In a request to ``http://www.example.com/myapp/?page=3``, the URLconf will look for ``/myapp/``. +The URLconf doesn't look at the request method. In other words, all request +methods -- ``POST``, ``GET``, ``HEAD``, etc. -- will be routed to the same +function for the same URL. + Syntax of the urlpatterns variable ================================== @@ -183,8 +187,8 @@ The remaining arguments should be tuples in this format:: (regular expression, Python callback function [, optional dictionary]) -...where ``dictionary_of_extra_arguments`` is optional. (See -"Passing extra options to view functions" below.) +...where ``optional dictionary`` is optional. (See +_`Passing extra options to view functions` below.) handler404 ---------- @@ -209,7 +213,7 @@ include ------- A function that takes a full Python import path to another URLconf that should -be "included" in this place. See "Including other URLconfs" below. +be "included" in this place. See _`Including other URLconfs` below. Notes on capturing text in URLs =============================== @@ -259,12 +263,12 @@ Here's the example URLconf from the `Django overview`_:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^articles/(?P<year>\d{4})/$', 'myproject.news.views.year_archive'), - (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'myproject.news.views.month_archive'), - (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'myproject.news.views.article_detail'), + (r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'), ) -In this example, each view has a common prefix -- ``"myproject.news.views"``. +In this example, each view has a common prefix -- ``'myproject.news.views'``. Instead of typing that out for each entry in ``urlpatterns``, you can use the first argument to the ``patterns()`` function to specify a prefix to apply to each view function. @@ -274,9 +278,9 @@ With this in mind, the above example can be written more concisely as:: from django.conf.urls.defaults import * urlpatterns = patterns('myproject.news.views', - (r'^articles/(?P<year>\d{4})/$', 'year_archive'), - (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'month_archive'), - (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'article_detail'), + (r'^articles/(\d{4})/$', 'year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), ) Note that you don't put a trailing dot (``"."``) in the prefix. Django puts @@ -299,7 +303,6 @@ number of other URLconfs:: (r'^weblog/', include('django_website.apps.blog.urls.blog')), (r'^documentation/', include('django_website.apps.docs.urls.docs')), (r'^comments/', include('django.contrib.comments.urls.comments')), - (r'^rss/', include('django.conf.urls.rss')), ) Note that the regular expressions in this example don't have a ``$`` |
