diff options
| author | Joseph Kocherhans <joseph@jkocherhans.com> | 2006-11-06 21:11:49 +0000 |
|---|---|---|
| committer | Joseph Kocherhans <joseph@jkocherhans.com> | 2006-11-06 21:11:49 +0000 |
| commit | dc59c670b8cbe055ff3565f8d5a2f600c5ab1ba8 (patch) | |
| tree | 84a2d1a3e729a813cf692ebbe7404ba8e5687d22 /docs | |
| parent | bf629e5a4d1a51f938c84d35d768830158ad5ebd (diff) | |
Merged to [3519]
git-svn-id: http://code.djangoproject.com/svn/django/branches/generic-auth@4024 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
32 files changed, 1228 insertions, 243 deletions
diff --git a/docs/add_ons.txt b/docs/add_ons.txt index d72e92b018..6507f3b139 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -2,12 +2,15 @@ The "contrib" add-ons ===================== -Django aims to follow Python's "batteries included" philosophy. It ships with a -variety of extra, optional tools that solve common Web-development problems. +Django aims to follow Python's `"batteries included" philosophy`_. It ships +with a variety of extra, optional tools that solve common Web-development +problems. This code lives in ``django/contrib`` in the Django distribution. Here's a rundown of the packages in ``contrib``: +.. _"batteries included" philosophy: http://docs.python.org/tut/node12.html#batteries-included + admin ===== @@ -128,6 +131,8 @@ A collection of template filters that implement these common markup languages: * Markdown * ReST (ReStructured Text) +For documentation, read the source code in django/contrib/markup/templatetags/markup.py. + redirects ========= diff --git a/docs/admin_css.txt b/docs/admin_css.txt index 069012a84b..ec402f7142 100644 --- a/docs/admin_css.txt +++ b/docs/admin_css.txt @@ -118,8 +118,8 @@ additional class on the ``a`` for that tool. These are ``.addlink`` and Example from a changelist page:: <ul class="object-tools"> - <li><a href="/stories/add/" class="addlink">Add redirect</a></li> - </ul> + <li><a href="/stories/add/" class="addlink">Add redirect</a></li> + </ul> .. image:: http://media.djangoproject.com/img/doc/admincss/objecttools_01.gif :alt: Object tools on a changelist page diff --git a/docs/api_stability.txt b/docs/api_stability.txt new file mode 100644 index 0000000000..a9d6904735 --- /dev/null +++ b/docs/api_stability.txt @@ -0,0 +1,123 @@ +============= +API stability +============= + +Although Django has not reached a 1.0 release, the bulk of Django's public APIs are +stable as of the 0.95 release. This document explains which APIs will and will not +change before the 1.0 release. + +What "stable" means +=================== + +In this context, stable means: + + - All the public APIs -- everything documented in the linked documents, and + all methods that don't begin with an underscore -- will not be moved or + renamed without providing backwards-compatible aliases. + + - If new features are added to these APIs -- which is quite possible -- + they will not break or change the meaning of existing methods. In other + words, "stable" does not (necessarily) mean "complete." + + - If, for some reason, an API declared stable must be removed or replaced, it + will be declared deprecated but will remain in the API until at least + version 1.1. Warnings will be issued when the deprecated method is + called. + + - We'll only break backwards compatibility of these APIs if a bug or + security hole makes it completely unavoidable. + +Stable APIs +=========== + +These APIs are stable: + + - `Caching`_. + + - `Custom template tags and libraries`_ (with the possible exception for a + small change in the way templates are registered and loaded). + + - `Database lookup`_ (with the exception of validation; see below). + + - `django-admin utility`_. + + - `FastCGI integration`_. + + - `Flatpages`_. + + - `Generic views`_. + + - `Internationalization`_. + + - `Legacy database integration`_. + + - `Model definition`_ (with the exception of generic relations; see below). + + - `mod_python integration`_. + + - `Redirects`_. + + - `Request/response objects`_. + + - `Sending email`_. + + - `Sessions`_. + + - `Settings`_. + + - `Syndication`_. + + - `Template language`_ (with the exception of some possible disambiguation + of how tag arguments are passed to tags and filters). + + - `Transactions`_. + + - `URL dispatch`_. + +You'll notice that this list comprises the bulk of Django's APIs. That's right +-- most of the changes planned between now and Django 1.0 are either under the +hood, feature additions, or changes to a few select bits. A good estimate is +that 90% of Django can be considered forwards-compatible at this point. + +That said, these APIs should *not* be considered stable, and are likely to +change: + + - `Forms and validation`_ will most likely be compeltely rewritten to + deemphasize Manipulators in favor of validation-aware models. + + - `Serialization`_ is under heavy development; changes are likely. + + - The `authentication`_ framework is changing to be far more flexible, and + API changes may be necessary. + + - Generic relations will most likely be moved out of core and into the + content-types contrib package to avoid core dependacies on optional + components. + + - The comments framework, which is yet undocumented, will likely get a complete + rewrite before Django 1.0. Even if the change isn't quite that drastic, + there will at least be moderate changes. + +.. _caching: http://www.djangoproject.com/documentation/cache/ +.. _custom template tags and libraries: http://www.djangoproject.com/documentation/templates_python/ +.. _database lookup: http://www.djangoproject.com/documentation/db_api/ +.. _django-admin utility: http://www.djangoproject.com/documentation/django_admin/ +.. _fastcgi integration: http://www.djangoproject.com/documentation/fastcgi/ +.. _flatpages: http://www.djangoproject.com/documentation/flatpages/ +.. _generic views: http://www.djangoproject.com/documentation/generic_views/ +.. _internationalization: http://www.djangoproject.com/documentation/i18n/ +.. _legacy database integration: http://www.djangoproject.com/documentation/legacy_databases/ +.. _model definition: http://www.djangoproject.com/documentation/model_api/ +.. _mod_python integration: http://www.djangoproject.com/documentation/modpython/ +.. _redirects: http://www.djangoproject.com/documentation/redirects/ +.. _request/response objects: http://www.djangoproject.com/documentation/request_response/ +.. _sending email: http://www.djangoproject.com/documentation/email/ +.. _sessions: http://www.djangoproject.com/documentation/sessions/ +.. _settings: http://www.djangoproject.com/documentation/settings/ +.. _syndication: http://www.djangoproject.com/documentation/syndication/ +.. _template language: http://www.djangoproject.com/documentation/templates/ +.. _transactions: http://www.djangoproject.com/documentation/transactions/ +.. _url dispatch: http://www.djangoproject.com/documentation/url_dispatch/ +.. _forms and validation: http://www.djangoproject.com/documentation/forms/ +.. _serialization: http://www.djangoproject.com/documentation/serialization/ +.. _authentication: http://www.djangoproject.com/documentation/authentication/ diff --git a/docs/authentication.txt b/docs/authentication.txt index 79a4ed0875..d10dda28ef 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -95,7 +95,11 @@ In addition to those automatic API methods, ``User`` objects have the following custom methods: * ``is_anonymous()`` -- Always returns ``False``. This is a way of - comparing ``User`` objects to anonymous users. + differentiating ``User`` and ``AnonymousUser`` objects. Generally, you + should prefer using ``is_authenticated()`` to this method. + + * ``is_authenticated()`` -- Always returns ``True``. This is a way to + tell if the user has been authenticated. * ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``, with a space in between. @@ -219,6 +223,7 @@ the ``django.contrib.auth.models.User`` interface, with these differences: * ``id`` is always ``None``. * ``is_anonymous()`` returns ``True`` instead of ``False``. + * ``is_authenticated()`` returns ``False`` instead of ``True``. * ``has_perm()`` always returns ``False``. * ``set_password()``, ``check_password()``, ``save()``, ``delete()``, ``set_groups()`` and ``set_permissions()`` raise ``NotImplementedError``. @@ -254,12 +259,12 @@ 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:: +previous section). You can tell them apart with ``is_authenticated()``, like so:: - if request.user.is_anonymous(): - # Do something for anonymous users. + if request.user.is_authenticated(): + # Do something for authenticated users. else: - # Do something for logged-in users. + # Do something for anonymous users. .. _request objects: http://www.djangoproject.com/documentation/request_response/#httprequest-objects .. _session documentation: http://www.djangoproject.com/documentation/sessions/ @@ -267,17 +272,54 @@ previous section). You can tell them apart with ``is_anonymous()``, like so:: How to log a user in -------------------- -To log a user in, do the following within a view:: +Django provides two functions in ``django.contrib.auth``: ``authenticate()`` +and ``login()``. + +To authenticate a given username and password, use ``authenticate()``. It +takes two keyword arguments, ``username`` and ``password``, and it returns +a ``User`` object if the password is valid for the given username. If the +password is invalid, ``authenticate()`` returns ``None``. Example:: + + from django.contrib.auth import authenticate + user = authenticate(username='john', password='secret') + if user is not None: + print "You provided a correct username and password!" + else: + print "Your username and password were incorrect." + +To log a user in, in a view, use ``login()``. It takes an ``HttpRequest`` +object and a ``User`` object. ``login()`` saves the user's ID in the session, +using Django's session framework, so, as mentioned above, you'll need to make +sure to have the session middleware installed. + +This example shows how you might use both ``authenticate()`` and ``login()``:: + + from django.contrib.auth import authenticate, login + + def my_view(request): + username = request.POST['username'] + password = request.POST['password'] + user = authenticate(username=username, password=password) + if user is not None: + login(request, user) + # Redirect to a success page. + else: + # Return an error message. - from django.contrib.auth.models import SESSION_KEY - request.session[SESSION_KEY] = some_user.id +How to log a user out +--------------------- -Because this uses sessions, you'll need to make sure you have -``SessionMiddleware`` enabled. See the `session documentation`_ for more -information. +To log out a user who has been logged in via ``django.contrib.auth.login()``, +use ``django.contrib.auth.logout()`` within your view. It takes an +``HttpRequest`` object and has no return value. Example:: -This assumes ``some_user`` is your ``User`` instance. Depending on your task, -you'll probably want to make sure to validate the user's username and password. + from django.contrib.auth import logout + + def logout_view(request): + logout(request) + # Redirect to a success page. + +Note that ``logout()`` doesn't throw any errors if the user wasn't logged in. Limiting access to logged-in users ---------------------------------- @@ -286,19 +328,19 @@ 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:: +``request.user.is_authenticated()`` and either redirect to a login page:: from django.http import HttpResponseRedirect def my_view(request): - if request.user.is_anonymous(): + if not request.user.is_authenticated(): return HttpResponseRedirect('/login/?next=%s' % request.path) # ... ...or display an error message:: def my_view(request): - if request.user.is_anonymous(): + if not request.user.is_authenticated(): return render_to_response('myapp/login_error.html') # ... @@ -402,7 +444,7 @@ For example, this view checks to make sure the user is logged in and has the permission ``polls.can_vote``:: def my_view(request): - if request.user.is_anonymous() or not request.user.has_perm('polls.can_vote'): + if not (request.user.is_authenticated() and request.user.has_perm('polls.can_vote')): return HttpResponse("You can't vote in this poll.") # ... @@ -560,7 +602,7 @@ The currently logged-in user and his/her permissions are made available in the setting contains ``"django.core.context_processors.auth"``, which is default. For more, see the `RequestContext docs`_. - .. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext + .. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-requestcontext Users ----- @@ -568,10 +610,10 @@ Users The currently logged-in user, either a ``User`` instance or an``AnonymousUser`` instance, is stored in the template variable ``{{ user }}``:: - {% if user.is_anonymous %} - <p>Welcome, new user. Please log in.</p> + {% if user.is_authenticated %} + <p>Welcome, {{ user.username }}. Thanks for logging in.</p> {% else %} - <p>Welcome, {{ user.username }}. Thanks for logging in.</p> + <p>Welcome, new user. Please log in.</p> {% endif %} Permissions @@ -672,3 +714,117 @@ Finally, note that this messages framework only works with users in the user database. To send messages to anonymous users, use the `session framework`_. .. _session framework: http://www.djangoproject.com/documentation/sessions/ + +Other authentication sources +============================ + +The authentication that comes with Django is good enough for most common cases, +but you may have the need to hook into another authentication source -- that +is, another source of usernames and passwords or authentication methods. + +For example, your company may already have an LDAP setup that stores a username +and password for every employee. It'd be a hassle for both the network +administrator and the users themselves if users had separate accounts in LDAP +and the Django-based applications. + +So, to handle situations like this, the Django authentication system lets you +plug in another authentication sources. You can override Django's default +database-based scheme, or you can use the default system in tandem with other +systems. + +Specifying authentication backends +---------------------------------- + +Behind the scenes, Django maintains a list of "authentication backends" that it +checks for authentication. When somebody calls +``django.contrib.auth.authenticate()`` -- as described in "How to log a user in" +above -- Django tries authenticating across all of its authentication backends. +If the first authentication method fails, Django tries the second one, and so +on, until all backends have been attempted. + +The list of authentication backends to use is specified in the +``AUTHENTICATION_BACKENDS`` setting. This should be a tuple of Python path +names that point to Python classes that know how to authenticate. These classes +can be anywhere on your Python path. + +By default, ``AUTHENTICATION_BACKENDS`` is set to:: + + ('django.contrib.auth.backends.ModelBackend',) + +That's the basic authentication scheme that checks the Django users database. + +The order of ``AUTHENTICATION_BACKENDS`` matters, so if the same username and +password is valid in multiple backends, Django will stop processing at the +first positive match. + +Writing an authentication backend +--------------------------------- + +An authentication backend is a class that implements two methods: +``get_user(id)`` and ``authenticate(**credentials)``. + +The ``get_user`` method takes an ``id`` -- which could be a username, database +ID or whatever -- and returns a ``User`` object. + +The ``authenticate`` method takes credentials as keyword arguments. Most of +the time, it'll just look like this:: + + class MyBackend: + def authenticate(username=None, password=None): + # Check the username/password and return a User. + +But it could also authenticate a token, like so:: + + class MyBackend: + def authenticate(token=None): + # Check the token and return a User. + +Either way, ``authenticate`` should check the credentials it gets, and it +should return a ``User`` object that matches those credentials, if the +credentials are valid. If they're not valid, it should return ``None``. + +The Django admin system is tightly coupled to the Django ``User`` object +described at the beginning of this document. For now, the best way to deal with +this is to create a Django ``User`` object for each user that exists for your +backend (e.g., in your LDAP directory, your external SQL database, etc.) You +can either write a script to do this in advance, or your ``authenticate`` +method can do it the first time a user logs in. + +Here's an example backend that authenticates against a username and password +variable defined in your ``settings.py`` file and creates a Django ``User`` +object the first time a user authenticates:: + + from django.conf import settings + from django.contrib.auth.models import User, check_password + + class SettingsBackend: + """ + Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD. + + Use the login name, and a hash of the password. For example: + + ADMIN_LOGIN = 'admin' + ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de' + """ + def authenticate(self, username=None, password=None): + login_valid = (settings.ADMIN_LOGIN == username) + pwd_valid = check_password(password, settings.ADMIN_PASSWORD) + if login_valid and pwd_valid: + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + # Create a new user. Note that we can set password + # to anything, because it won't be checked; the password + # from settings.py will. + user = User(username=username, password='get from settings.py') + user.is_staff = True + user.is_superuser = True + user.save() + return user + return None + + def get_user(self, user_id): + try: + return User.objects.get(pk=user_id) + except User.DoesNotExist: + return None diff --git a/docs/cache.txt b/docs/cache.txt index 2ef3d6503f..62fec289b9 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -230,8 +230,13 @@ Then, add the following required settings to your Django settings file: collisions. Use an empty string if you don't care. The cache middleware caches every page that doesn't have GET or POST -parameters. Additionally, ``CacheMiddleware`` automatically sets a few headers -in each ``HttpResponse``: +parameters. Optionally, if the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting is +``True``, only anonymous requests (i.e., not those made by a logged-in user) +will be cached. This is a simple and effective way of disabling caching for any +user-specific pages (include Django's admin interface). + +Additionally, ``CacheMiddleware`` automatically sets a few headers in each +``HttpResponse``: * Sets the ``Last-Modified`` header to the current date/time when a fresh (uncached) version of the page is requested. diff --git a/docs/contributing.txt b/docs/contributing.txt index d7552cdc7c..9d116cac10 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -168,6 +168,10 @@ Please follow these coding standards when writing code for inclusion in Django: {{foo}} + * Please don't put your name in the code. While we appreciate all + contributions to Django, our policy is not to publish individual + developer names in code -- for instance, at the top of Python modules. + Committing code =============== @@ -212,6 +216,10 @@ repository: first, then the "Fixed #abc." For example: "magic-removal: Fixed #123 -- Added whizbang feature." + For the curious: We're using a `Trac post-commit hook`_ for this. + + .. _Trac post-commit hook: http://trac.edgewall.org/browser/trunk/contrib/trac-post-commit-hook + * If your commit references a ticket in the Django `ticket tracker`_ but does *not* close the ticket, include the phrase "Refs #abc", where "abc" is the number of the ticket your commit references. We've rigged diff --git a/docs/db-api.txt b/docs/db-api.txt index 5108949184..a7cf30813d 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -60,6 +60,10 @@ the database until you explicitly call ``save()``. The ``save()`` method has no return value. +To create an object and save it all in one step see the `create`__ method. + +__ `create(**kwargs)`_ + Auto-incrementing primary keys ------------------------------ @@ -574,6 +578,9 @@ related ``Person`` *and* the related ``City``:: p = b.author # Hits the database. c = p.hometown # Hits the database. +Note that ``select_related()`` does not follow foreign keys that have +``null=True``. + ``extra(select=None, where=None, params=None, tables=None)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -705,6 +712,20 @@ The ``DoesNotExist`` exception inherits from except ObjectDoesNotExist: print "Either the entry or blog doesn't exist." +``create(**kwargs)`` +~~~~~~~~~~~~~~~~~~~~ + +A convenience method for creating an object and saving it all in one step. Thus:: + + p = Person.objects.create(first_name="Bruce", last_name="Springsteen") + +and:: + + p = Person(first_name="Bruce", last_name="Springsteen") + p.save() + +are equivalent. + ``get_or_create(**kwargs)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1103,35 +1124,37 @@ Note this is only available in MySQL and requires direct manipulation of the database to add the full-text index. 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) + Blog.objects.get(id__exact=14) # Explicit form + Blog.objects.get(id=14) # __exact is implied 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:: +three statements are equivalent:: - Blog.objects.get(id__exact=14) - Blog.objects.get(pk=14) + Blog.objects.get(id__exact=14) # Explicit form + Blog.objects.get(id=14) # __exact is implied + Blog.objects.get(pk=14) # pk implies id__exact -``pk`` lookups also work across joins. For example, these two statements are +``pk`` lookups also work across joins. For example, these three statements are equivalent:: - Entry.objects.filter(blog__id__exact=3) - Entry.objects.filter(blog__pk=3) + Entry.objects.filter(blog__id__exact=3) # Explicit form + Entry.objects.filter(blog__id=3) # __exact is implied + Entry.objects.filter(blog__pk=3) # __pk implies __id__exact Lookups that span relationships ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1532,6 +1555,21 @@ loaded, Django iterates over every model in ``INSTALLED_APPS`` and creates the backward relationships in memory as needed. Essentially, one of the functions of ``INSTALLED_APPS`` is to tell Django the entire model domain. +Queries over related objects +---------------------------- + +Queries involving related objects follow the same rules as queries involving +normal value fields. When specifying the the value for a query to match, you +may use either an object instance itself, or the primary key value for the +object. + +For example, if you have a Blog object ``b`` with ``id=5``, the following +three queries would be identical:: + + Entry.objects.filter(blog=b) # Query using object instance + Entry.objects.filter(blog=b.id) # Query using id from instance + Entry.objects.filter(blog=5) # Query using id directly + Deleting objects ================ diff --git a/docs/design_philosophies.txt b/docs/design_philosophies.txt index 17ed3ad6da..7fdc7ea01b 100644 --- a/docs/design_philosophies.txt +++ b/docs/design_philosophies.txt @@ -274,8 +274,8 @@ Loose coupling A view shouldn't care about which template system the developer uses -- or even whether a template system is used at all. -Designate between GET and POST ------------------------------- +Differentiate between GET and POST +---------------------------------- GET and POST are distinct; developers should explicitly use one or the other. The framework should make it easy to distinguish between GET and POST data. diff --git a/docs/django-admin.txt b/docs/django-admin.txt index 3334ae4530..eb7b2dccd6 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -126,8 +126,9 @@ 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. -Primary keys are automatically introspected for PostgreSQL and MySQL, in which -case Django puts in the ``primary_key=True`` where needed. +Primary keys are automatically introspected for PostgreSQL, MySQL and +SQLite, 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 and with certain types of MySQL tables. @@ -191,6 +192,14 @@ documentation. .. _serving static files: http://www.djangoproject.com/documentation/static_files/ +Turning off auto-reload +~~~~~~~~~~~~~~~~~~~~~~~ + +To disable auto-reloading of code while the development server is running, use the +``--noreload`` option, like so:: + + django-admin.py runserver --noreload + shell ----- diff --git a/docs/faq.txt b/docs/faq.txt index adcdbaca59..36fb547cf1 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -156,7 +156,7 @@ logical to us. ----------------------------------------------------- We're well aware that there are other awesome Web frameworks out there, and -we're not adverse to borrowing ideas where appropriate. However, Django was +we're not averse to borrowing ideas where appropriate. However, Django was developed precisely because we were unhappy with the status quo, so please be aware that "because <Framework X>" does it is not going to be sufficient reason to add a given feature to Django. @@ -251,6 +251,16 @@ information than the docs that come with the latest Django release. .. _stored in revision control: http://code.djangoproject.com/browser/django/trunk/docs +Where can I find Django developers for hire? +-------------------------------------------- + +Consult our `developers for hire page`_ for a list of Django developers who +would be happy to help you. + +You might also be interested in posting a job to http://www.gypsyjobs.com/ . + +.. _developers for hire page: http://code.djangoproject.com/wiki/DevelopersForHire + Installation questions ====================== @@ -301,16 +311,18 @@ PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported. Do I have to use mod_python? ---------------------------- -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. +Although we recommend mod_python for production use, you don't have to use it, +thanks to the fact that Django uses an arrangement called WSGI_. Django can +talk to any WSGI-enabled server. The most common non-mod_python deployment +setup is FastCGI. See `How to use Django with FastCGI`_ for full information. -For production use, though, we recommend mod_python. The Django developers have -been running it on mod_python for several years, and it's quite stable. +Also, see the `server arrangements wiki page`_ for other deployment strategies. -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`_. +If you just want to play around and develop things on your local computer, use +the development Web server that comes with Django. Things should Just Work. .. _WSGI: http://www.python.org/peps/pep-0333.html +.. _How to use Django with FastCGI: http://www.djangoproject.com/documentation/fastcgi/ .. _server arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements How do I install mod_python on Windows? @@ -409,6 +421,36 @@ Using a ``FileField`` or an ``ImageField`` in a model takes a few steps: absolute URL to your image in a template with ``{{ object.get_mug_shot_url }}``. +Databases and models +==================== + +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.db import connection + >>> connection.queries + [{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls', + 'time': '0.002'}] + +``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. + +``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? +---------------------------------------------- + +Yes. See `Integrating with a legacy database`_. + +.. _`Integrating with a legacy database`: http://www.djangoproject.com/documentation/legacy_databases/ + If I make changes to a model, how do I update the database? ----------------------------------------------------------- @@ -437,35 +479,24 @@ uniqueness at that level. Single-column primary keys are needed for things such as the admin interface to work; e.g., you need a simple way of being able to specify an object to edit or delete. -The database API -================ +How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type? +------------------------------------------------------------------------------------------------------------------ -How can I see the raw SQL queries Django is running? ----------------------------------------------------- +We try to avoid adding special cases in the Django code to accomodate all the +database-specific options such as table type, etc. If you'd like to use any of +these options, create an `SQL initial data file`_ that contains ``ALTER TABLE`` +statements that do what you want to do. The initial data files are executed in +your database after the ``CREATE TABLE`` statements. -Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do -this:: +For example, if you're using MySQL and want your tables to use the MyISAM table +type, create an initial data file and put something like this in it:: - >>> 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'}] + ALTER TABLE myapp_mytable ENGINE=MyISAM; -``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:: +As explained in the `SQL initial data file`_ documentation, this SQL file can +contain arbitrary SQL, so you can make any sorts of changes you need to make. - ``sql`` -- The raw SQL statement - ``time`` -- How long the statement took to execute, in seconds. - -``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? ----------------------------------------------- - -Yes. See `Integrating with a legacy database`_. - -.. _`Integrating with a legacy database`: http://www.djangoproject.com/documentation/legacy_databases/ +.. _SQL initial data file: http://www.djangoproject.com/documentation/model_api/#providing-initial-sql-data Why is Django leaking memory? ----------------------------- @@ -514,13 +545,26 @@ If you're sure your username and password are correct, make sure your user account has ``is_active`` and ``is_staff`` set to True. The admin site only allows access to users with those two fields both set to True. +How can I prevent the cache middleware from caching the admin site? +------------------------------------------------------------------- + +Set the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting to ``True``. See the +`cache documentation`_ for more information. + +.. _cache documentation: ../cache/#the-per-site-cache + How do I automatically set a field's value to the user who last edited the object in the admin? ----------------------------------------------------------------------------------------------- -At this point, you can't do this. But it's an oft-requested feature, so we're -discussing how it can be implemented. The problem is we don't want to couple -the model layer with the admin layer with the request layer (to get the current -user). It's a tricky problem. +At this point, Django doesn't have an official way to do this. But it's an oft-requested +feature, so we're discussing how it can be implemented. The problem is we don't want to couple +the model layer with the admin layer with the request layer (to get the current user). It's a +tricky problem. + +One person hacked up a `solution that doesn't require patching Django`_, but note that it's an +unofficial solution, and there's no guarantee it won't break at some point. + +.. _solution that doesn't require patching Django: http://lukeplant.me.uk/blog.php?id=1107301634 How do I limit admin access so that objects can only be edited by the users who created them? --------------------------------------------------------------------------------------------- @@ -585,3 +629,21 @@ To create a user, you'll have to use the Python API. See `creating users`_ for full info. .. _creating users: http://www.djangoproject.com/documentation/authentication/#creating-users + +Contributing code +================= + +I submitted a bug fix in the ticket system several weeks ago. Why are you ignoring my patch? +-------------------------------------------------------------------------------------------- + +Don't worry: We're not ignoring you! + +It's important to understand there is a difference between "a ticket is being +ignored" and "a ticket has not been attended to yet." Django's ticket system +contains hundreds of open tickets, of various degrees of impact on end-user +functionality, and Django's developers have to review and prioritize. + +Besides, if your feature request stands no chance of inclusion in Django, we +won't ignore it -- we'll just close the ticket. So if your ticket is still +open, it doesn't mean we're ignoring you; it just means we haven't had time to +look at it yet. diff --git a/docs/fastcgi.txt b/docs/fastcgi.txt index 41b9561b6d..41d50d97a1 100644 --- a/docs/fastcgi.txt +++ b/docs/fastcgi.txt @@ -2,7 +2,7 @@ How to use Django with FastCGI ============================== -Although the current preferred setup for running Django is Apache_ with +Although the `current preferred setup`_ for running Django is Apache_ with `mod_python`_, many people use shared hosting, on which FastCGI is the only viable option. In some setups, FastCGI also allows better security -- and, possibly, better performance -- than mod_python. @@ -17,6 +17,7 @@ served with no startup time. Unlike mod_python (or `mod_perl`_), a FastCGI process doesn't run inside the Web server process, but in a separate, persistent process. +.. _current preferred setup: http://www.djangoproject.com/documentation/modpython/ .. _Apache: http://httpd.apache.org/ .. _mod_python: http://www.modpython.org/ .. _mod_perl: http://perl.apache.org/ @@ -35,6 +36,16 @@ persistent process. security benefit on shared systems, because it means you can secure your code from other users. +Prerequisite: flup +================== + +Before you can start using FastCGI with Django, you'll need to install flup_, +which is a Python library for dealing with FastCGI. Make sure to use the latest +Subversion snapshot of flup, as some users have reported stalled pages with +older flup versions. + +.. _flup: http://www.saddi.com/software/flup/ + Starting your FastCGI server ============================ @@ -120,18 +131,53 @@ Apache setup ============ To use Django with Apache and FastCGI, you'll need Apache installed and -configured, with mod_fastcgi installed and enabled. Consult the Apache +configured, with `mod_fastcgi`_ installed and enabled. Consult the Apache documentation for instructions. -Add the following to your ``httpd.conf``:: +Once you've got that set up, point Apache at your Django FastCGI instance by +editing the ``httpd.conf`` (Apache configuration) file. You'll need to do two +things: + + * Use the ``FastCGIExternalServer`` directive to specify the location of + your FastCGI server. + * Use ``mod_rewrite`` to point URLs at FastCGI as appropriate. + +.. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html + +Specifying the location of the FastCGI server +--------------------------------------------- + +The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI +server. As the `FastCGIExternalServer docs`_ explain, you can specify either a +``socket`` or a ``host``. Here are examples of both:: - # Connect to FastCGI via a socket / named pipe + # Connect to FastCGI via a socket / named pipe. FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock - # Connect to FastCGI via a TCP host/port - # FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033 - <VirtualHost 64.92.160.91> - ServerName mysite.com + # Connect to FastCGI via a TCP host/port. + FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033 + +In either case, the file ``/home/user/public_html/mysite.fcgi`` doesn't +actually have to exist. It's just a URL used by the Web server internally -- a +hook for signifying which requests at a URL should be handled by FastCGI. (More +on this in the next section.) + +.. _FastCGIExternalServer docs: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer + +Using mod_rewrite to point URLs at FastCGI +------------------------------------------ + +The second step is telling Apache to use FastCGI for URLs that match a certain +pattern. To do this, use the `mod_rewrite`_ module and rewrite URLs to +``mysite.fcgi`` (or whatever you specified in the ``FastCGIExternalServer`` +directive, as explained in the previous section). + +In this example, we tell Apache to use FastCGI to handle any request that +doesn't represent a file on the filesystem and doesn't start with ``/media/``. +This is probably the most common case, if you're using Django's admin site:: + + <VirtualHost 12.34.56.78> + ServerName example.com DocumentRoot /home/user/public_html Alias /media /home/user/python/django/contrib/admin/media RewriteEngine On @@ -140,22 +186,18 @@ Add the following to your ``httpd.conf``:: RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] </VirtualHost> -Note that while you have to specify a mysite.fcgi, that this file doesn't -actually have to exist. It is just an internal URL to the webserver which -signifies that any requests to that URL will go to the external FastCGI -server. +.. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html -LigHTTPd Setup +lighttpd setup ============== -LigHTTPd is a light-weight asynchronous web-server, which is commonly used -for serving static files. However, it supports FastCGI natively, and as such -is a very good choice for serving both static and dynamic media, if your site -does not have any apache-specific components. +lighttpd is a lightweight Web server commonly used for serving static files. It +supports FastCGI natively and, thus, is a good choice for serving both static +and dynamic pages, if your site doesn't have any Apache-specific needs. Make sure ``mod_fastcgi`` is in your modules list, somewhere after -mod_rewrite and mod_access, but not after mod_accesslog. You'll probably -want mod_alias as well, for serving admin media. +``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll +probably want ``mod_alias`` as well, for serving admin media. Add the following to your lighttpd config file:: @@ -165,7 +207,7 @@ Add the following to your lighttpd config file:: "main" => ( # Use host / port instead of socket for TCP fastcgi # "host" => "127.0.0.1", - # "port" => 3033, + # "port" => 3033, "socket" => "/home/user/mysite.sock", "check-local" => "disable", ) @@ -181,14 +223,15 @@ Add the following to your lighttpd config file:: "^(/.*)$" => "/mysite.fcgi$1", ) -Running multiple django sites on one LigHTTPd +Running multiple Django sites on one lighttpd --------------------------------------------- -LigHTTPd allows you to use what is called conditional configuration to allow -configuration to be customized per-host. In order to specify multiple fastcgi -sites, simply add a conditional block around your fastcgi config for each site:: +lighttpd lets you use "conditional configuration" to allow configuration to be +customized per host. To specify multiple FastCGI sites, just add a conditional +block around your FastCGI config for each site:: - $HTTP["host"] == "www.website1.com" { + # If the hostname is 'www.example1.com'... + $HTTP["host"] == "www.example1.com" { server.document-root = "/foo/site1" fastcgi.server = ( ... @@ -196,7 +239,8 @@ sites, simply add a conditional block around your fastcgi config for each site:: ... } - $HTTP["host"] == "www.website2.com" { + # If the hostname is 'www.example2.com'... + $HTTP["host"] == "www.example2.com" { server.document-root = "/foo/site2" fastcgi.server = ( ... @@ -204,44 +248,44 @@ sites, simply add a conditional block around your fastcgi config for each site:: ... } -You can also run multiple django installations on the same site simply by -specifying multiple entries in the ``fastcgi.server`` directive, add one -fastcgi host for each. +You can also run multiple Django installations on the same site simply by +specifying multiple entries in the ``fastcgi.server`` directive. Add one +FastCGI host for each. -Running Django on a shared-hosting provider -=========================================== +Running Django on a shared-hosting provider with Apache +======================================================= -For many users on shared-hosting providers, you aren't able to run your own -server daemons nor do they have access to the httpd.conf of their webserver. -However, it is still possible to run Django using webserver-spawned processes. +Many shared-hosting providers don't allow you to run your own server daemons or +edit the ``httpd.conf`` file. In these cases, it's still possible to run Django +using Web server-spawned processes. .. admonition:: Note - If you are using webserver-managed processes, there's no need for you - to start the FastCGI server on your own. Apache will spawn a number - of processes, scaling as it needs to. + If you're using Web server-spawned processes, as explained in this section, + there's no need for you to start the FastCGI server on your own. Apache + will spawn a number of processes, scaling as it needs to. -In your web root directory, add this to a file named .htaccess :: +In your Web root directory, add this to a file named ``.htaccess`` :: AddHandler fastcgi-script .fcgi RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] -Now you must add a small shim script in order for apache to properly -spawn your FastCGI program. Create a mysite.fcgi and place it in your -web directory, making it executable :: +Then, create a small script that tells Apache how to spawn your FastCGI +program. Create a file ``mysite.fcgi`` and place it in your Web directory, and +be sure to make it executable :: #!/usr/bin/python import sys, os - # add a custom pythonpath + # Add a custom Python path. sys.path.insert(0, "/home/user/python") - # switch to the directory of your project. (optional) + # Switch to the directory of your project. (Optional.) # os.chdir("/home/user/myproject") - # change to the name of your app's settings module + # Set the DJANGO_SETTINGS_MODULE environment variable. os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings" from django.core.servers.fastcgi import runfastcgi @@ -250,13 +294,13 @@ web directory, making it executable :: Restarting the spawned server ----------------------------- -If you change the code of your site, to make apache re-load your django -application, you do not need to restart the server. Simply re-upload or -edit your ``mysite.fcgi`` in such a way that the timestamp on the file -will change. When apache sees that the file has been updated, it will -restart your django application for you. +If you change any Python code on your site, you'll need to tell FastCGI the +code has changed. But there's no need to restart Apache in this case. Rather, +just reupload ``mysite.fcgi``, or edit the file, so that the timestamp on the +file will change. When Apache sees the file has been updated, it will restart +your Django application for you. -If you have access to a command shell on a unix system, restarting the -server can be done with the ``touch`` command:: +If you have access to a command shell on a Unix system, you can accomplish this +easily by using the ``touch`` command:: touch mysite.fcgi diff --git a/docs/forms.txt b/docs/forms.txt index 5026bc1bab..67408f3c5d 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -50,7 +50,7 @@ model that "knows" how to create or modify instances of that model and how to validate data for the object. Manipulators come in two flavors: ``AddManipulators`` and ``ChangeManipulators``. Functionally they are quite similar, but the former knows how to create new instances of the model, while -the later modifies existing instances. Both types of classes are automatically +the latter modifies existing instances. Both types of classes are automatically created when you define a new class:: >>> from mysite.myapp.models import Place @@ -404,6 +404,43 @@ Here's a simple function that might drive the above form:: errors = new_data = {} form = forms.FormWrapper(manipulator, new_data, errors) return render_to_response('contact_form.html', {'form': form}) + +``FileField`` and ``ImageField`` special cases +============================================== + +Dealing with ``FileField`` and ``ImageField`` objects is a little more +complicated. + +First, you'll need to make sure that your ``<form>`` element correctly defines +the ``enctype`` as ``"multipart/form-data"``, in order to upload files:: + + <form enctype="multipart/form-data" method="post" action="/foo/"> + +Next, you'll need to treat the field in the template slightly differently. A +``FileField`` or ``ImageField`` is represented by *two* HTML form elements. + +For example, given this field in a model:: + + photo = model.ImageField('/path/to/upload/location') + +You'd need to display two formfields in the template:: + + <p><label for="id_photo">Photo:</label> {{ form.photo }}{{ form.photo_file }}</p> + +The first bit (``{{ form.photo }}``) displays the currently-selected file, +while the second (``{{ form.photo_file }}``) actually contains the file upload +form field. Thus, at the validation layer you need to check the ``photo_file`` +key. + +Finally, in your view, make sure to access ``request.FILES``, rather than +``request.POST``, for the uploaded files. This is necessary because +``request.POST`` does not contain file-upload data. + +For example, following the ``new_data`` convention, you might do something like +this:: + + new_data = request.POST.copy() + new_data.update(request.FILES) Validators ========== diff --git a/docs/generic_views.txt b/docs/generic_views.txt index d14fe12418..aab878467f 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -148,7 +148,8 @@ are views for displaying drilldown pages for date-based data. **Description:** A top-level index page showing the "latest" objects, by date. Objects with -a date in the *future* are not included. +a date in the *future* are not included unless you set ``allow_future`` to +``True``. **Required arguments:** @@ -185,6 +186,11 @@ a date in the *future* are not included. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template @@ -217,7 +223,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A yearly archive page showing all available months in a given year. Objects -with a date in the *future* are not displayed. +with a date in the *future* are not displayed unless you set ``allow_future`` +to ``True``. **Required arguments:** @@ -265,6 +272,11 @@ with a date in the *future* are not displayed. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template @@ -296,7 +308,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A monthly archive page showing all objects in a given month. Objects with a -date in the *future* are not displayed. +date in the *future* are not displayed unless you set ``allow_future`` to +``True``. **Required arguments:** @@ -346,6 +359,11 @@ date in the *future* are not displayed. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template @@ -378,7 +396,7 @@ In addition to ``extra_context``, the template's context will be: **Description:** A weekly archive page showing all objects in a given week. Objects with a date -in the *future* are not displayed. +in the *future* are not displayed unless you set ``allow_future`` to ``True``. **Required arguments:** @@ -422,6 +440,11 @@ in the *future* are not displayed. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template @@ -445,7 +468,8 @@ In addition to ``extra_context``, the template's context will be: **Description:** A day archive page showing all objects in a given day. Days in the future throw -a 404 error, regardless of whether any objects exist for future days. +a 404 error, regardless of whether any objects exist for future days, unless +you set ``allow_future`` to ``True``. **Required arguments:** @@ -501,6 +525,11 @@ a 404 error, regardless of whether any objects exist for future days. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template @@ -537,7 +566,9 @@ and today's date is used instead. **Description:** -A page representing an individual object. +A page representing an individual object. If the object has a date value in the +future, the view will throw a 404 error by default, unless you set +``allow_future`` to ``True``. **Required arguments:** @@ -604,6 +635,11 @@ A page representing an individual object. * ``mimetype``: The MIME type to use for the resulting document. Defaults to the value of the ``DEFAULT_MIME_TYPE`` setting. + * ``allow_future``: A boolean specifying whether to include "future" + objects on this page, where "future" means objects in which the field + specified in ``date_field`` is greater than the current date/time. By + default, this is ``False``. + **Template name:** If ``template_name`` isn't specified, this view will use the template diff --git a/docs/i18n.txt b/docs/i18n.txt index 1220ea95b3..e12900c2f9 100644 --- a/docs/i18n.txt +++ b/docs/i18n.txt @@ -35,12 +35,25 @@ How to internationalize your app: in three steps support. 3. Activate the locale middleware in your Django settings. - .. admonition:: Behind the scenes Django's translation machinery uses the standard ``gettext`` module that comes with Python. +If you don't need internationalization +====================================== + +Django's internationalization hooks are on by default, and that means there's a +bit of i18n-related overhead in certain places of the framework. If you don't +use internationalization, you should take the two seconds to set +``USE_I18N = False`` in your settings file. If ``USE_I18N`` is set to +``False``, then Django will make some optimizations so as not to load the +internationalization machinery. + +See the `documentation for USE_I18N`_. + +.. _documentation for USE_I18N: http://www.djangoproject.com/documentation/settings/#use-i18n + How to specify translation strings ================================== @@ -211,11 +224,18 @@ block:: This will have {{ myvar }} inside. {% endblocktrans %} +If you need to bind more than one expression inside a ``blocktrans`` tag, +separate the pieces with ``and``:: + + {% blocktrans with book|title as book_t and author|title as author_t %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + To pluralize, specify both the singular and plural forms with the ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and ``{% endblocktrans %}``. Example:: - {% blocktrans count list|counted as counter %} + {% blocktrans count list|count as counter %} There is only one {{ name }} object. {% plural %} There are {{ counter }} {{ name }} objects. @@ -293,7 +313,7 @@ marked for translation. It creates (or updates) a message file in the directory ``conf/locale``. In the ``de`` example, the file will be ``conf/locale/de/LC_MESSAGES/django.po``. -If run over your project source tree or your appliation source tree, it will +If run over your project source tree or your application source tree, it will do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES`` (note the missing ``conf`` prefix). @@ -336,7 +356,7 @@ A quick explanation: Long messages are a special case. There, the first string directly after the ``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be written over the next few lines as one string per line. Those strings are -directlyconcatenated. Don't forget trailing spaces within the strings; +directly concatenated. Don't forget trailing spaces within the strings; otherwise, they'll be tacked together without whitespace! .. admonition:: Mind your charset @@ -439,7 +459,7 @@ Notes: ``de``. * Only languages listed in the `LANGUAGES setting`_ can be selected. If you want to restrict the language selection to a subset of provided - languages (because your appliaction doesn't provide all those languages), + languages (because your application doesn't provide all those languages), set ``LANGUAGES`` to a list of languages. For example:: LANGUAGES = ( @@ -452,6 +472,30 @@ Notes: en-us). .. _LANGUAGES setting: http://www.djangoproject.com/documentation/settings/#languages + + * If you define a custom ``LANGUAGES`` setting, as explained in the + previous bullet, it's OK to mark the languages as translation strings + -- but use a "dummy" ``gettext()`` function, not the one in + ``django.utils.translation``. You should *never* import + ``django.utils.translation`` from within your settings file, because that + module in itself depends on the settings, and that would cause a circular + import. + + The solution is to use a "dummy" ``gettext()`` function. Here's a sample + settings file:: + + gettext = lambda s: s + + LANGUAGES = ( + ('de', gettext('German')), + ('en', gettext('English')), + ) + + With this arrangement, ``make-messages.py`` will still find and mark + these strings for translation, but the translation won't happen at + runtime -- so you'll have to remember to wrap the languages in the *real* + ``gettext()`` in any code that uses ``LANGUAGES`` at runtime. + * The ``LocaleMiddleware`` can only select languages for which there is a Django-provided base translation. If you want to provide translations for your application that aren't already in the set of translations @@ -610,7 +654,7 @@ The ``javascript_catalog`` view ------------------------------- The main solution to these problems is the ``javascript_catalog`` view, which -sends out a JavaScript code library with functions that mimick the ``gettext`` +sends out a JavaScript code library with functions that mimic the ``gettext`` interface, plus an array of translation strings. Those translation strings are taken from the application, project or Django core, according to what you specify in either the {{{info_dict}}} or the URL. @@ -628,7 +672,7 @@ You hook it up like this:: Each string in ``packages`` should be in Python dotted-package syntax (the same format as the strings in ``INSTALLED_APPS``) and should refer to a package that contains a ``locale`` directory. If you specify multiple packages, all -those catalogs aremerged into one catalog. This is useful if you have +those catalogs are merged into one catalog. This is useful if you have JavaScript that uses strings from different applications. You can make the view dynamic by putting the packages into the URL pattern:: diff --git a/docs/install.txt b/docs/install.txt index 800c49b596..fb1bd73122 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -77,9 +77,9 @@ It's easy either way. Installing the official version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Download Django-0.91.tar.gz from our `download page`_. -2. ``tar xzvf Django-0.91.tar.gz`` -3. ``cd Django-0.91`` +1. Download Django-0.95.tar.gz from our `download page`_. +2. ``tar xzvf Django-0.95.tar.gz`` +3. ``cd Django-0.95`` 4. ``sudo python setup.py install`` Note that the last command will automatically download and install setuptools_ @@ -89,14 +89,6 @@ connection. This will install Django in your Python installation's ``site-packages`` directory. -.. note:: - - Due to recent backwards-incompatible changes, it is strongly recommended - that you use the development version (below) for any new applications or - if you are just starting to work with Django. The 0.91 release is a - dead-end branch that is primarily of use for supporting legacy Django - applications. - .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools Installing the development version diff --git a/docs/model-api.txt b/docs/model-api.txt index 0dc98416a3..c369508c65 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -1225,6 +1225,51 @@ A few special cases to note about ``list_display``: return self.birthday.strftime('%Y')[:3] + "0's" decade_born_in.short_description = 'Birth decade' + * If the string given is a method of the model, Django will HTML-escape the + output by default. If you'd rather not escape the output of the method, + give the method an ``allow_tags`` attribute whose value is ``True``. + + Here's a full example model:: + + class Person(models.Model): + first_name = models.CharField(maxlength=50) + last_name = models.CharField(maxlength=50) + color_code = models.CharField(maxlength=6) + + class Admin: + list_display = ('first_name', 'last_name', 'colored_name') + + def colored_name(self): + return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) + colored_name.allow_tags = True + +``list_display_links`` +---------------------- + +Set ``list_display_links`` to control which fields in ``list_display`` should +be linked to the "change" page for an object. + +By default, the change list page will link the first column -- the first field +specified in ``list_display`` -- to the change page for each item. But +``list_display_links`` lets you change which columns are linked. Set +``list_display_links`` to a list or tuple of field names (in the same format as +``list_display``) to link. + +``list_display_links`` can specify one or many field names. As long as the +field names appear in ``list_display``, Django doesn't care how many (or how +few) fields are linked. The only requirement is: If you want to use +``list_display_links``, you must define ``list_display``. + +In this example, the ``first_name`` and ``last_name`` fields will be linked on +the change list page:: + + class Admin: + list_display = ('first_name', 'last_name', 'birthday') + list_display_links = ('first_name', 'last_name') + +Finally, note that in order to use ``list_display_links``, you must define +``list_display``, too. + ``list_filter`` --------------- diff --git a/docs/modpython.txt b/docs/modpython.txt index 0c0219e2e9..b88874d3d3 100644 --- a/docs/modpython.txt +++ b/docs/modpython.txt @@ -10,15 +10,17 @@ Python code into memory when the server starts. Code stays in memory throughout the life of an Apache process, which leads to significant performance gains over other server arrangements. -Django requires Apache 2.x and mod_python 3.x. +Django requires Apache 2.x and mod_python 3.x, and you should use Apache's +`prefork MPM`_, as opposed to the `worker MPM`_. -We recommend you use Apache's `prefork MPM`_, as opposed to the `worker MPM`_. +You may also be interested in `How to use Django with FastCGI`_. .. _Apache: http://httpd.apache.org/ .. _mod_python: http://www.modpython.org/ .. _mod_perl: http://perl.apache.org/ .. _prefork MPM: http://httpd.apache.org/docs/2.2/mod/prefork.html .. _worker MPM: http://httpd.apache.org/docs/2.2/mod/worker.html +.. _How to use Django with FastCGI: http://www.djangoproject.com/documentation/fastcgi/ Basic configuration =================== diff --git a/docs/outputting_pdf.txt b/docs/outputting_pdf.txt index a58cf2c217..edd34aca24 100644 --- a/docs/outputting_pdf.txt +++ b/docs/outputting_pdf.txt @@ -110,7 +110,7 @@ efficient. Here's the above "Hello World" example rewritten to use from cStringIO import StringIO from reportlab.pdfgen import canvas - from django.utils.httpwrappers import HttpResponse + from django.http import HttpResponse def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. diff --git a/docs/release_notes_0.95.txt b/docs/release_notes_0.95.txt new file mode 100644 index 0000000000..e5b89e5a7a --- /dev/null +++ b/docs/release_notes_0.95.txt @@ -0,0 +1,126 @@ +================================= +Django version 0.95 release notes +================================= + + +Welcome to the Django 0.95 release. + +This represents a significant advance in Django development since the 0.91 +release in January 2006. The details of every change in this release would be +too extensive to list in full, but a summary is presented below. + +Suitability and API stability +============================= + +This release is intended to provide a stable reference point for developers +wanting to work on production-level applications that use Django. + +However, it's not the 1.0 release, and we'll be introducing further changes +before 1.0. For a clear look at which areas of the framework will change (and +which ones will *not* change) before 1.0, see the api-stability.txt file, which +lives in the docs/ directory of the distribution. + +You may have a need to use some of the features that are marked as +"subject to API change" in that document, but that's OK with us as long as it's +OK with you, and as long as you understand APIs may change in the future. + +Fortunately, most of Django's core APIs won't be changing before version 1.0. +There likely won't be as big of a change between 0.95 and 1.0 versions as there +was between 0.91 and 0.95. + +Changes and new features +======================== + +The major changes in this release (for developers currently using the 0.91 +release) are a result of merging the 'magic-removal' branch of development. +This branch removed a number of constraints in the way Django code had to be +written that were a consequence of decisions made in the early days of Django, +prior to its open-source release. It's now possible to write more natural, +Pythonic code that works as expected, and there's less "black magic" happening +behind the scenes. + +Aside from that, another main theme of this release is a dramatic increase in +usability. We've made countless improvements in error messages, documentation, +etc., to improve developers' quality of life. + +The new features and changes introduced in 0.95 include: + + * Django now uses a more consistent and natural filtering interface for + retrieving objects from the database. + + * User-defined models, functions and constants now appear in the module + namespace they were defined in. (Previously everything was magically + transferred to the django.models.* namespace.) + + * Some optional applications, such as the FlatPage, Sites and Redirects + apps, have been decoupled and moved into django.contrib. If you don't + want to use these applications, you no longer have to install their + database tables. + + * Django now has support for managing database transactions. + + * We've added the ability to write custom authentication and authorization + backends for authenticating users against alternate systems, such as + LDAP. + + * We've made it easier to add custom table-level functions to models, + through a new "Manager" API. + + * It's now possible to use Django without a database. This simply means + that the framework no longer requires you to have a working database set + up just to serve dynamic pages. In other words, you can just use + URLconfs/views on their own. Previously, the framework required that a + database be configured, regardless of whether you actually used it. + + * It's now more explicit and natural to override save() and delete() + methods on models, rather than needing to hook into the pre_save() and + post_save() method hooks. + + * Individual pieces of the framework now can be configured without + requiring the setting of an environment variable. This permits use of, + for example, the Django templating system inside other applications. + + * More and more parts of the framework have been internationalized, as + we've expanded internationalization (i18n) support. The Django + codebase, including code and templates, has now been translated, at least + in part, into 31 languages. From Arabic to Chinese to Hungarian to Welsh, + it is now possible to use Django's admin site in your native language. + +The number of changes required to port from 0.91-compatible code to the 0.95 +code base are significant in some cases. However, they are, for the most part, +reasonably routine and only need to be done once. A list of the necessary +changes is described in the `Removing The Magic`_ wiki page. There is also an +easy checklist_ for reference when undertaking the porting operation. + +.. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 + +Problem reports and getting help +================================ + +Need help resolving a problem with Django? The documentation in the +distribution is also available online_ at the `Django website`_. The FAQ_ +document is especially recommended, as it contains a number of issues that +come up time and again. + +For more personalized help, the `django-users`_ mailing list is a very active +list, with more than 2,000 subscribers who can help you solve any sort of +Django problem. We recommend you search the archives first, though, because +many common questions appear with some regularity, and any particular problem +may already have been answered. + +Finally, for those who prefer the more immediate feedback offered by IRC, +there's a #django channel or irc.freenode.net that is regularly populated by +Django users and developers from around the world. Friendly people are usually +available at any hour of the day -- to help, or just to chat. + +.. _online: http://www.djangoproject.com/documentation/ +.. _Django website: http://www.djangoproject.com/ +.. _FAQ: http://www.djangoproject.com/documentation/faq/ +.. _django-users: http://groups.google.com/group/django-users + +Thanks for using Django! + +The Django Team +July 2006 + diff --git a/docs/request_response.txt b/docs/request_response.txt index 0bcb3a7f5b..7480a6d3bb 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -106,12 +106,12 @@ All attributes except ``session`` should be considered read-only. A ``django.contrib.auth.models.User`` object representing the currently logged-in user. If the user isn't currently logged in, ``user`` will be set to an instance of ``django.contrib.auth.models.AnonymousUser``. You - can tell them apart with ``is_anonymous()``, like so:: + can tell them apart with ``is_authenticated()``, like so:: - if request.user.is_anonymous(): - # Do something for anonymous users. - else: + if request.user.is_authenticated(): # Do something for logged-in users. + else: + # Do something for anonymous users. ``user`` is only available if your Django installation has the ``AuthenticationMiddleware`` activated. For more, see @@ -134,21 +134,25 @@ Methods ------- ``__getitem__(key)`` - Returns the GET/POST value for the given key, checking POST first, then - GET. Raises ``KeyError`` if the key doesn't exist. + Returns the GET/POST value for the given key, checking POST first, then + GET. Raises ``KeyError`` if the key doesn't exist. - This lets you use dictionary-accessing syntax on an ``HttpRequest`` - instance. Example: ``request["foo"]`` would return ``True`` if either - ``request.POST`` or ``request.GET`` had a ``"foo"`` key. + This lets you use dictionary-accessing syntax on an ``HttpRequest`` + instance. Example: ``request["foo"]`` would return ``True`` if either + ``request.POST`` or ``request.GET`` had a ``"foo"`` key. ``has_key()`` - Returns ``True`` or ``False``, designating whether ``request.GET`` or - ``request.POST`` has the given key. + Returns ``True`` or ``False``, designating whether ``request.GET`` or + ``request.POST`` has the given key. ``get_full_path()`` - Returns the ``path``, plus an appended query string, if applicable. + Returns the ``path``, plus an appended query string, if applicable. - Example: ``"/music/bands/the_beatles/?print=true"`` + Example: ``"/music/bands/the_beatles/?print=true"`` + +``is_secure()`` + Returns ``True`` if the request is secure; that is, if it was made with + HTTPS. QueryDict objects ----------------- diff --git a/docs/serialization.txt b/docs/serialization.txt new file mode 100644 index 0000000000..25199e7a50 --- /dev/null +++ b/docs/serialization.txt @@ -0,0 +1,102 @@ +========================== +Serializing Django objects +========================== + +.. note:: + + This API is currently under heavy development and may change -- + perhaps drastically -- in the future. + + You have been warned. + +Django's serialization framework provides a mechanism for "translating" Django +objects into other formats. Usually these other formats will be text-based and +used for sending Django objects over a wire, but it's possible for a +serializer to handle any format (text-based or not). + +Serializing data +---------------- + +At the highest level, serializing data is a very simple operation:: + + from django.core import serializers + data = serializers.serialize("xml", SomeModel.objects.all()) + +The arguments to the ``serialize`` function are the format to serialize the +data to (see `Serialization formats`_) and a QuerySet_ to serialize. +(Actually, the second argument can be any iterator that yields Django objects, +but it'll almost always be a QuerySet). + +.. _QuerySet: ../db_api/#retrieving-objects + +You can also use a serializer object directly:: + + xml_serializer = serializers.get_serializer("xml") + xml_serializer.serialize(queryset) + data = xml_serializer.getvalue() + +This is useful if you want to serialize data directly to a file-like object +(which includes a HTTPResponse_):: + + out = open("file.xml", "w") + xml_serializer.serialize(SomeModel.objects.all(), stream=out) + +.. _HTTPResponse: ../request_response/#httpresponse-objects + +Deserializing data +------------------ + +Deserializing data is also a fairly simple operation:: + + for obj in serializers.deserialize("xml", data): + do_something_with(obj) + +As you can see, the ``deserialize`` function takes the same format argument as +``serialize``, a string or stream of data, and returns an iterator. + +However, here it gets slightly complicated. The objects returned by the +``deserialize`` iterator *aren't* simple Django objects. Instead, they are +special ``DeserializedObject`` instances that wrap a created -- but unsaved -- +object and any associated relationship data. + +Calling ``DeserializedObject.save()`` saves the object to the database. + +This ensures that deserializing is a non-destructive operation even if the +data in your serialized representation doesn't match what's currently in the +database. Usually, working with these ``DeserializedObject`` instances looks +something like:: + + for deserialized_object in serializers.deserialize("xml", data): + if object_should_be_saved(deserialized_object): + obj.save() + +In other words, the usual use is to examine the deserialized objects to make +sure that they are "appropriate" for saving before doing so. Of course, if you trust your data source you could just save the object and move on. + +The Django object itself can be inspected as ``deserialized_object.object``. + +Serialization formats +--------------------- + +Django "ships" with a few included serializers: + + ========== ============================================================== + Identifier Information + ========== ============================================================== + ``xml`` Serializes to and from a simple XML dialect. + + ``json`` Serializes to and from JSON_ (using a version of simplejson_ + bundled with Django). + + ``python`` Translates to and from "simple" Python objects (lists, dicts, + strings, etc.). Not really all that useful on its own, but + used as a base for other serializers. + ========== ============================================================== + +.. _json: http://json.org/ +.. _simplejson: http://undefined.org/python/#simplejson + +Writing custom serializers +`````````````````````````` + +XXX ... diff --git a/docs/sessions.txt b/docs/sessions.txt index 2dba491159..c473d0a3db 100644 --- a/docs/sessions.txt +++ b/docs/sessions.txt @@ -10,18 +10,22 @@ Cookies contain a session ID -- not the data itself. Enabling sessions ================= -Sessions are implemented via middleware_. +Sessions are implemented via a piece of middleware_ and a Django model. -Turn session functionality on and off by editing the ``MIDDLEWARE_CLASSES`` -setting. To activate sessions, make sure ``MIDDLEWARE_CLASSES`` contains -``'django.contrib.sessions.middleware.SessionMiddleware'``. +To enable session functionality, do these two things: -The default ``settings.py`` created by ``django-admin.py startproject`` has -``SessionMiddleware`` activated. + * Edit the ``MIDDLEWARE_CLASSES`` setting and make sure + ``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. + The default ``settings.py`` created by ``django-admin.py startproject`` has + ``SessionMiddleware`` activated. + + * Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting, and + run ``manage.py syncdb`` to install the single database table that stores + session data. If you don't want to use sessions, you might as well remove the -``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES``. It'll save you a small -bit of overhead. +``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'`` +from your ``INSTALLED_APPS``. It'll save you a small bit of overhead. .. _middleware: http://www.djangoproject.com/documentation/middleware/ diff --git a/docs/settings.txt b/docs/settings.txt index 553736b280..099196e56e 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -107,15 +107,20 @@ For more, see the `diffsettings documentation`_. Using settings in Python code ============================= -In your Django apps, use settings by importing them from +In your Django apps, use settings by importing the object ``django.conf.settings``. Example:: - from django.conf.settings import DEBUG + from django.conf import settings - if DEBUG: + if settings.DEBUG: # Do something -Note that your code should *not* import from either ``global_settings`` or +Note that ``django.conf.settings`` isn't a module -- it's an object. So +importing individual settings is not possible:: + + from django.conf.settings import DEBUG # This won't work. + +Also note that your code should *not* import from either ``global_settings`` or your own settings file. ``django.conf.settings`` abstracts the concepts of default settings and site-specific settings; it presents a single interface. It also decouples the code that uses settings from the location of your @@ -127,9 +132,9 @@ Altering settings at runtime You shouldn't alter settings in your applications at runtime. For example, don't do this in a view:: - from django.conf.settings import DEBUG + from django.conf import settings - DEBUG = True # Don't do this! + settings.DEBUG = True # Don't do this! The only place you should assign to settings is in a settings file. @@ -496,6 +501,28 @@ specifies which languages are available for language selection. See the Generally, the default value should suffice. Only set this setting if you want to restrict language selection to a subset of the Django-provided languages. +If you define a custom ``LANGUAGES`` setting, it's OK to mark the languages as +translation strings (as in the default value displayed above) -- but use a +"dummy" ``gettext()`` function, not the one in ``django.utils.translation``. +You should *never* import ``django.utils.translation`` from within your +settings file, because that module in itself depends on the settings, and that +would cause a circular import. + +The solution is to use a "dummy" ``gettext()`` function. Here's a sample +settings file:: + + gettext = lambda s: s + + LANGUAGES = ( + ('de', gettext('German')), + ('en', gettext('English')), + ) + +With this arrangement, ``make-messages.py`` will still find and mark these +strings for translation, but the translation won't happen at runtime -- so +you'll have to remember to wrap the languages in the *real* ``gettext()`` in +any code that uses ``LANGUAGES`` at runtime. + MANAGERS -------- @@ -724,11 +751,22 @@ TIME_ZONE Default: ``'America/Chicago'`` A string representing the time zone for this installation. `See available choices`_. +(Note that list of available choices lists more than one on the same line; +you'll want to use just one of the choices for a given time zone. For instance, +one line says ``'Europe/London GB GB-Eire'``, but you should use the first bit +of that -- ``'Europe/London'`` -- as your ``TIME_ZONE`` setting.) Note that this is the time zone to which Django will convert all dates/times -- not necessarily the timezone of the server. For example, one server may serve multiple Django-powered sites, each with a separate time-zone setting. +Normally, Django sets the ``os.environ['TZ']`` variable to the time zone you +specify in the ``TIME_ZONE`` setting. Thus, all your views and models will +automatically operate in the correct time zone. However, if you're using the +manual configuration option (see below), Django will *not* touch the ``TZ`` +environment variable, and it'll be up to you to ensure your processes are +running in the correct environment. + USE_ETAGS --------- @@ -738,6 +776,16 @@ A boolean that specifies whether to output the "Etag" header. This saves bandwidth but slows down performance. This is only used if ``CommonMiddleware`` is installed (see the `middleware docs`_). +USE_I18N +-------- + +Default: ``True`` + +A boolean that specifies whether Django's internationalization system should be +enabled. This provides an easy way to turn it off, for performance. If this is +set to ``False``, Django will make some optimizations so as not to load the +internationalization machinery. + YEAR_MONTH_FORMAT ----------------- @@ -796,6 +844,15 @@ uppercase, with the same name as the settings described above. If a particular setting is not passed to ``configure()`` and is needed at some later point, Django will use the default setting value. +Configuring Django in this fashion is mostly necessary -- and, indeed, +recommended -- when you're using a piece of the framework inside a larger +application. + +Consequently, when configured via ``settings.configure()``, Django will not +make any modifications to the process environment variables. (See the +explanation of ``TIME_ZONE``, above, for why this would normally occur.) It's +assumed that you're already in full control of your environment in these cases. + Custom default settings ----------------------- diff --git a/docs/syndication_feeds.txt b/docs/syndication_feeds.txt index 4f77c4ff21..b00af200a0 100644 --- a/docs/syndication_feeds.txt +++ b/docs/syndication_feeds.txt @@ -134,7 +134,9 @@ put into those elements. If you don't create a template for either the title or description, the framework will use the template ``"{{ obj }}"`` by default -- that is, - the normal string representation of the object. + the normal string representation of the object. You can also change the + names of these two templates by specifying ``title_template`` and + ``description_template`` as attributes of your ``Feed`` class. * To specify the contents of ``<link>``, you have two options. For each item in ``items()``, Django first tries executing a ``get_absolute_url()`` method on that object. If that method doesn't @@ -342,6 +344,16 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas feed_type = feedgenerator.Rss201rev2Feed + # TEMPLATE NAMES -- Optional. These should be strings representing + # names of Django templates that the system should use in rendering the + # title and description of your feed items. Both are optional. + # If you don't specify one, or either, Django will use the template + # 'feeds/SLUG_title.html' and 'feeds/SLUG_description.html', where SLUG + # is the slug you specify in the URL. + + title_template = None + description_template = None + # TITLE -- One of the following three is required. The framework looks # for them in this order. @@ -415,7 +427,7 @@ This example illustrates all possible attributes and methods for a ``Feed`` clas author's e-mail as a normal Python string. """ - def author_name(self): + def author_email(self): """ Returns the feed's author's e-mail as a normal Python string. """ diff --git a/docs/templates.txt b/docs/templates.txt index 42947510d1..49d30018fe 100644 --- a/docs/templates.txt +++ b/docs/templates.txt @@ -47,7 +47,7 @@ explained later in this document.:: JavaScript and CSV. You can use the template language for any text-based format. - Oh, and one more thing: Making humans edit XML is masochistic! + Oh, and one more thing: Making humans edit XML is sadistic! Variables ========= @@ -363,10 +363,15 @@ extends Signal that this template extends a parent template. -This tag may be used in two ways: ``{% extends "base.html" %}`` (with quotes) -uses the literal value "base.html" as the name of the parent template to -extend, or ``{% extends variable %}`` uses the value of ``variable`` as the -name of the parent template to extend. +This tag can be used in two ways: + + * ``{% extends "base.html" %}`` (with quotes) uses the literal value + ``"base.html"`` as the name of the parent template to extend. + + * ``{% extends variable %}`` uses the value of ``variable``. If the variable + evaluates to a string, Django will use that string as the name of the + parent template. If the variable evaluates to a ``Template`` object, + Django will use that object as the parent template. See `Template inheritance`_ for more information. @@ -493,6 +498,11 @@ If you need to combine ``and`` and ``or`` to do advanced logic, just use nested {% endif %} {% endif %} +Multiple uses of the same logical operator are fine, as long as you use the +same operator. For example, this is valid:: + + {% if athlete_list or coach_list or parent_list or teacher_list %} + ifchanged ~~~~~~~~~ @@ -951,12 +961,26 @@ any string. pluralize ~~~~~~~~~ -Returns ``'s'`` if the value is not 1. +Returns a plural suffix if the value is not 1. By default, this suffix is ``'s'``. Example:: You have {{ num_messages }} message{{ num_messages|pluralize }}. +For words that require a suffix other than ``'s'``, you can provide an alternate +suffix as a parameter to the filter. + +Example:: + + You have {{ num_walruses }} walrus{{ num_walrus|pluralize:"es" }}. + +For words that don't pluralize by simple suffix, you can specify both a +singular and plural suffix, separated by a comma. + +Example:: + + You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}. + pprint ~~~~~~ diff --git a/docs/templates_python.txt b/docs/templates_python.txt index 5e3038ebb4..95ccfb3eab 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -198,21 +198,6 @@ some things to keep in mind: How invalid variables are handled ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In Django 0.91, if a variable doesn't exist, the template system fails -silently. The variable is replaced with an empty string:: - - >>> t = Template("My name is {{ my_name }}.") - >>> c = Context({"foo": "bar"}) - >>> t.render(c) - "My name is ." - -This applies to any level of lookup:: - - >>> t = Template("My name is {{ person.fname }} {{ person.lname }}.") - >>> c = Context({"person": {"fname": "Stan"}}) - >>> t.render(c) - "My name is Stan ." - If a variable doesn't exist, the template system inserts the value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` (the empty string) by default. @@ -357,7 +342,7 @@ django.core.context_processors.request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every -``DjangoContext`` will contain a variable ``request``, which is the current +``RequestContext`` will contain a variable ``request``, which is the current `HttpRequest object`_. Note that this processor is not enabled by default; you'll have to activate it. @@ -643,7 +628,7 @@ the current date/time, formatted according to a parameter given in the tag, in `strftime syntax`_. It's a good idea to decide the tag syntax before anything else. In our case, let's say the tag should be used like this:: - <p>The time is {% current_time "%Y-%M-%d %I:%M %p" %}.</p> + <p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p> .. _`strftime syntax`: http://www.python.org/doc/current/lib/module-time.html#l2h-1941 @@ -653,10 +638,10 @@ object:: from django import template def do_current_time(parser, token): try: - # Splitting by None == splitting by spaces. - tag_name, format_string = token.contents.split(None, 1) + # split_contents() knows not to split quoted strings. + tag_name, format_string = token.split_contents() except ValueError: - raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0] + raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents[0] if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name return CurrentTimeNode(format_string[1:-1]) @@ -667,7 +652,13 @@ Notes: example. * ``token.contents`` is a string of the raw contents of the tag. In our - example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``. + example, it's ``'current_time "%Y-%m-%d %I:%M %p"'``. + + * The ``token.split_contents()`` method separates the arguments on spaces + while keeping quoted strings together. The more straightforward + ``token.contents.split()`` wouldn't be as robust, as it would naively + split on *all* spaces, including those within quoted strings. It's a good + idea to always use ``token.split_contents()``. * This function is responsible for raising ``django.template.TemplateSyntaxError``, with helpful messages, for @@ -681,7 +672,7 @@ Notes: * The function returns a ``CurrentTimeNode`` with everything the node needs to know about this tag. In this case, it just passes the argument -- - ``"%Y-%M-%d %I:%M %p"``. The leading and trailing quotes from the + ``"%Y-%m-%d %I:%M %p"``. The leading and trailing quotes from the template tag are removed in ``format_string[1:-1]``. * The parsing is very low-level. The Django developers have experimented @@ -766,27 +757,24 @@ registers it with the template system. Our earlier ``current_time`` function could thus be written like this:: - # This version of do_current_time takes only a single argument and returns - # a string. - - def do_current_time(token): - try: - # Splitting by None == splitting by spaces. - tag_name, format_string = token.contents.split(None, 1) - except ValueError: - raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0] - if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): - raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name - return datetime.datetime.now().strftime(self.format_string[1:-1]) + def current_time(format_string): + return datetime.datetime.now().strftime(format_string) - register.simple_tag(do_current_time) + register.simple_tag(current_time) In Python 2.4, the decorator syntax also works:: - @simple_tag - def do_current_time(token): + @register.simple_tag + def current_time(token): ... +A couple of things to note about the ``simple_tag`` helper function: + * Only the (single) argument is passed into our function. + * Checking for the required number of arguments, etc, has already been + done by the time our function is called, so we don't need to do that. + * The quotes around the argument (if any) have already been stripped away, + so we just receive a plain string. + Inclusion tags ~~~~~~~~~~~~~~ @@ -844,7 +832,7 @@ loader, we'd register the tag like this:: As always, Python 2.4 decorator syntax works as well, so we could have written:: - @inclusion_tag('results.html') + @register.inclusion_tag('results.html') def show_results(poll): ... diff --git a/docs/transactions.txt b/docs/transactions.txt index c1cd5aa984..2b0755a257 100644 --- a/docs/transactions.txt +++ b/docs/transactions.txt @@ -2,7 +2,8 @@ Managing database transactions ============================== -Django gives you a few ways to control how database transactions are managed. +Django gives you a few ways to control how database transactions are managed, +if you're using a database that supports transactions. Django's default transaction behavior ===================================== @@ -144,3 +145,19 @@ Thus, this is best used in situations where you want to run your own transaction-controlling middleware or do something really strange. In almost all situations, you'll be better off using the default behavior, or the transaction middleware, and only modify selected functions as needed. + +Transactions in MySQL +===================== + +If you're using MySQL, your tables may or may not support transactions; it +depends on your MySQL version and the table types you're using. (By +"table types," we mean something like "InnoDB" or "MyISAM".) MySQL transaction +peculiarities are outside the scope of this article, but the MySQL site has +`information on MySQL transactions`_. + +If your MySQL setup does *not* support transactions, then Django will function +in auto-commit mode: Statements will be executed and committed as soon as +they're called. If your MySQL setup *does* support transactions, Django will +handle transactions as explained in this document. + +.. _information on MySQL transactions: http://dev.mysql.com/books/mysqlpress/mysql-tutorial/ch10.html diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt index c353e1ab4b..1113b603da 100644 --- a/docs/tutorial01.txt +++ b/docs/tutorial01.txt @@ -81,7 +81,7 @@ the following output on the command line:: Validating models... 0 errors found. - Django version 0.95 (post-magic-removal), using settings 'mysite.settings' + Django version 0.95, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). @@ -346,6 +346,8 @@ Note the following: the SQL to the database. If you're interested, also run the following commands: + * ``python manage.py validate polls`` -- Checks for any errors in the + construction of your models. * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data required for Django's admin framework and your models. diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt index 84eae3eb83..bc1717e67c 100644 --- a/docs/tutorial02.txt +++ b/docs/tutorial02.txt @@ -54,7 +54,8 @@ http://127.0.0.1:8000/admin/. You should see the admin's login screen: Enter the admin site ==================== -Now, try logging in. You should see the Django admin index page: +Now, try logging in. (You created a superuser account in the first part of this +tutorial, remember?) You should see the Django admin index page: .. image:: http://media.djangoproject.com/img/doc/tutorial/admin02t.png :alt: Django admin index page diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index 3a830eb76f..248d234043 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -189,7 +189,7 @@ publication date:: from django.http import HttpResponse def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date') + latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] output = ', '.join([p.question for p in latest_poll_list]) return HttpResponse(output) @@ -202,7 +202,7 @@ So let's use Django's template system to separate the design from Python:: from django.http import HttpResponse def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date') + latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] t = loader.get_template('polls/index.html') c = Context({ 'latest_poll_list': latest_poll_list, @@ -288,7 +288,7 @@ exception if a poll with the requested ID doesn't exist. A shortcut: get_object_or_404() ------------------------------- -It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the +It's a very common idiom to use ``get()`` and raise ``Http404`` if the object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view, rewritten:: @@ -313,8 +313,8 @@ exist. foremost design goals of Django is to maintain loose coupling. There's also a ``get_list_or_404()`` function, which works just as -``get_object_or_404()`` -- except using ``get_list()`` instead of -``get_object()``. It raises ``Http404`` if the list is empty. +``get_object_or_404()`` -- except using ``filter()`` instead of +``get()``. It raises ``Http404`` if the list is empty. Write a 404 (page not found) view ================================= diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index 8ef4a03c6d..f234ed0ce1 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -198,7 +198,7 @@ By default, the ``object_detail`` generic view uses a template called ``vote()``. Similarly, the ``object_list`` generic view uses a template called -``<app name>/<module name>_list.html``. Thus, rename ``poll/index.html`` to +``<app name>/<module name>_list.html``. Thus, rename ``polls/index.html`` to ``polls/poll_list.html``. Because we have more than one entry in the URLconf that uses ``object_detail`` @@ -206,7 +206,7 @@ for the polls app, we manually specify a template name for the results view: ``template_name='polls/results.html'``. Otherwise, both views would use the same template. Note that we use ``dict()`` to return an altered dictionary in place. -In previous versions of the tutorial, the templates have been provided with a context +In previous parts of the tutorial, the templates have been provided with a context that contains the ``poll` and ``latest_poll_list`` context variables. However, the generic views provide the variables ``object`` and ``object_list`` as context. Therefore, you need to change your templates to match the new context variables. diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 498a906d5e..6158014fc8 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -263,12 +263,12 @@ Here's the example URLconf from the `Django overview`_:: from django.conf.urls.defaults import * urlpatterns = patterns('', - (r'^articles/(\d{4})/$', 'myproject.news.views.year_archive'), - (r'^articles/(\d{4})/(\d{2})/$', 'myproject.news.views.month_archive'), - (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'myproject.news.views.article_detail'), + (r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'), ) -In this example, each view has a common prefix -- ``'myproject.news.views'``. +In this example, each view has a common prefix -- ``'mysite.news.views'``. Instead of typing that out for each entry in ``urlpatterns``, you can use the first argument to the ``patterns()`` function to specify a prefix to apply to each view function. @@ -277,7 +277,7 @@ With this in mind, the above example can be written more concisely as:: from django.conf.urls.defaults import * - urlpatterns = patterns('myproject.news.views', + urlpatterns = patterns('mysite.news.views', (r'^articles/(\d{4})/$', 'year_archive'), (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), @@ -389,3 +389,45 @@ to pass metadata and options to views. .. _generic views: http://www.djangoproject.com/documentation/generic_views/ .. _syndication framework: http://www.djangoproject.com/documentation/syndication/ + +Passing extra options to ``include()`` +-------------------------------------- + +**New in the Django development version.** + +Similarly, you can pass extra options to ``include()``. When you pass extra +options to ``include()``, *each* line in the included URLconf will be passed +the extra options. + +For example, these two URLconf sets are functionally identical: + +Set one:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner'), {'blogid': 3}), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + ) + +Set two:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner')), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), + (r'^about/$', 'mysite.views.about', {'blogid': 3}), + ) + +Note that extra options will *always* be passed to *every* line in the included +URLconf, regardless of whether the line's view actually accepts those options +as valid. For this reason, this technique is only useful if you're certain that +every view in the the included URLconf accepts the extra options you're passing. |
