From f69cf70ed813a8cd7e1f963a14ae39103e8d5265 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Tue, 2 May 2006 01:31:56 +0000 Subject: 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 --- docs/add_ons.txt | 4 +- docs/admin_css.txt | 57 +- docs/authentication.txt | 231 +++--- docs/cache.txt | 335 +++++++-- docs/db-api.txt | 1668 +++++++++++++++++++++++++++++++----------- docs/design_philosophies.txt | 22 +- docs/django-admin.txt | 181 +++-- docs/email.txt | 46 +- docs/faq.txt | 150 ++-- docs/flatpages.txt | 37 +- docs/forms.txt | 255 +++++-- docs/generic_views.txt | 1170 ++++++++++++++++++++--------- docs/i18n.txt | 10 +- docs/install.txt | 6 +- docs/legacy_databases.txt | 44 +- docs/middleware.txt | 34 +- docs/model-api.txt | 1385 ++++++++++++++++++++--------------- docs/modpython.txt | 18 +- docs/outputting_csv.txt | 14 +- docs/outputting_pdf.txt | 2 +- docs/overview.txt | 203 ++--- docs/redirects.txt | 13 +- docs/request_response.txt | 58 +- docs/sessions.txt | 42 +- docs/settings.txt | 71 +- docs/static_files.txt | 16 +- docs/syndication_feeds.txt | 26 +- docs/templates.txt | 130 ++-- docs/templates_python.txt | 144 ++-- docs/transactions.txt | 146 ++++ docs/tutorial01.txt | 329 +++++---- docs/tutorial02.txt | 99 ++- docs/tutorial03.txt | 125 ++-- docs/tutorial04.txt | 92 +-- docs/url_dispatch.txt | 57 +- 35 files changed, 4691 insertions(+), 2529 deletions(-) create mode 100644 docs/transactions.txt (limited to 'docs') 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`_: - - * ``get_group_list(**kwargs)`` - * ``set_groups(id_list)`` - * ``get_permission_list(**kwargs)`` - * ``set_user_permissions(id_list)`` +``user_permissions``. ``User`` objects can access their related +objects in the same way as any other `Django model`_:: + + ``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]``. - -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. +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 ``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 {% 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? - -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. - -.. _slashdotted: http://en.wikipedia.org/wiki/Slashdot_effect +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. + +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. + +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``. + +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. -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. +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``. -The ``CACHE_BACKEND`` setting is a "fake" URI (really an unregistered scheme). -Examples: +Local-memory caching +-------------------- - ============================== =========================================== - 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. +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:: - This backend requires the - `Python memcached bindings`_. + CACHE_BACKEND = 'locmem:///' - db://tablename/ A database backend in a table named - "tablename". This table should be created - with "django-admin createcachetable". +Simple caching (for development) +-------------------------------- - file:///var/tmp/django_cache/ A file-based cache stored in the directory - /var/tmp/django_cache/. +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:: - 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! + CACHE_BACKEND = 'simple:///' - locmem:/// A more sophisticated local memory cache; - this is multi-process- and thread-safe. +Dummy caching (for development) +------------------------------- - 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. - ============================== =========================================== +Finally, Django comes with a "dummy" cache that doesn't actually cache -- it +just implements the cache interface without doing anything. -All caches may take arguments -- they're given in query-string style. Valid -arguments are: +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. - -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:: - - >>> 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'}] - -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. - -get_values_iterator(\**kwargs) ------------------------------- +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. -Just like ``get_values()``, except it returns an iterator instead of a list. -See the section on ``get_iterator()`` above. - -get_in_bulk(id_list, \**kwargs) -------------------------------- - -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:: - - >>> 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?} +(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`_.) -Field lookups -============= +.. _AutoField documentation: TODO: Link -Basic field lookups take the form ``field__lookuptype`` (that's a -double-underscore). For example:: +Explicitly specifying auto-primary-key values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - polls.get_list(pub_date__lte=datetime.datetime.now()) +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. -translates (roughly) into the following SQL:: +Example:: - SELECT * FROM polls_polls WHERE pub_date <= NOW(); + b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.') + b3.id # Returns 3. + b3.save() + b3.id # Returns 3. -.. admonition:: How this is possible +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. - 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. +Given the above ``'Cheddar Talk'`` blog example, this example would override +the previous record in the database:: -The DB API supports the following lookup types: - - =========== ============================================================== - 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)``. - =========== ============================================================== - -Multiple lookups are allowed, of course, and are translated as "AND"s:: - - polls.get_list( - pub_date__year=2005, - pub_date__month=1, - question__startswith="Would", - ) + b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.') + b4.save() # Overrides the previous blog with ID=3! -...retrieves all polls published in January 2005 that have a question starting with "Would." +See _`How Django knows to UPDATE vs. INSERT`, below, for the reason this +happens. -For convenience, there's a ``pk`` lookup type, which translates into -``(primary_key)__exact``. In the polls example, these two statements are -equivalent:: +Explicitly specifying auto-primary-key values is mostly useful for bulk-saving +objects, when you're confident you won't have primary-key collision. - polls.get_object(id__exact=3) - polls.get_object(pk=3) +Saving changes to objects +========================= -``pk`` lookups also work across joins. In the polls example, these two -statements are equivalent:: +To save changes to an object that's already in the database, use ``save()``. - choices.get_list(poll__id__exact=3) - choices.get_list(poll__pk=3) +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:: -If you pass an invalid keyword argument, the function will raise ``TypeError``. + b5.name = 'New name' + b5.save() -.. _`Keyword Arguments`: http://docs.python.org/tut/node6.html#SECTION006720000000000000000 +This performs an ``UPDATE`` SQL statement behind the scenes. Django doesn't hit +the database until you explicitly call ``save()``. -OR lookups ----------- +The ``save()`` method has no return value. -By default, multiple lookups are "AND"ed together. If you'd like to use ``OR`` -statements in your queries, use the ``complex`` lookup type. +How Django knows to UPDATE vs. INSERT +------------------------------------- -``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:: +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: + + * 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``. + +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. + +Retrieving objects +================== + +To retrieve objects from your database, you construct a ``QuerySet`` via a +``Manager`` on your model class. + +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``. + +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:: + + Blog.objects # + b = Blog(name='Foo', tagline='Bar') + b.objects # AttributeError: "Manager isn't accessible via Blog instances." + +(``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. + +Retrieving all objects +---------------------- - from django.core.meta import Q - polls.get_object(complex=(Q(question__startswith='Who') | Q(question__startswith='What'))) +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``. -The ``|`` symbol signifies an "OR", so this (roughly) translates into:: +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 +----------------- - SELECT * FROM polls - WHERE question LIKE 'Who%' OR question LIKE 'What%'; +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. + +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()) -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:: + 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. - polls.get_list(order_by=['?']) +QuerySet methods that return new QuerySets +------------------------------------------ + +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. + +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() -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. +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. -Relationships across applications ---------------------------------- +dates(field, kind, order='ASC') +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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 ``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``. -Selecting related objects -------------------------- +``field`` should be the name of a ``DateField`` or ``DateTimeField`` of your +model. -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. +``kind`` should be either ``"year"``, ``"month"`` or ``"day"``. Each +``datetime.datetime`` object in the result list is "truncated" to the given +``type``. -For example, using the Poll and Choice models from above, if you do the following:: + * ``"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. - c = choices.get_object(id__exact=5, select_related=True) +Examples:: -Then subsequent calls to ``c.get_poll()`` won't hit the database. + >>> 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)] -Note that ``select_related`` follows foreign keys as far as possible. If you have the +select_related() +~~~~~~~~~~~~~~~~ + +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. + +The following examples illustrate the difference between plain lookups and +``select_related()`` lookups. Here's standard lookup:: + + # Hits the database. + e = Entry.objects.get(id=5) + + # Hits the database again to get the related Blog object. + b = e.blog + +And here's ``select_related`` lookup:: + + # Hits the database. + e = Entry.objects.select_related().get(id=5) + + # 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) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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. +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``. -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:: +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. - >>> people.get_values(fields=['first_name'], distinct=True) - [{'first_name': 'Adrian'}, {'first_name': 'Jacob'}, {'first_name': 'Simon'}] + Example:: -Other lookup options -==================== + Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) -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.: + 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. + + Django inserts the given SQL snippet directly into the ``SELECT`` + statement, so the resulting SQL of the above example would be:: + + SELECT blog_entry.*, (pub_date > '2006-01-01') + FROM blog_entry; + + + 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') -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:: +SQL equivalent:: - polls.get_list( - select={ - 'choice_count': 'SELECT COUNT(*) FROM choices WHERE poll_id = polls.id' - } + SELECT ... WHERE headline ILIKE '%Lennon%'; + +gt +~~ + +Greater than. + +Example:: + + Entry.objects.filter(id__gt=4) + +SQL equivalent:: + + SELECT ... WHERE id > 4; + +gte +~~~ + +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))) -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``. +... would not be valid. -``where`` and ``tables`` both take a list of strings. All ``where`` parameters -are "AND"ed to any other search criteria. +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. + +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. + + =============== ============= ============= + 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