diff options
author | Nishanth Amuluru | 2011-01-11 22:41:51 +0530 |
---|---|---|
committer | Nishanth Amuluru | 2011-01-11 22:41:51 +0530 |
commit | b03203c8cb991c16ac8a3d74c8c4078182d0bb48 (patch) | |
tree | 7cf13b2deacbfaaec99edb431b83ddd5ea734a52 /parts/django/docs/intro | |
parent | 0c50203cd9eb94b819883c3110922e873f003138 (diff) | |
download | pytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.tar.gz pytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.tar.bz2 pytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.zip |
removed all the buildout files
Diffstat (limited to 'parts/django/docs/intro')
31 files changed, 0 insertions, 2722 deletions
diff --git a/parts/django/docs/intro/_images/admin01.png b/parts/django/docs/intro/_images/admin01.png Binary files differdeleted file mode 100644 index 28f14d6..0000000 --- a/parts/django/docs/intro/_images/admin01.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin02.png b/parts/django/docs/intro/_images/admin02.png Binary files differdeleted file mode 100644 index 4b49ebb..0000000 --- a/parts/django/docs/intro/_images/admin02.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin02t.png b/parts/django/docs/intro/_images/admin02t.png Binary files differdeleted file mode 100644 index d7519d1..0000000 --- a/parts/django/docs/intro/_images/admin02t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin03.png b/parts/django/docs/intro/_images/admin03.png Binary files differdeleted file mode 100644 index 635226c..0000000 --- a/parts/django/docs/intro/_images/admin03.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin03t.png b/parts/django/docs/intro/_images/admin03t.png Binary files differdeleted file mode 100644 index 94273cb..0000000 --- a/parts/django/docs/intro/_images/admin03t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin04.png b/parts/django/docs/intro/_images/admin04.png Binary files differdeleted file mode 100644 index 982420a..0000000 --- a/parts/django/docs/intro/_images/admin04.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin04t.png b/parts/django/docs/intro/_images/admin04t.png Binary files differdeleted file mode 100644 index a2ec8bb..0000000 --- a/parts/django/docs/intro/_images/admin04t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin05.png b/parts/django/docs/intro/_images/admin05.png Binary files differdeleted file mode 100644 index b424393..0000000 --- a/parts/django/docs/intro/_images/admin05.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin05t.png b/parts/django/docs/intro/_images/admin05t.png Binary files differdeleted file mode 100644 index a5da950..0000000 --- a/parts/django/docs/intro/_images/admin05t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin06.png b/parts/django/docs/intro/_images/admin06.png Binary files differdeleted file mode 100644 index 5f24d4e..0000000 --- a/parts/django/docs/intro/_images/admin06.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin06t.png b/parts/django/docs/intro/_images/admin06t.png Binary files differdeleted file mode 100644 index fb65e0a..0000000 --- a/parts/django/docs/intro/_images/admin06t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin07.png b/parts/django/docs/intro/_images/admin07.png Binary files differdeleted file mode 100644 index b21022f..0000000 --- a/parts/django/docs/intro/_images/admin07.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin08.png b/parts/django/docs/intro/_images/admin08.png Binary files differdeleted file mode 100644 index ddac57e..0000000 --- a/parts/django/docs/intro/_images/admin08.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin08t.png b/parts/django/docs/intro/_images/admin08t.png Binary files differdeleted file mode 100644 index 83773bb..0000000 --- a/parts/django/docs/intro/_images/admin08t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin09.png b/parts/django/docs/intro/_images/admin09.png Binary files differdeleted file mode 100644 index ba7de1b..0000000 --- a/parts/django/docs/intro/_images/admin09.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin10.png b/parts/django/docs/intro/_images/admin10.png Binary files differdeleted file mode 100644 index 07a9bf3..0000000 --- a/parts/django/docs/intro/_images/admin10.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin11.png b/parts/django/docs/intro/_images/admin11.png Binary files differdeleted file mode 100644 index 6c583fd..0000000 --- a/parts/django/docs/intro/_images/admin11.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin11t.png b/parts/django/docs/intro/_images/admin11t.png Binary files differdeleted file mode 100644 index af792b8..0000000 --- a/parts/django/docs/intro/_images/admin11t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin12.png b/parts/django/docs/intro/_images/admin12.png Binary files differdeleted file mode 100644 index aac5c0d..0000000 --- a/parts/django/docs/intro/_images/admin12.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin13.png b/parts/django/docs/intro/_images/admin13.png Binary files differdeleted file mode 100644 index 49a5950..0000000 --- a/parts/django/docs/intro/_images/admin13.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin13t.png b/parts/django/docs/intro/_images/admin13t.png Binary files differdeleted file mode 100644 index 7dc01e1..0000000 --- a/parts/django/docs/intro/_images/admin13t.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin14.png b/parts/django/docs/intro/_images/admin14.png Binary files differdeleted file mode 100644 index b1f4a54..0000000 --- a/parts/django/docs/intro/_images/admin14.png +++ /dev/null diff --git a/parts/django/docs/intro/_images/admin14t.png b/parts/django/docs/intro/_images/admin14t.png Binary files differdeleted file mode 100644 index 86c3acc..0000000 --- a/parts/django/docs/intro/_images/admin14t.png +++ /dev/null diff --git a/parts/django/docs/intro/index.txt b/parts/django/docs/intro/index.txt deleted file mode 100644 index bc61be7..0000000 --- a/parts/django/docs/intro/index.txt +++ /dev/null @@ -1,36 +0,0 @@ -Getting started -=============== - -New to Django? Or to Web development in general? Well, you came to the right -place: read this material to quickly get up and running. - -.. toctree:: - :maxdepth: 1 - - overview - install - tutorial01 - tutorial02 - tutorial03 - tutorial04 - whatsnext - -.. seealso:: - - If you're new to Python_, you might want to start by getting an idea of what - the language is like. Django is 100% Python, so if you've got minimal - comfort with Python you'll probably get a lot more out of Django. - - If you're new to programming entirely, you might want to start with this - `list of Python resources for non-programmers`_ - - If you already know a few other languages and want to get up to speed with - Python quickly, we recommend `Dive Into Python`_ (also available in a - `dead-tree version`_). If that's not quite your style, there are quite - a few other `books about Python`_. - - .. _python: http://python.org/ - .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers - .. _dive into python: http://diveintopython.org/ - .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 - .. _books about Python: http://wiki.python.org/moin/PythonBooks
\ No newline at end of file diff --git a/parts/django/docs/intro/install.txt b/parts/django/docs/intro/install.txt deleted file mode 100644 index 327686f..0000000 --- a/parts/django/docs/intro/install.txt +++ /dev/null @@ -1,84 +0,0 @@ -Quick install guide -=================== - -Before you can use Django, you'll need to get it installed. We have a -:doc:`complete installation guide </topics/install>` that covers all the -possibilities; this guide will guide you to a simple, minimal installation -that'll work while you walk through the introduction. - -Install Python --------------- - -Being a Python Web framework, Django requires Python. It works with any Python -version from 2.4 to 2.7 (due to backwards -incompatibilities in Python 3.0, Django does not currently work with -Python 3.0; see :doc:`the Django FAQ </faq/install>` for more -information on supported Python versions and the 3.0 transition), but we recommend installing Python 2.5 or later. If you do so, you won't need to set up a database just yet: Python 2.5 or later includes a lightweight database called SQLite_. - -.. _sqlite: http://sqlite.org/ - -Get Python at http://www.python.org. If you're running Linux or Mac OS X, you -probably already have it installed. - -.. admonition:: Django on Jython - - If you use Jython_ (a Python implementation for the Java platform), you'll - need to follow a few additional steps. See :doc:`/howto/jython` for details. - -.. _jython: http://www.jython.org/ - -You can verify that Python's installed by typing ``python`` from your shell; you should see something like:: - - Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17) - [GCC 4.0.1 (Apple Inc. build 5465)] on darwin - Type "help", "copyright", "credits" or "license" for more information. - >>> - -Set up a database ------------------ - -If you installed Python 2.5 or later, you can skip this step for now. - -If not, or if you'd like to work with a "large" database engine like PostgreSQL, -MySQL, or Oracle, consult the :ref:`database installation information -<database-installation>`. - -Remove any old versions of Django ---------------------------------- - -If you are upgrading your installation of Django from a previous version, you -will need to :ref:`uninstall the old Django version before installing the new -version <removing-old-versions-of-django>`. - -Install Django --------------- - -You've got three easy options to install Django: - - * Install a version of Django :doc:`provided by your operating system - distribution </misc/distributions>`. This is the quickest option for those - who have operating systems that distribute Django. - - * :ref:`Install an official release <installing-official-release>`. This - is the best approach for users who want a stable version number and aren't - concerned about running a slightly older version of Django. - - * :ref:`Install the latest development version - <installing-development-version>`. This is best for users who want the - latest-and-greatest features and aren't afraid of running brand-new code. - -.. admonition:: Always refer to the documentation that corresponds to the - version of Django you're using! - - If you do either of the first two steps, keep an eye out for parts of the - documentation marked **new in development version**. That phrase flags - features that are only available in development versions of Django, and - they likely won't work with an official release. - -That's it! ----------- - -That's it -- you can now :doc:`move onto the tutorial </intro/tutorial01>`. - - - diff --git a/parts/django/docs/intro/overview.txt b/parts/django/docs/intro/overview.txt deleted file mode 100644 index 34572a6..0000000 --- a/parts/django/docs/intro/overview.txt +++ /dev/null @@ -1,324 +0,0 @@ -================== -Django at a glance -================== - -Because Django was developed in a fast-paced newsroom environment, it was -designed to make common Web-development tasks fast and easy. Here's an informal -overview of how to write a database-driven Web app with Django. - -The goal of this document is to give you enough technical specifics to -understand how Django works, but this isn't intended to be a tutorial or -reference -- but we've got both! When you're ready to start a project, you can -:doc:`start with the tutorial </intro/tutorial01>` or :doc:`dive right into more -detailed documentation </topics/index>`. - -Design your model -================= - -Although you can use Django without a database, it comes with an -object-relational mapper in which you describe your database layout in Python -code. - -The :doc:`data-model syntax </topics/db/models>` offers many rich ways of -representing your models -- so far, it's been solving two years' worth of -database-schema problems. Here's a quick example, which might be saved in -the file ``mysite/news/models.py``:: - - class Reporter(models.Model): - full_name = models.CharField(max_length=70) - - def __unicode__(self): - return self.full_name - - class Article(models.Model): - pub_date = models.DateTimeField() - headline = models.CharField(max_length=200) - content = models.TextField() - reporter = models.ForeignKey(Reporter) - - def __unicode__(self): - return self.headline - -Install it -========== - -Next, run the Django command-line utility to create the database tables -automatically: - -.. code-block:: bash - - manage.py syncdb - -The :djadmin:`syncdb` command looks at all your available models and creates -tables in your database for whichever tables don't already exist. - -Enjoy the free API -================== - -With that, you've got a free, and rich, :doc:`Python API </topics/db/queries>` to -access your data. The API is created on the fly, no code generation necessary:: - - # Import the models we created from our "news" app - >>> from news.models import Reporter, Article - - # No reporters are in the system yet. - >>> Reporter.objects.all() - [] - - # Create a new Reporter. - >>> r = Reporter(full_name='John Smith') - - # Save the object into the database. You have to call save() explicitly. - >>> r.save() - - # Now it has an ID. - >>> r.id - 1 - - # Now the new reporter is in the database. - >>> Reporter.objects.all() - [<Reporter: John Smith>] - - # Fields are represented as attributes on the Python object. - >>> r.full_name - 'John Smith' - - # Django provides a rich database lookup API. - >>> Reporter.objects.get(id=1) - <Reporter: John Smith> - >>> Reporter.objects.get(full_name__startswith='John') - <Reporter: John Smith> - >>> Reporter.objects.get(full_name__contains='mith') - <Reporter: John Smith> - >>> Reporter.objects.get(id=2) - Traceback (most recent call last): - ... - DoesNotExist: Reporter matching query does not exist. - - # Create an article. - >>> from datetime import datetime - >>> a = Article(pub_date=datetime.now(), headline='Django is cool', - ... content='Yeah.', reporter=r) - >>> a.save() - - # Now the article is in the database. - >>> Article.objects.all() - [<Article: Django is cool>] - - # Article objects get API access to related Reporter objects. - >>> r = a.reporter - >>> r.full_name - 'John Smith' - - # And vice versa: Reporter objects get API access to Article objects. - >>> r.article_set.all() - [<Article: Django is cool>] - - # The API follows relationships as far as you need, performing efficient - # JOINs for you behind the scenes. - # This finds all articles by a reporter whose name starts with "John". - >>> Article.objects.filter(reporter__full_name__startswith="John") - [<Article: Django is cool>] - - # Change an object by altering its attributes and calling save(). - >>> r.full_name = 'Billy Goat' - >>> r.save() - - # Delete an object with delete(). - >>> r.delete() - -A dynamic admin interface: it's not just scaffolding -- it's the whole house -============================================================================ - -Once your models are defined, Django can automatically create a professional, -production ready :doc:`administrative interface </ref/contrib/admin/index>` -- a Web -site that lets authenticated users add, change and delete objects. It's as easy -as registering your model in the admin site:: - - # In models.py... - - from django.db import models - - class Article(models.Model): - pub_date = models.DateTimeField() - headline = models.CharField(max_length=200) - content = models.TextField() - reporter = models.ForeignKey(Reporter) - - - # In admin.py in the same directory... - - import models - from django.contrib import admin - - admin.site.register(models.Article) - -The philosophy here is that your site is edited by a staff, or a client, or -maybe just you -- and you don't want to have to deal with creating backend -interfaces just to manage content. - -One typical workflow in creating Django apps is to create models and get the -admin sites up and running as fast as possible, so your staff (or clients) can -start populating data. Then, develop the way data is presented to the public. - -Design your URLs -================ - -A clean, elegant URL scheme is an important detail in a high-quality Web -application. Django encourages beautiful URL design and doesn't put any cruft -in URLs, like ``.php`` or ``.asp``. - -To design URLs for an app, you create a Python module called a :doc:`URLconf -</topics/http/urls>`. A table of contents for your app, it contains a simple mapping -between URL patterns and Python callback functions. URLconfs also serve to -decouple URLs from Python code. - -Here's what a URLconf might look like for the ``Reporter``/``Article`` -example above:: - - from django.conf.urls.defaults import * - - urlpatterns = patterns('', - (r'^articles/(\d{4})/$', 'news.views.year_archive'), - (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'), - (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'), - ) - -The code above maps URLs, as simple regular expressions, to the location of -Python callback functions ("views"). The regular expressions use parenthesis to -"capture" values from the URLs. When a user requests a page, Django runs -through each pattern, in order, and stops at the first one that matches the -requested URL. (If none of them matches, Django calls a special-case 404 view.) -This is blazingly fast, because the regular expressions are compiled at load -time. - -Once one of the regexes matches, Django imports and calls the given view, which -is a simple Python function. Each view gets passed a request object -- -which contains request metadata -- and the values captured in the regex. - -For example, if a user requested the URL "/articles/2005/05/39323/", Django -would call the function ``news.views.article_detail(request, -'2005', '05', '39323')``. - -Write your views -================ - -Each view is responsible for doing one of two things: Returning an -:class:`~django.http.HttpResponse` object containing the content for the -requested page, or raising an exception such as :class:`~django.http.Http404`. -The rest is up to you. - -Generally, a view retrieves data according to the parameters, loads a template -and renders the template with the retrieved data. Here's an example view for -``year_archive`` from above:: - - def year_archive(request, year): - a_list = Article.objects.filter(pub_date__year=year) - return render_to_response('news/year_archive.html', {'year': year, 'article_list': a_list}) - -This example uses Django's :doc:`template system </topics/templates>`, which has -several powerful features but strives to stay simple enough for non-programmers -to use. - -Design your templates -===================== - -The code above loads the ``news/year_archive.html`` template. - -Django has a template search path, which allows you to minimize redundancy among -templates. In your Django settings, you specify a list of directories to check -for templates. If a template doesn't exist in the first directory, it checks the -second, and so on. - -Let's say the ``news/article_detail.html`` template was found. Here's what that -might look like: - -.. code-block:: html+django - - {% extends "base.html" %} - - {% block title %}Articles for {{ year }}{% endblock %} - - {% block content %} - <h1>Articles for {{ year }}</h1> - - {% for article in article_list %} - <p>{{ article.headline }}</p> - <p>By {{ article.reporter.full_name }}</p> - <p>Published {{ article.pub_date|date:"F j, Y" }}</p> - {% endfor %} - {% endblock %} - -Variables are surrounded by double-curly braces. ``{{ article.headline }}`` -means "Output the value of the article's headline attribute." But dots aren't -used only for attribute lookup: They also can do dictionary-key lookup, index -lookup and function calls. - -Note ``{{ article.pub_date|date:"F j, Y" }}`` uses a Unix-style "pipe" (the "|" -character). This is called a template filter, and it's a way to filter the value -of a variable. In this case, the date filter formats a Python datetime object in -the given format (as found in PHP's date function; yes, there is one good idea -in PHP). - -You can chain together as many filters as you'd like. You can write custom -filters. You can write custom template tags, which run custom Python code behind -the scenes. - -Finally, Django uses the concept of "template inheritance": That's what the -``{% extends "base.html" %}`` does. It means "First load the template called -'base', which has defined a bunch of blocks, and fill the blocks with the -following blocks." In short, that lets you dramatically cut down on redundancy -in templates: each template has to define only what's unique to that template. - -Here's what the "base.html" template might look like: - -.. code-block:: html+django - - <html> - <head> - <title>{% block title %}{% endblock %}</title> - </head> - <body> - <img src="sitelogo.gif" alt="Logo" /> - {% block content %}{% endblock %} - </body> - </html> - -Simplistically, it defines the look-and-feel of the site (with the site's logo), -and provides "holes" for child templates to fill. This makes a site redesign as -easy as changing a single file -- the base template. - -It also lets you create multiple versions of a site, with different base -templates, while reusing child templates. Django's creators have used this -technique to create strikingly different cell-phone editions of sites -- simply -by creating a new base template. - -Note that you don't have to use Django's template system if you prefer another -system. While Django's template system is particularly well-integrated with -Django's model layer, nothing forces you to use it. For that matter, you don't -have to use Django's database API, either. You can use another database -abstraction layer, you can read XML files, you can read files off disk, or -anything you want. Each piece of Django -- models, views, templates -- is -decoupled from the next. - -This is just the surface -======================== - -This has been only a quick overview of Django's functionality. Some more useful -features: - - * A :doc:`caching framework </topics/cache>` that integrates with memcached - or other backends. - - * A :doc:`syndication framework </ref/contrib/syndication>` that makes - creating RSS and Atom feeds as easy as writing a small Python class. - - * More sexy automatically-generated admin features -- this overview barely - scratched the surface. - -The next obvious steps are for you to `download Django`_, read :doc:`the -tutorial </intro/tutorial01>` and join `the community`_. Thanks for your -interest! - -.. _download Django: http://www.djangoproject.com/download/ -.. _the community: http://www.djangoproject.com/community/ diff --git a/parts/django/docs/intro/tutorial01.txt b/parts/django/docs/intro/tutorial01.txt deleted file mode 100644 index 560070b..0000000 --- a/parts/django/docs/intro/tutorial01.txt +++ /dev/null @@ -1,690 +0,0 @@ -===================================== -Writing your first Django app, part 1 -===================================== - -Let's learn by example. - -Throughout this tutorial, we'll walk you through the creation of a basic -poll application. - -It'll consist of two parts: - - * A public site that lets people view polls and vote in them. - * An admin site that lets you add, change and delete polls. - -We'll assume you have :doc:`Django installed </intro/install>` already. You can -tell Django is installed by running the Python interactive interpreter and -typing ``import django``. If that command runs successfully, with no errors, -Django is installed. - -.. admonition:: Where to get help: - - If you're having trouble going through this tutorial, please post a message - to `django-users`__ or drop by `#django on irc.freenode.net`__ to chat - with other Django users who might be able to help. - -__ http://groups.google.com/group/django-users -__ irc://irc.freenode.net/django - -Creating a project -================== - -If this is your first time using Django, you'll have to take care of some -initial setup. Namely, you'll need to auto-generate some code that establishes a -Django :term:`project` -- a collection of settings for an instance of Django, -including database configuration, Django-specific options and -application-specific settings. - -From the command line, ``cd`` into a directory where you'd like to store your -code, then run the command ``django-admin.py startproject mysite``. This will -create a ``mysite`` directory in your current directory. - -.. admonition:: Script name may differ in distribution packages - - If you installed Django using a Linux distribution's package manager - (e.g. apt-get or yum) ``django-admin.py`` may have been renamed to - ``django-admin``. You may continue through this documentation by omitting - ``.py`` from each command. - -.. admonition:: Mac OS X permissions - - If you're using Mac OS X, you may see the message "permission denied" when - you try to run ``django-admin.py startproject``. This is because, on - Unix-based systems like OS X, a file must be marked as "executable" before it - can be run as a program. To do this, open Terminal.app and navigate (using - the ``cd`` command) to the directory where :doc:`django-admin.py - </ref/django-admin>` is installed, then run the command - ``chmod +x django-admin.py``. - -.. note:: - - You'll need to avoid naming projects after built-in Python or Django - components. In particular, this means you should avoid using names like - ``django`` (which will conflict with Django itself) or ``test`` (which - conflicts with a built-in Python package). - -:doc:`django-admin.py </ref/django-admin>` should be on your system path if you -installed Django via ``python setup.py``. If it's not on your path, you can find -it in ``site-packages/django/bin``, where ```site-packages``` is a directory -within your Python installation. Consider symlinking to :doc:`django-admin.py -</ref/django-admin>` from some place on your path, such as -:file:`/usr/local/bin`. - -.. admonition:: Where should this code live? - - If your background is in PHP, you're probably used to putting code under the - Web server's document root (in a place such as ``/var/www``). With Django, - you don't do that. It's not a good idea to put any of this Python code - within your Web server's document root, because it risks the possibility - that people may be able to view your code over the Web. That's not good for - security. - - Put your code in some directory **outside** of the document root, such as - :file:`/home/mycode`. - -Let's look at what :djadmin:`startproject` created:: - - mysite/ - __init__.py - manage.py - settings.py - urls.py - -These files are: - - * :file:`__init__.py`: An empty file that tells Python that this directory - should be considered a Python package. (Read `more about packages`_ in the - official Python docs if you're a Python beginner.) - - * :file:`manage.py`: A command-line utility that lets you interact with this - Django project in various ways. You can read all the details about - :file:`manage.py` in :doc:`/ref/django-admin`. - - * :file:`settings.py`: Settings/configuration for this Django project. - :doc:`/topics/settings` will tell you all about how settings work. - - * :file:`urls.py`: The URL declarations for this Django project; a "table of - contents" of your Django-powered site. You can read more about URLs in - :doc:`/topics/http/urls`. - -.. _more about packages: http://docs.python.org/tutorial/modules.html#packages - -The development server ----------------------- - -Let's verify this worked. Change into the :file:`mysite` directory, if you -haven't already, and run the command ``python manage.py runserver``. You'll see -the following output on the command line:: - - Validating models... - 0 errors found. - - Django version 1.0, using settings 'mysite.settings' - Development server is running at http://127.0.0.1:8000/ - Quit the server with CONTROL-C. - -You've started the Django development server, a lightweight Web server written -purely in Python. We've included this with Django so you can develop things -rapidly, without having to deal with configuring a production server -- such as -Apache -- until you're ready for production. - -Now's a good time to note: DON'T use this server in anything resembling a -production environment. It's intended only for use while developing. (We're in -the business of making Web frameworks, not Web servers.) - -Now that the server's running, visit http://127.0.0.1:8000/ with your Web -browser. You'll see a "Welcome to Django" page, in pleasant, light-blue pastel. -It worked! - -.. admonition:: Changing the port - - By default, the :djadmin:`runserver` command starts the development server - on the internal IP at port 8000. - - If you want to change the server's port, pass - it as a command-line argument. For instance, this command starts the server - on port 8080: - - .. code-block:: bash - - python manage.py runserver 8080 - - If you want to change the server's IP, pass it along with the port. So to - listen on all public IPs (useful if you want to show off your work on other - computers), use: - - .. code-block:: bash - - python manage.py runserver 0.0.0.0:8000 - - Full docs for the development server can be found in the - :djadmin:`runserver` reference. - -Database setup --------------- - -Now, edit :file:`settings.py`. It's a normal Python module with -module-level variables representing Django settings. Change the -following keys in the :setting:`DATABASES` ``'default'`` item to match -your databases connection settings. - - * :setting:`ENGINE` -- Either - ``'django.db.backends.postgresql_psycopg2'``, - ``'django.db.backends.mysql'`` or - ``'django.db.backends.sqlite3'``. Other backends are - :setting:`also available <ENGINE>`. - - * :setting:`NAME` -- The name of your database. If you're using - SQLite, the database will be a file on your computer; in that - case, :setting:`NAME` should be the full absolute path, - including filename, of that file. If the file doesn't exist, it - will automatically be created when you synchronize the database - for the first time (see below). - - When specifying the path, always use forward slashes, even on - Windows (e.g. ``C:/homes/user/mysite/sqlite3.db``). - - * :setting:`USER` -- Your database username (not used for SQLite). - - * :setting:`PASSWORD` -- Your database password (not used for - SQLite). - - * :setting:`HOST` -- The host your database is on. Leave this as - an empty string if your database server is on the same physical - machine (not used for SQLite). - -If you're new to databases, we recommend simply using SQLite (by -setting :setting:`ENGINE` to ``'django.db.backends.sqlite3'``). SQLite -is included as part of Python 2.5 and later, so you won't need to -install anything else. - -.. note:: - - If you're using PostgreSQL or MySQL, make sure you've created a database by - this point. Do that with "``CREATE DATABASE database_name;``" within your - database's interactive prompt. - - If you're using SQLite, you don't need to create anything beforehand - the - database file will be created automatically when it is needed. - -While you're editing :file:`settings.py`, take note of the -:setting:`INSTALLED_APPS` setting towards the bottom of the file. That variable -holds the names of all Django applications that are activated in this Django -instance. Apps can be used in multiple projects, and you can package and -distribute them for use by others in their projects. - -By default, :setting:`INSTALLED_APPS` contains the following apps, all of which -come with Django: - - * :mod:`django.contrib.auth` -- An authentication system. - - * :mod:`django.contrib.contenttypes` -- A framework for content types. - - * :mod:`django.contrib.sessions` -- A session framework. - - * :mod:`django.contrib.sites` -- A framework for managing multiple sites - with one Django installation. - - * :mod:`django.contrib.messages` -- A messaging framework. - -These applications are included by default as a convenience for the common case. - -Each of these applications makes use of at least one database table, though, -so we need to create the tables in the database before we can use them. To do -that, run the following command: - -.. code-block:: bash - - python manage.py syncdb - -The :djadmin:`syncdb` command looks at the :setting:`INSTALLED_APPS` setting and -creates any necessary database tables according to the database settings in your -:file:`settings.py` file. You'll see a message for each database table it -creates, and you'll get a prompt asking you if you'd like to create a superuser -account for the authentication system. Go ahead and do that. - -If you're interested, run the command-line client for your database and type -``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to -display the tables Django created. - -.. admonition:: For the minimalists - - Like we said above, the default applications are included for the common - case, but not everybody needs them. If you don't need any or all of them, - feel free to comment-out or delete the appropriate line(s) from - :setting:`INSTALLED_APPS` before running :djadmin:`syncdb`. The - :djadmin:`syncdb` command will only create tables for apps in - :setting:`INSTALLED_APPS`. - -.. _creating-models: - -Creating models -=============== - -Now that your environment -- a "project" -- is set up, you're set to start -doing work. - -Each application you write in Django consists of a Python package, somewhere -on your `Python path`_, that follows a certain convention. Django comes with a -utility that automatically generates the basic directory structure of an app, -so you can focus on writing code rather than creating directories. - -.. admonition:: Projects vs. apps - - What's the difference between a project and an app? An app is a Web - application that does something -- e.g., a Weblog system, a database of - public records or a simple poll app. A project is a collection of - configuration and apps for a particular Web site. A project can contain - multiple apps. An app can be in multiple projects. - -Your apps can live anywhere on your `Python path`_. In this tutorial, we'll -create our poll app in the :file:`mysite` directory for simplicity. - -To create your app, make sure you're in the :file:`mysite` directory and type -this command: - -.. code-block:: bash - - python manage.py startapp polls - -That'll create a directory :file:`polls`, which is laid out like this:: - - polls/ - __init__.py - models.py - tests.py - views.py - -This directory structure will house the poll application. - -The first step in writing a database Web app in Django is to define your models --- essentially, your database layout, with additional metadata. - -.. admonition:: Philosophy - - A model is the single, definitive source of data about your data. It contains - the essential fields and behaviors of the data you're storing. Django follows - the :ref:`DRY Principle <dry>`. The goal is to define your data model in one - place and automatically derive things from it. - -In our simple poll app, we'll create two models: polls and choices. A poll has -a question and a publication date. A choice has two fields: the text of the -choice and a vote tally. Each choice is associated with a poll. - -These concepts are represented by simple Python classes. Edit the -:file:`polls/models.py` file so it looks like this:: - - from django.db import models - - class Poll(models.Model): - question = models.CharField(max_length=200) - pub_date = models.DateTimeField('date published') - - class Choice(models.Model): - poll = models.ForeignKey(Poll) - choice = models.CharField(max_length=200) - votes = models.IntegerField() - -The code is straightforward. Each model is represented by a class that -subclasses :class:`django.db.models.Model`. Each model has a number of class -variables, each of which represents a database field in the model. - -Each field is represented by an instance of a :class:`~django.db.models.Field` -class -- e.g., :class:`~django.db.models.CharField` for character fields and -:class:`~django.db.models.DateTimeField` for datetimes. This tells Django what -type of data each field holds. - -The name of each :class:`~django.db.models.Field` instance (e.g. ``question`` or -``pub_date`` ) is the field's name, in machine-friendly format. You'll use this -value in your Python code, and your database will use it as the column name. - -You can use an optional first positional argument to a -:class:`~django.db.models.Field` to designate a human-readable name. That's used -in a couple of introspective parts of Django, and it doubles as documentation. -If this field isn't provided, Django will use the machine-readable name. In this -example, we've only defined a human-readable name for ``Poll.pub_date``. For all -other fields in this model, the field's machine-readable name will suffice as -its human-readable name. - -Some :class:`~django.db.models.Field` classes have required elements. -:class:`~django.db.models.CharField`, for example, requires that you give it a -:attr:`~django.db.models.Field.max_length`. That's used not only in the database -schema, but in validation, as we'll soon see. - -Finally, note a relationship is defined, using -:class:`~django.db.models.ForeignKey`. That tells Django each Choice is related -to a single Poll. Django supports all the common database relationships: -many-to-ones, many-to-manys and one-to-ones. - -.. _`Python path`: http://docs.python.org/tutorial/modules.html#the-module-search-path - -Activating models -================= - -That small bit of model code gives Django a lot of information. With it, Django -is able to: - - * Create a database schema (``CREATE TABLE`` statements) for this app. - * Create a Python database-access API for accessing Poll and Choice objects. - -But first we need to tell our project that the ``polls`` app is installed. - -.. admonition:: Philosophy - - Django apps are "pluggable": You can use an app in multiple projects, and - you can distribute apps, because they don't have to be tied to a given - Django installation. - -Edit the :file:`settings.py` file again, and change the -:setting:`INSTALLED_APPS` setting to include the string ``'polls'``. So -it'll look like this:: - - INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'polls' - ) - -Now Django knows to include the ``polls`` app. Let's run another -command: - -.. code-block:: bash - - python manage.py sql polls - -You should see something similar to the following (the ``CREATE TABLE`` SQL -statements for the polls app): - -.. code-block:: sql - - BEGIN; - CREATE TABLE "polls_poll" ( - "id" serial NOT NULL PRIMARY KEY, - "question" varchar(200) NOT NULL, - "pub_date" timestamp with time zone NOT NULL - ); - CREATE TABLE "polls_choice" ( - "id" serial NOT NULL PRIMARY KEY, - "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"), - "choice" varchar(200) NOT NULL, - "votes" integer NOT NULL - ); - COMMIT; - -Note the following: - - * The exact output will vary depending on the database you are using. - - * Table names are automatically generated by combining the name of the app - (``polls``) and the lowercase name of the model -- ``poll`` and - ``choice``. (You can override this behavior.) - - * Primary keys (IDs) are added automatically. (You can override this, too.) - - * By convention, Django appends ``"_id"`` to the foreign key field name. - Yes, you can override this, as well. - - * The foreign key relationship is made explicit by a ``REFERENCES`` - statement. - - * It's tailored to the database you're using, so database-specific field - types such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or - ``integer primary key`` (SQLite) are handled for you automatically. Same - goes for quoting of field names -- e.g., using double quotes or single - quotes. The author of this tutorial runs PostgreSQL, so the example - output is in PostgreSQL syntax. - - * The :djadmin:`sql` command doesn't actually run the SQL in your database - - it just prints it to the screen so that you can see what SQL Django thinks - is required. If you wanted to, you could copy and paste this SQL into your - database prompt. However, as we will see shortly, Django provides an - easier way of committing the SQL to the database. - -If you're interested, also run the following commands: - - * :djadmin:`python manage.py validate <validate>` -- Checks for any errors - in the construction of your models. - - * :djadmin:`python manage.py sqlcustom polls <sqlcustom>` -- Outputs any - :ref:`custom SQL statements <initial-sql>` (such as table modifications or - constraints) that are defined for the application. - - * :djadmin:`python manage.py sqlclear polls <sqlclear>` -- Outputs the - necessary ``DROP TABLE`` statements for this app, according to which - tables already exist in your database (if any). - - * :djadmin:`python manage.py sqlindexes polls <sqlindexes>` -- Outputs the - ``CREATE INDEX`` statements for this app. - - * :djadmin:`python manage.py sqlall polls <sqlall>` -- A combination of all - the SQL from the :djadmin:`sql`, :djadmin:`sqlcustom`, and - :djadmin:`sqlindexes` commands. - -Looking at the output of those commands can help you understand what's actually -happening under the hood. - -Now, run :djadmin:`syncdb` again to create those model tables in your database: - -.. code-block:: bash - - python manage.py syncdb - -The :djadmin:`syncdb` command runs the sql from 'sqlall' on your database for -all apps in :setting:`INSTALLED_APPS` that don't already exist in your database. -This creates all the tables, initial data and indexes for any apps you have -added to your project since the last time you ran syncdb. :djadmin:`syncdb` can -be called as often as you like, and it will only ever create the tables that -don't exist. - -Read the :doc:`django-admin.py documentation </ref/django-admin>` for full -information on what the ``manage.py`` utility can do. - -Playing with the API -==================== - -Now, let's hop into the interactive Python shell and play around with the free -API Django gives you. To invoke the Python shell, use this command: - -.. code-block:: bash - - python manage.py shell - -We're using this instead of simply typing "python", because ``manage.py`` sets -up the project's environment for you. "Setting up the environment" involves two -things: - - * Putting ``polls`` on ``sys.path``. For flexibility, several pieces of - Django refer to projects in Python dotted-path notation (e.g. - ``'polls.models'``). In order for this to work, the ``polls`` - package has to be on ``sys.path``. - - We've already seen one example of this: the :setting:`INSTALLED_APPS` - setting is a list of packages in dotted-path notation. - - * Setting the ``DJANGO_SETTINGS_MODULE`` environment variable, which gives - Django the path to your ``settings.py`` file. - -.. admonition:: Bypassing manage.py - - If you'd rather not use ``manage.py``, no problem. Just make sure ``mysite`` - and ``polls`` are at the root level on the Python path (i.e., ``import mysite`` - and ``import polls`` work) and set the ``DJANGO_SETTINGS_MODULE`` environment - variable to ``mysite.settings``. - - For more information on all of this, see the :doc:`django-admin.py - documentation </ref/django-admin>`. - -Once you're in the shell, explore the :doc:`database API </topics/db/queries>`:: - - >>> from polls.models import Poll, Choice # Import the model classes we just wrote. - - # No polls are in the system yet. - >>> Poll.objects.all() - [] - - # Create a new Poll. - >>> import datetime - >>> p = Poll(question="What's up?", pub_date=datetime.datetime.now()) - - # Save the object into the database. You have to call save() explicitly. - >>> p.save() - - # Now it has an ID. Note that this might say "1L" instead of "1", depending - # on which database you're using. That's no biggie; it just means your - # database backend prefers to return integers as Python long integer - # objects. - >>> p.id - 1 - - # Access database columns via Python attributes. - >>> p.question - "What's up?" - >>> p.pub_date - datetime.datetime(2007, 7, 15, 12, 00, 53) - - # Change values by changing the attributes, then calling save(). - >>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0) - >>> p.save() - - # objects.all() displays all the polls in the database. - >>> Poll.objects.all() - [<Poll: Poll object>] - - -Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful representation -of this object. Let's fix that by editing the polls model (in the -``polls/models.py`` file) and adding a -:meth:`~django.db.models.Model.__unicode__` method to both ``Poll`` and -``Choice``:: - - class Poll(models.Model): - # ... - def __unicode__(self): - return self.question - - class Choice(models.Model): - # ... - def __unicode__(self): - return self.choice - -It's important to add :meth:`~django.db.models.Model.__unicode__` methods to -your models, not only for your own sanity when dealing with the interactive -prompt, but also because objects' representations are used throughout Django's -automatically-generated admin. - -.. admonition:: Why :meth:`~django.db.models.Model.__unicode__` and not - :meth:`~django.db.models.Model.__str__`? - - If you're familiar with Python, you might be in the habit of adding - :meth:`~django.db.models.Model.__str__` methods to your classes, not - :meth:`~django.db.models.Model.__unicode__` methods. We use - :meth:`~django.db.models.Model.__unicode__` here because Django models deal - with Unicode by default. All data stored in your database is converted to - Unicode when it's returned. - - Django models have a default :meth:`~django.db.models.Model.__str__` method - that calls :meth:`~django.db.models.Model.__unicode__` and converts the - result to a UTF-8 bytestring. This means that ``unicode(p)`` will return a - Unicode string, and ``str(p)`` will return a normal string, with characters - encoded as UTF-8. - - If all of this is jibberish to you, just remember to add - :meth:`~django.db.models.Model.__unicode__` methods to your models. With any - luck, things should Just Work for you. - -Note these are normal Python methods. Let's add a custom method, just for -demonstration:: - - import datetime - # ... - class Poll(models.Model): - # ... - def was_published_today(self): - return self.pub_date.date() == datetime.date.today() - -Note the addition of ``import datetime`` to reference Python's standard -``datetime`` module. - -Save these changes and start a new Python interactive shell by running -``python manage.py shell`` again:: - - >>> from polls.models import Poll, Choice - - # Make sure our __unicode__() addition worked. - >>> Poll.objects.all() - [<Poll: What's up?>] - - # Django provides a rich database lookup API that's entirely driven by - # keyword arguments. - >>> Poll.objects.filter(id=1) - [<Poll: What's up?>] - >>> Poll.objects.filter(question__startswith='What') - [<Poll: What's up?>] - - # Get the poll whose year is 2007. - >>> Poll.objects.get(pub_date__year=2007) - <Poll: What's up?> - - >>> Poll.objects.get(id=2) - Traceback (most recent call last): - ... - DoesNotExist: Poll matching query does not exist. - - # Lookup by a primary key is the most common case, so Django provides a - # shortcut for primary-key exact lookups. - # The following is identical to Poll.objects.get(id=1). - >>> Poll.objects.get(pk=1) - <Poll: What's up?> - - # Make sure our custom method worked. - >>> p = Poll.objects.get(pk=1) - >>> p.was_published_today() - False - - # Give the Poll a couple of Choices. The create call constructs a new - # choice object, does the INSERT statement, adds the choice to the set - # of available choices and returns the new Choice object. Django creates - # a set to hold the "other side" of a ForeignKey relation - # (e.g. a poll's choices) which can be accessed via the API. - >>> p = Poll.objects.get(pk=1) - - # Display any choices from the related object set -- none so far. - >>> p.choice_set.all() - [] - - # Create three choices. - >>> p.choice_set.create(choice='Not much', votes=0) - <Choice: Not much> - >>> p.choice_set.create(choice='The sky', votes=0) - <Choice: The sky> - >>> c = p.choice_set.create(choice='Just hacking again', votes=0) - - # Choice objects have API access to their related Poll objects. - >>> c.poll - <Poll: What's up?> - - # And vice versa: Poll objects get access to Choice objects. - >>> p.choice_set.all() - [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] - >>> p.choice_set.count() - 3 - - # The API automatically follows relationships as far as you need. - # Use double underscores to separate relationships. - # This works as many levels deep as you want; there's no limit. - # Find all Choices for any poll whose pub_date is in 2007. - >>> Choice.objects.filter(poll__pub_date__year=2007) - [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] - - # Let's delete one of the choices. Use delete() for that. - >>> c = p.choice_set.filter(choice__startswith='Just hacking') - >>> c.delete() - -For more information on model relations, see :doc:`Accessing related objects -</ref/models/relations>`. For full details on the database API, see our -:doc:`Database API reference </topics/db/queries>`. - -When you're comfortable with the API, read :doc:`part 2 of this tutorial -</intro/tutorial02>` to get Django's automatic admin working. diff --git a/parts/django/docs/intro/tutorial02.txt b/parts/django/docs/intro/tutorial02.txt deleted file mode 100644 index c80d87d..0000000 --- a/parts/django/docs/intro/tutorial02.txt +++ /dev/null @@ -1,465 +0,0 @@ -===================================== -Writing your first Django app, part 2 -===================================== - -This tutorial begins where :doc:`Tutorial 1 </intro/tutorial01>` left off. We're -continuing the Web-poll application and will focus on Django's -automatically-generated admin site. - -.. admonition:: Philosophy - - Generating admin sites for your staff or clients to add, change and delete - content is tedious work that doesn't require much creativity. For that - reason, Django entirely automates creation of admin interfaces for models. - - Django was written in a newsroom environment, with a very clear separation - between "content publishers" and the "public" site. Site managers use the - system to add news stories, events, sports scores, etc., and that content is - displayed on the public site. Django solves the problem of creating a - unified interface for site administrators to edit content. - - The admin isn't necessarily intended to be used by site visitors; it's for - site managers. - -Activate the admin site -======================= - -The Django admin site is not activated by default -- it's an opt-in thing. To -activate the admin site for your installation, do these three things: - - * Add ``"django.contrib.admin"`` to your :setting:`INSTALLED_APPS` setting. - - * Run ``python manage.py syncdb``. Since you have added a new application - to :setting:`INSTALLED_APPS`, the database tables need to be updated. - - * Edit your ``mysite/urls.py`` file and uncomment the lines that reference - the admin -- there are three lines in total to uncomment. This file is a - URLconf; we'll dig into URLconfs in the next tutorial. For now, all you - need to know is that it maps URL roots to applications. In the end, you - should have a ``urls.py`` file that looks like this: - - .. versionchanged:: 1.1 - The method for adding admin urls has changed in Django 1.1. - - .. parsed-literal:: - - from django.conf.urls.defaults import * - - # Uncomment the next two lines to enable the admin: - **from django.contrib import admin** - **admin.autodiscover()** - - urlpatterns = patterns('', - # Example: - # (r'^mysite/', include('mysite.foo.urls')), - - # Uncomment the admin/doc line below and add 'django.contrib.admindocs' - # to INSTALLED_APPS to enable admin documentation: - # (r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - **(r'^admin/', include(admin.site.urls)),** - ) - - (The bold lines are the ones that needed to be uncommented.) - -Start the development server -============================ - -Let's start the development server and explore the admin site. - -Recall from Tutorial 1 that you start the development server like so: - -.. code-block:: bash - - python manage.py runserver - -Now, open a Web browser and go to "/admin/" on your local domain -- e.g., -http://127.0.0.1:8000/admin/. You should see the admin's login screen: - -.. image:: _images/admin01.png - :alt: Django admin login screen - -Enter the admin site -==================== - -Now, try logging in. (You created a superuser account in the first part of this -tutorial, remember? If you didn't create one or forgot the password you can -:ref:`create another one <topics-auth-creating-superusers>`.) You should see -the Django admin index page: - -.. image:: _images/admin02t.png - :alt: Django admin index page - -You should see a few other types of editable content, including groups, users -and sites. These are core features Django ships with by default. - -Make the poll app modifiable in the admin -========================================= - -But where's our poll app? It's not displayed on the admin index page. - -Just one thing to do: We need to tell the admin that ``Poll`` -objects have an admin interface. To do this, create a file called -``admin.py`` in your ``polls`` directory, and edit it to look like this:: - - from polls.models import Poll - from django.contrib import admin - - admin.site.register(Poll) - -You'll need to restart the development server to see your changes. Normally, -the server auto-reloads code every time you modify a file, but the action of -creating a new file doesn't trigger the auto-reloading logic. - -Explore the free admin functionality -==================================== - -Now that we've registered ``Poll``, Django knows that it should be displayed on -the admin index page: - -.. image:: _images/admin03t.png - :alt: Django admin index page, now with polls displayed - -Click "Polls." Now you're at the "change list" page for polls. This page -displays all the polls in the database and lets you choose one to change it. -There's the "What's up?" poll we created in the first tutorial: - -.. image:: _images/admin04t.png - :alt: Polls change list page - -Click the "What's up?" poll to edit it: - -.. image:: _images/admin05t.png - :alt: Editing form for poll object - -Things to note here: - - * The form is automatically generated from the Poll model. - - * The different model field types (:class:`~django.db.models.DateTimeField`, - :class:`~django.db.models.CharField`) correspond to the appropriate HTML - input widget. Each type of field knows how to display itself in the Django - admin. - - * Each :class:`~django.db.models.DateTimeField` gets free JavaScript - shortcuts. Dates get a "Today" shortcut and calendar popup, and times get - a "Now" shortcut and a convenient popup that lists commonly entered times. - -The bottom part of the page gives you a couple of options: - - * Save -- Saves changes and returns to the change-list page for this type of - object. - - * Save and continue editing -- Saves changes and reloads the admin page for - this object. - - * Save and add another -- Saves changes and loads a new, blank form for this - type of object. - - * Delete -- Displays a delete confirmation page. - -Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then -click "Save and continue editing." Then click "History" in the upper right. -You'll see a page listing all changes made to this object via the Django admin, -with the timestamp and username of the person who made the change: - -.. image:: _images/admin06t.png - :alt: History page for poll object - -Customize the admin form -======================== - -Take a few minutes to marvel at all the code you didn't have to write. By -registering the Poll model with ``admin.site.register(Poll)``, Django was able -to construct a default form representation. Often, you'll want to customize how -the admin form looks and works. You'll do this by telling Django the options -you want when you register the object. - -Let's see how this works by re-ordering the fields on the edit form. Replace -the ``admin.site.register(Poll)`` line with:: - - class PollAdmin(admin.ModelAdmin): - fields = ['pub_date', 'question'] - - admin.site.register(Poll, PollAdmin) - -You'll follow this pattern -- create a model admin object, then pass it as the -second argument to ``admin.site.register()`` -- any time you need to change the -admin options for an object. - -This particular change above makes the "Publication date" come before the -"Question" field: - -.. image:: _images/admin07.png - :alt: Fields have been reordered - -This isn't impressive with only two fields, but for admin forms with dozens -of fields, choosing an intuitive order is an important usability detail. - -And speaking of forms with dozens of fields, you might want to split the form -up into fieldsets:: - - class PollAdmin(admin.ModelAdmin): - fieldsets = [ - (None, {'fields': ['question']}), - ('Date information', {'fields': ['pub_date']}), - ] - - admin.site.register(Poll, PollAdmin) - -The first element of each tuple in ``fieldsets`` is the title of the fieldset. -Here's what our form looks like now: - -.. image:: _images/admin08t.png - :alt: Form has fieldsets now - -You can assign arbitrary HTML classes to each fieldset. Django provides a -``"collapse"`` class that displays a particular fieldset initially collapsed. -This is useful when you have a long form that contains a number of fields that -aren't commonly used:: - - class PollAdmin(admin.ModelAdmin): - fieldsets = [ - (None, {'fields': ['question']}), - ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), - ] - -.. image:: _images/admin09.png - :alt: Fieldset is initially collapsed - -Adding related objects -====================== - -OK, we have our Poll admin page. But a ``Poll`` has multiple ``Choices``, and -the admin page doesn't display choices. - -Yet. - -There are two ways to solve this problem. The first is to register ``Choice`` -with the admin just as we did with ``Poll``. That's easy:: - - from polls.models import Choice - - admin.site.register(Choice) - -Now "Choices" is an available option in the Django admin. The "Add choice" form -looks like this: - -.. image:: _images/admin10.png - :alt: Choice admin page - -In that form, the "Poll" field is a select box containing every poll in the -database. Django knows that a :class:`~django.db.models.ForeignKey` should be -represented in the admin as a ``<select>`` box. In our case, only one poll -exists at this point. - -Also note the "Add Another" link next to "Poll." Every object with a -``ForeignKey`` relationship to another gets this for free. When you click "Add -Another," you'll get a popup window with the "Add poll" form. If you add a poll -in that window and click "Save," Django will save the poll to the database and -dynamically add it as the selected choice on the "Add choice" form you're -looking at. - -But, really, this is an inefficient way of adding Choice objects to the system. -It'd be better if you could add a bunch of Choices directly when you create the -Poll object. Let's make that happen. - -Remove the ``register()`` call for the Choice model. Then, edit the ``Poll`` -registration code to read:: - - class ChoiceInline(admin.StackedInline): - model = Choice - extra = 3 - - class PollAdmin(admin.ModelAdmin): - fieldsets = [ - (None, {'fields': ['question']}), - ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), - ] - inlines = [ChoiceInline] - - admin.site.register(Poll, PollAdmin) - -This tells Django: "Choice objects are edited on the Poll admin page. By -default, provide enough fields for 3 choices." - -Load the "Add poll" page to see how that looks, you may need to restart your development server: - -.. image:: _images/admin11t.png - :alt: Add poll page now has choices on it - -It works like this: There are three slots for related Choices -- as specified -by ``extra`` -- and each time you come back to the "Change" page for an -already-created object, you get another three extra slots. - -One small problem, though. It takes a lot of screen space to display all the -fields for entering related Choice objects. For that reason, Django offers a -tabular way of displaying inline related objects; you just need to change -the ``ChoiceInline`` declaration to read:: - - class ChoiceInline(admin.TabularInline): - #... - -With that ``TabularInline`` (instead of ``StackedInline``), the -related objects are displayed in a more compact, table-based format: - -.. image:: _images/admin12.png - :alt: Add poll page now has more compact choices - -Customize the admin change list -=============================== - -Now that the Poll admin page is looking good, let's make some tweaks to the -"change list" page -- the one that displays all the polls in the system. - -Here's what it looks like at this point: - -.. image:: _images/admin04t.png - :alt: Polls change list page - -By default, Django displays the ``str()`` of each object. But sometimes it'd be -more helpful if we could display individual fields. To do that, use the -``list_display`` admin option, which is a tuple of field names to display, as -columns, on the change list page for the object:: - - class PollAdmin(admin.ModelAdmin): - # ... - list_display = ('question', 'pub_date') - -Just for good measure, let's also include the ``was_published_today`` custom -method from Tutorial 1:: - - class PollAdmin(admin.ModelAdmin): - # ... - list_display = ('question', 'pub_date', 'was_published_today') - -Now the poll change list page looks like this: - -.. image:: _images/admin13t.png - :alt: Polls change list page, updated - -You can click on the column headers to sort by those values -- except in the -case of the ``was_published_today`` header, because sorting by the output of -an arbitrary method is not supported. Also note that the column header for -``was_published_today`` is, by default, the name of the method (with -underscores replaced with spaces). But you can change that by giving that -method (in ``models.py``) a ``short_description`` attribute:: - - def was_published_today(self): - return self.pub_date.date() == datetime.date.today() - was_published_today.short_description = 'Published today?' - -Edit your admin.py file again and add an improvement to the Poll change list page: Filters. Add the -following line to ``PollAdmin``:: - - list_filter = ['pub_date'] - -That adds a "Filter" sidebar that lets people filter the change list by the -``pub_date`` field: - -.. image:: _images/admin14t.png - :alt: Polls change list page, updated - -The type of filter displayed depends on the type of field you're filtering on. -Because ``pub_date`` is a DateTimeField, Django knows to give the default -filter options for DateTimeFields: "Any date," "Today," "Past 7 days," -"This month," "This year." - -This is shaping up well. Let's add some search capability:: - - search_fields = ['question'] - -That adds a search box at the top of the change list. When somebody enters -search terms, Django will search the ``question`` field. You can use as many -fields as you'd like -- although because it uses a ``LIKE`` query behind the -scenes, keep it reasonable, to keep your database happy. - -Finally, because Poll objects have dates, it'd be convenient to be able to -drill down by date. Add this line:: - - date_hierarchy = 'pub_date' - -That adds hierarchical navigation, by date, to the top of the change list page. -At top level, it displays all available years. Then it drills down to months -and, ultimately, days. - -Now's also a good time to note that change lists give you free pagination. The -default is to display 50 items per page. Change-list pagination, search boxes, -filters, date-hierarchies and column-header-ordering all work together like you -think they should. - -Customize the admin look and feel -================================= - -Clearly, having "Django administration" at the top of each admin page is -ridiculous. It's just placeholder text. - -That's easy to change, though, using Django's template system. The Django admin -is powered by Django itself, and its interfaces use Django's own template -system. - -Open your settings file (``mysite/settings.py``, remember) and look at the -:setting:`TEMPLATE_DIRS` setting. :setting:`TEMPLATE_DIRS` is a tuple of -filesystem directories to check when loading Django templates. It's a search -path. - -By default, :setting:`TEMPLATE_DIRS` is empty. So, let's add a line to it, to -tell Django where our templates live:: - - TEMPLATE_DIRS = ( - "/home/my_username/mytemplates", # Change this to your own directory. - ) - -Now copy the template ``admin/base_site.html`` from within the default Django -admin template directory in the source code of Django itself -(``django/contrib/admin/templates``) into an ``admin`` subdirectory of -whichever directory you're using in :setting:`TEMPLATE_DIRS`. For example, if -your :setting:`TEMPLATE_DIRS` includes ``"/home/my_username/mytemplates"``, as -above, then copy ``django/contrib/admin/templates/admin/base_site.html`` to -``/home/my_username/mytemplates/admin/base_site.html``. Don't forget that -``admin`` subdirectory. - -Then, just edit the file and replace the generic Django text with your own -site's name as you see fit. - -This template file contains lots of text like ``{% block branding %}`` -and ``{{ title }}``. The ``{%`` and ``{{`` tags are part of Django's -template language. When Django renders ``admin/base_site.html``, this -template language will be evaluated to produce the final HTML page. -Don't worry if you can't make any sense of the template right now -- -we'll delve into Django's templating language in Tutorial 3. - -Note that any of Django's default admin templates can be overridden. To -override a template, just do the same thing you did with ``base_site.html`` -- -copy it from the default directory into your custom directory, and make -changes. - -Astute readers will ask: But if :setting:`TEMPLATE_DIRS` was empty by default, -how was Django finding the default admin templates? The answer is that, by -default, Django automatically looks for a ``templates/`` subdirectory within -each app package, for use as a fallback. See the :ref:`template loader -documentation <template-loaders>` for full information. - -Customize the admin index page -============================== - -On a similar note, you might want to customize the look and feel of the Django -admin index page. - -By default, it displays all the apps in :setting:`INSTALLED_APPS` that have been -registered with the admin application, in alphabetical order. You may want to -make significant changes to the layout. After all, the index is probably the -most important page of the admin, and it should be easy to use. - -The template to customize is ``admin/index.html``. (Do the same as with -``admin/base_site.html`` in the previous section -- copy it from the default -directory to your custom template directory.) Edit the file, and you'll see it -uses a template variable called ``app_list``. That variable contains every -installed Django app. Instead of using that, you can hard-code links to -object-specific admin pages in whatever way you think is best. Again, -don't worry if you can't understand the template language -- we'll cover that -in more detail in Tutorial 3. - -When you're comfortable with the admin site, read :doc:`part 3 of this tutorial -</intro/tutorial03>` to start working on public poll views. diff --git a/parts/django/docs/intro/tutorial03.txt b/parts/django/docs/intro/tutorial03.txt deleted file mode 100644 index 0843d9e..0000000 --- a/parts/django/docs/intro/tutorial03.txt +++ /dev/null @@ -1,546 +0,0 @@ -===================================== -Writing your first Django app, part 3 -===================================== - -This tutorial begins where :doc:`Tutorial 2 </intro/tutorial02>` left off. We're -continuing the Web-poll application and will focus on creating the public -interface -- "views." - -Philosophy -========== - -A view is a "type" of Web page in your Django application that generally serves -a specific function and has a specific template. For example, in a Weblog -application, you might have the following views: - - * Blog homepage -- displays the latest few entries. - - * Entry "detail" page -- permalink page for a single entry. - - * Year-based archive page -- displays all months with entries in the - given year. - - * Month-based archive page -- displays all days with entries in the - given month. - - * Day-based archive page -- displays all entries in the given day. - - * Comment action -- handles posting comments to a given entry. - -In our poll application, we'll have the following four views: - - * Poll "archive" page -- displays the latest few polls. - - * Poll "detail" page -- displays a poll question, with no results but - with a form to vote. - - * Poll "results" page -- displays results for a particular poll. - - * Vote action -- handles voting for a particular choice in a particular - poll. - -In Django, each view is represented by a simple Python function. - -Design your URLs -================ - -The first step of writing views is to design your URL structure. You do this by -creating a Python module, called a URLconf. URLconfs are how Django associates -a given URL with given Python code. - -When a user requests a Django-powered page, the system looks at the -:setting:`ROOT_URLCONF` setting, which contains a string in Python dotted -syntax. Django loads that module and looks for a module-level variable called -``urlpatterns``, which is a sequence of tuples in the following format:: - - (regular expression, Python callback function [, optional dictionary]) - -Django starts at the first regular expression and makes its way down the list, -comparing the requested URL against each regular expression until it finds one -that matches. - -When it finds a match, Django calls the Python callback function, with an -:class:`~django.http.HttpRequest` object as the first argument, any "captured" -values from the regular expression as keyword arguments, and, optionally, -arbitrary keyword arguments from the dictionary (an optional third item in the -tuple). - -For more on :class:`~django.http.HttpRequest` objects, see the -:doc:`/ref/request-response`. For more details on URLconfs, see the -:doc:`/topics/http/urls`. - -When you ran ``django-admin.py startproject mysite`` at the beginning of -Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also -automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to -point at that file:: - - ROOT_URLCONF = 'mysite.urls' - -Time for an example. Edit ``mysite/urls.py`` so it looks like this:: - - from django.conf.urls.defaults import * - - from django.contrib import admin - admin.autodiscover() - - urlpatterns = patterns('', - (r'^polls/$', 'polls.views.index'), - (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), - (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), - (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), - (r'^admin/', include(admin.site.urls)), - ) - -This is worth a review. When somebody requests a page from your Web site -- say, -"/polls/23/", Django will load this Python module, because it's pointed to by -the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns`` -and traverses the regular expressions in order. When it finds a regular -expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the -function ``detail()`` from ``polls/views.py``. Finally, it calls that -``detail()`` function like so:: - - detail(request=<HttpRequest object>, poll_id='23') - -The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses -around a pattern "captures" the text matched by that pattern and sends it as an -argument to the view function; the ``?P<poll_id>`` defines the name that will be -used to identify the matched pattern; and ``\d+`` is a regular expression to -match a sequence of digits (i.e., a number). - -Because the URL patterns are regular expressions, there really is no limit on -what you can do with them. And there's no need to add URL cruft such as ``.php`` --- unless you have a sick sense of humor, in which case you can do something -like this:: - - (r'^polls/latest\.php$', 'polls.views.index'), - -But, don't do that. It's silly. - -Note that these regular expressions do not search GET and POST parameters, or -the domain name. For example, in a request to ``http://www.example.com/myapp/``, -the URLconf will look for ``myapp/``. In a request to -``http://www.example.com/myapp/?page=3``, the URLconf will look for ``myapp/``. - -If you need help with regular expressions, see `Wikipedia's entry`_ and the -`Python documentation`_. Also, the O'Reilly book "Mastering Regular Expressions" -by Jeffrey Friedl is fantastic. - -Finally, a performance note: these regular expressions are compiled the first -time the URLconf module is loaded. They're super fast. - -.. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression -.. _Python documentation: http://docs.python.org/library/re.html - -Write your first view -===================== - -Well, we haven't created any views yet -- we just have the URLconf. But let's -make sure Django is following the URLconf properly. - -Fire up the Django development Web server: - -.. code-block:: bash - - python manage.py runserver - -Now go to "http://localhost:8000/polls/" on your domain in your Web browser. -You should get a pleasantly-colored error page with the following message:: - - ViewDoesNotExist at /polls/ - - Tried index in module polls.views. Error was: 'module' - object has no attribute 'index' - -This error happened because you haven't written a function ``index()`` in the -module ``polls/views.py``. - -Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error -messages tell you which view Django tried (and failed to find, because you -haven't written any views yet). - -Time to write the first view. Open the file ``polls/views.py`` -and put the following Python code in it:: - - from django.http import HttpResponse - - def index(request): - return HttpResponse("Hello, world. You're at the poll index.") - -This is the simplest view possible. Go to "/polls/" in your browser, and you -should see your text. - -Now lets add a few more views. These views are slightly different, because -they take an argument (which, remember, is passed in from whatever was -captured by the regular expression in the URLconf):: - - def detail(request, poll_id): - return HttpResponse("You're looking at poll %s." % poll_id) - - def results(request, poll_id): - return HttpResponse("You're looking at the results of poll %s." % poll_id) - - def vote(request, poll_id): - return HttpResponse("You're voting on poll %s." % poll_id) - -Take a look in your browser, at "/polls/34/". It'll run the `detail()` method -and display whatever ID you provide in the URL. Try "/polls/34/results/" and -"/polls/34/vote/" too -- these will display the placeholder results and voting -pages. - -Write views that actually do something -====================================== - -Each view is responsible for doing one of two things: Returning an -:class:`~django.http.HttpResponse` object containing the content for the -requested page, or raising an exception such as :exc:`~django.http.Http404`. The -rest is up to you. - -Your view can read records from a database, or not. It can use a template -system such as Django's -- or a third-party Python template system -- or not. -It can generate a PDF file, output XML, create a ZIP file on the fly, anything -you want, using whatever Python libraries you want. - -All Django wants is that :class:`~django.http.HttpResponse`. Or an exception. - -Because it's convenient, let's use Django's own database API, which we covered -in :doc:`Tutorial 1 </intro/tutorial01>`. Here's one stab at the ``index()`` -view, which displays the latest 5 poll questions in the system, separated by -commas, according to publication date:: - - from polls.models import Poll - from django.http import HttpResponse - - def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] - output = ', '.join([p.question for p in latest_poll_list]) - return HttpResponse(output) - -There's a problem here, though: The page's design is hard-coded in the view. If -you want to change the way the page looks, you'll have to edit this Python code. -So let's use Django's template system to separate the design from Python:: - - from django.template import Context, loader - from polls.models import Poll - from django.http import HttpResponse - - def index(request): - 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, - }) - return HttpResponse(t.render(c)) - -That code loads the template called "polls/index.html" and passes it a context. -The context is a dictionary mapping template variable names to Python objects. - -Reload the page. Now you'll see an error:: - - TemplateDoesNotExist at /polls/ - polls/index.html - -Ah. There's no template yet. First, create a directory, somewhere on your -filesystem, whose contents Django can access. (Django runs as whatever user your -server runs.) Don't put them under your document root, though. You probably -shouldn't make them public, just for security's sake. -Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py`` to tell Django where -it can find templates -- just as you did in the "Customize the admin look and -feel" section of Tutorial 2. - -When you've done that, create a directory ``polls`` in your template directory. -Within that, create a file called ``index.html``. Note that our -``loader.get_template('polls/index.html')`` code from above maps to -"[template_directory]/polls/index.html" on the filesystem. - -Put the following code in that template: - -.. code-block:: html+django - - {% if latest_poll_list %} - <ul> - {% for poll in latest_poll_list %} - <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> - {% endfor %} - </ul> - {% else %} - <p>No polls are available.</p> - {% endif %} - -Load the page in your Web browser, and you should see a bulleted-list -containing the "What's up" poll from Tutorial 1. The link points to the poll's -detail page. - -A shortcut: render_to_response() --------------------------------- - -It's a very common idiom to load a template, fill a context and return an -:class:`~django.http.HttpResponse` object with the result of the rendered -template. Django provides a shortcut. Here's the full ``index()`` view, -rewritten:: - - from django.shortcuts import render_to_response - from polls.models import Poll - - def index(request): - latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] - return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}) - -Note that once we've done this in all these views, we no longer need to import -:mod:`~django.template.loader`, :class:`~django.template.Context` and -:class:`~django.http.HttpResponse`. - -The :func:`~django.shortcuts.render_to_response` function takes a template name -as its first argument and a dictionary as its optional second argument. It -returns an :class:`~django.http.HttpResponse` object of the given template -rendered with the given context. - -Raising 404 -=========== - -Now, let's tackle the poll detail view -- the page that displays the question -for a given poll. Here's the view:: - - from django.http import Http404 - # ... - def detail(request, poll_id): - try: - p = Poll.objects.get(pk=poll_id) - except Poll.DoesNotExist: - raise Http404 - return render_to_response('polls/detail.html', {'poll': p}) - -The new concept here: The view raises the :exc:`~django.http.Http404` exception -if a poll with the requested ID doesn't exist. - -We'll discuss what you could put in that ``polls/detail.html`` template a bit -later, but if you'd like to quickly get the above example working, just:: - - {{ poll }} - -will get you started for now. - -A shortcut: get_object_or_404() -------------------------------- - -It's a very common idiom to use :meth:`~django.db.models.QuerySet.get` and raise -:exc:`~django.http.Http404` if the object doesn't exist. Django provides a -shortcut. Here's the ``detail()`` view, rewritten:: - - from django.shortcuts import render_to_response, get_object_or_404 - # ... - def detail(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/detail.html', {'poll': p}) - -The :func:`~django.shortcuts.get_object_or_404` function takes a Django model -as its first argument and an arbitrary number of keyword arguments, which it -passes to the module's :meth:`~django.db.models.QuerySet.get` function. It -raises :exc:`~django.http.Http404` if the object doesn't exist. - -.. admonition:: Philosophy - - Why do we use a helper function :func:`~django.shortcuts.get_object_or_404` - instead of automatically catching the - :exc:`~django.core.exceptions.ObjectDoesNotExist` exceptions at a higher - level, or having the model API raise :exc:`~django.http.Http404` instead of - :exc:`~django.core.exceptions.ObjectDoesNotExist`? - - Because that would couple the model layer to the view layer. One of the - foremost design goals of Django is to maintain loose coupling. - -There's also a :func:`~django.shortcuts.get_list_or_404` function, which works -just as :func:`~django.shortcuts.get_object_or_404` -- except using -:meth:`~django.db.models.QuerySet.filter` instead of -:meth:`~django.db.models.QuerySet.get`. It raises :exc:`~django.http.Http404` if -the list is empty. - -Write a 404 (page not found) view -================================= - -When you raise :exc:`~django.http.Http404` from within a view, Django will load -a special view devoted to handling 404 errors. It finds it by looking for the -variable ``handler404``, which is a string in Python dotted syntax -- the same -format the normal URLconf callbacks use. A 404 view itself has nothing special: -It's just a normal view. - -You normally won't have to bother with writing 404 views. By default, URLconfs -have the following line up top:: - - from django.conf.urls.defaults import * - -That takes care of setting ``handler404`` in the current module. As you can see -in ``django/conf/urls/defaults.py``, ``handler404`` is set to -:func:`django.views.defaults.page_not_found` by default. - -Four more things to note about 404 views: - - * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your - 404 view will never be used (and thus the ``404.html`` template will never - be rendered) because the traceback will be displayed instead. - - * The 404 view is also called if Django doesn't find a match after checking - every regular expression in the URLconf. - - * If you don't define your own 404 view -- and simply use the default, which - is recommended -- you still have one obligation: To create a ``404.html`` - template in the root of your template directory. The default 404 view will - use that template for all 404 errors. - - * If :setting:`DEBUG` is set to ``False`` (in your settings module) and if - you didn't create a ``404.html`` file, an ``Http500`` is raised instead. - So remember to create a ``404.html``. - -Write a 500 (server error) view -=============================== - -Similarly, URLconfs may define a ``handler500``, which points to a view to call -in case of server errors. Server errors happen when you have runtime errors in -view code. - -Use the template system -======================= - -Back to the ``detail()`` view for our poll application. Given the context -variable ``poll``, here's what the "polls/detail.html" template might look -like: - -.. code-block:: html+django - - <h1>{{ poll.question }}</h1> - <ul> - {% for choice in poll.choice_set.all %} - <li>{{ choice.choice }}</li> - {% endfor %} - </ul> - -The template system uses dot-lookup syntax to access variable attributes. In -the example of ``{{ poll.question }}``, first Django does a dictionary lookup -on the object ``poll``. Failing that, it tries attribute lookup -- which works, -in this case. If attribute lookup had failed, it would've tried calling the -method ``question()`` on the poll object. - -Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is -interpreted as the Python code ``poll.choice_set.all()``, which returns an -iterable of Choice objects and is suitable for use in the ``{% for %}`` tag. - -See the :doc:`template guide </topics/templates>` for more about templates. - -Simplifying the URLconfs -======================== - -Take some time to play around with the views and template system. As you edit -the URLconf, you may notice there's a fair bit of redundancy in it:: - - urlpatterns = patterns('', - (r'^polls/$', 'polls.views.index'), - (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), - (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), - (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), - ) - -Namely, ``polls.views`` is in every callback. - -Because this is a common case, the URLconf framework provides a shortcut for -common prefixes. You can factor out the common prefixes and add them as the -first argument to :func:`~django.conf.urls.defaults.patterns`, like so:: - - urlpatterns = patterns('polls.views', - (r'^polls/$', 'index'), - (r'^polls/(?P<poll_id>\d+)/$', 'detail'), - (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), - (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), - ) - -This is functionally identical to the previous formatting. It's just a bit -tidier. - -Since you generally don't want the prefix for one app to be applied to every -callback in your URLconf, you can concatenate multiple -:func:`~django.conf.urls.defaults.patterns`. Your full ``mysite/urls.py`` might -now look like this:: - - from django.conf.urls.defaults import * - - from django.contrib import admin - admin.autodiscover() - - urlpatterns = patterns('polls.views', - (r'^polls/$', 'index'), - (r'^polls/(?P<poll_id>\d+)/$', 'detail'), - (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), - (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), - ) - - urlpatterns += patterns('', - (r'^admin/', include(admin.site.urls)), - ) - -Decoupling the URLconfs -======================= - -While we're at it, we should take the time to decouple our poll-app URLs from -our Django project configuration. Django apps are meant to be pluggable -- that -is, each particular app should be transferable to another Django installation -with minimal fuss. - -Our poll app is pretty decoupled at this point, thanks to the strict directory -structure that ``python manage.py startapp`` created, but one part of it is -coupled to the Django settings: The URLconf. - -We've been editing the URLs in ``mysite/urls.py``, but the URL design of an -app is specific to the app, not to the Django installation -- so let's move the -URLs within the app directory. - -Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change -``mysite/urls.py`` to remove the poll-specific URLs and insert an -:func:`~django.conf.urls.defaults.include`, leaving you with:: - - # This also imports the include function - from django.conf.urls.defaults import * - - from django.contrib import admin - admin.autodiscover() - - urlpatterns = patterns('', - (r'^polls/', include('polls.urls')), - (r'^admin/', include(admin.site.urls)), - ) - -:func:`~django.conf.urls.defaults.include` simply references another URLconf. -Note that the regular expression doesn't have a ``$`` (end-of-string match -character) but has the trailing slash. Whenever Django encounters -:func:`~django.conf.urls.defaults.include`, it chops off whatever part of the -URL matched up to that point and sends the remaining string to the included -URLconf for further processing. - -Here's what happens if a user goes to "/polls/34/" in this system: - - * Django will find the match at ``'^polls/'`` - - * Then, Django will strip off the matching text (``"polls/"``) and send the - remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for - further processing. - -Now that we've decoupled that, we need to decouple the ``polls.urls`` -URLconf by removing the leading "polls/" from each line, and removing the -lines registering the admin site. Your ``polls.urls`` file should now look like -this:: - - from django.conf.urls.defaults import * - - urlpatterns = patterns('polls.views', - (r'^$', 'index'), - (r'^(?P<poll_id>\d+)/$', 'detail'), - (r'^(?P<poll_id>\d+)/results/$', 'results'), - (r'^(?P<poll_id>\d+)/vote/$', 'vote'), - ) - -The idea behind :func:`~django.conf.urls.defaults.include` and URLconf -decoupling is to make it easy to plug-and-play URLs. Now that polls are in their -own URLconf, they can be placed under "/polls/", or under "/fun_polls/", or -under "/content/polls/", or any other path root, and the app will still work. - -All the poll app cares about is its relative path, not its absolute path. - -When you're comfortable with writing views, read :doc:`part 4 of this tutorial -</intro/tutorial04>` to learn about simple form processing and generic views. diff --git a/parts/django/docs/intro/tutorial04.txt b/parts/django/docs/intro/tutorial04.txt deleted file mode 100644 index dfbd82d..0000000 --- a/parts/django/docs/intro/tutorial04.txt +++ /dev/null @@ -1,346 +0,0 @@ -===================================== -Writing your first Django app, part 4 -===================================== - -This tutorial begins where :doc:`Tutorial 3 </intro/tutorial03>` left off. We're -continuing the Web-poll application and will focus on simple form processing and -cutting down our code. - -Write a simple form -=================== - -Let's update our poll detail template ("polls/detail.html") from the last -tutorial, so that the template contains an HTML ``<form>`` element: - -.. code-block:: html+django - - <h1>{{ poll.question }}</h1> - - {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} - - <form action="/polls/{{ poll.id }}/vote/" method="post"> - {% csrf_token %} - {% for choice in poll.choice_set.all %} - <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> - <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br /> - {% endfor %} - <input type="submit" value="Vote" /> - </form> - -A quick rundown: - - * The above template displays a radio button for each poll choice. The - ``value`` of each radio button is the associated poll choice's ID. The - ``name`` of each radio button is ``"choice"``. That means, when somebody - selects one of the radio buttons and submits the form, it'll send the - POST data ``choice=3``. This is HTML Forms 101. - - * We set the form's ``action`` to ``/polls/{{ poll.id }}/vote/``, and we - set ``method="post"``. Using ``method="post"`` (as opposed to - ``method="get"``) is very important, because the act of submitting this - form will alter data server-side. Whenever you create a form that alters - data server-side, use ``method="post"``. This tip isn't specific to - Django; it's just good Web development practice. - - * ``forloop.counter`` indicates how many times the :ttag:`for` tag has gone - through its loop - - * Since we're creating a POST form (which can have the effect of modifying - data), we need to worry about Cross Site Request Forgeries. - Thankfully, you don't have to worry too hard, because Django comes with - a very easy-to-use system for protecting against it. In short, all POST - forms that are targeted at internal URLs should use the ``{% csrf_token %}`` - template tag. - -The ``{% csrf_token %}`` tag requires information from the request object, which -is not normally accessible from within the template context. To fix this, a -small adjustment needs to be made to the ``detail`` view, so that it looks like -the following:: - - from django.template import RequestContext - # ... - def detail(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/detail.html', {'poll': p}, - context_instance=RequestContext(request)) - -The details of how this works are explained in the documentation for -:ref:`RequestContext <subclassing-context-requestcontext>`. - -Now, let's create a Django view that handles the submitted data and does -something with it. Remember, in :doc:`Tutorial 3 </intro/tutorial03>`, we -created a URLconf for the polls application that includes this line:: - - (r'^(?P<poll_id>\d+)/vote/$', 'vote'), - -We also created a dummy implementation of the ``vote()`` function. Let's -create a real version. Add the following to ``polls/views.py``:: - - from django.shortcuts import get_object_or_404, render_to_response - from django.http import HttpResponseRedirect, HttpResponse - from django.core.urlresolvers import reverse - from django.template import RequestContext - from polls.models import Choice, Poll - # ... - def vote(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - try: - selected_choice = p.choice_set.get(pk=request.POST['choice']) - except (KeyError, Choice.DoesNotExist): - # Redisplay the poll voting form. - return render_to_response('polls/detail.html', { - 'poll': p, - 'error_message': "You didn't select a choice.", - }, context_instance=RequestContext(request)) - else: - selected_choice.votes += 1 - selected_choice.save() - # Always return an HttpResponseRedirect after successfully dealing - # with POST data. This prevents data from being posted twice if a - # user hits the Back button. - return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,))) - -This code includes a few things we haven't covered yet in this tutorial: - - * :attr:`request.POST <django.http.HttpRequest.POST>` is a dictionary-like - object that lets you access submitted data by key name. In this case, - ``request.POST['choice']`` returns the ID of the selected choice, as a - string. :attr:`request.POST <django.http.HttpRequest.POST>` values are - always strings. - - Note that Django also provides :attr:`request.GET - <django.http.HttpRequest.GET>` for accessing GET data in the same way -- - but we're explicitly using :attr:`request.POST - <django.http.HttpRequest.POST>` in our code, to ensure that data is only - altered via a POST call. - - * ``request.POST['choice']`` will raise :exc:`KeyError` if ``choice`` wasn't - provided in POST data. The above code checks for :exc:`KeyError` and - redisplays the poll form with an error message if ``choice`` isn't given. - - * After incrementing the choice count, the code returns an - :class:`~django.http.HttpResponseRedirect` rather than a normal - :class:`~django.http.HttpResponse`. - :class:`~django.http.HttpResponseRedirect` takes a single argument: the - URL to which the user will be redirected (see the following point for how - we construct the URL in this case). - - As the Python comment above points out, you should always return an - :class:`~django.http.HttpResponseRedirect` after successfully dealing with - POST data. This tip isn't specific to Django; it's just good Web - development practice. - - * We are using the :func:`~django.core.urlresolvers.reverse` function in the - :class:`~django.http.HttpResponseRedirect` constructor in this example. - This function helps avoid having to hardcode a URL in the view function. - It is given the name of the view that we want to pass control to and the - variable portion of the URL pattern that points to that view. In this - case, using the URLconf we set up in Tutorial 3, this - :func:`~django.core.urlresolvers.reverse` call will return a string like - :: - - '/polls/3/results/' - - ... where the ``3`` is the value of ``p.id``. This redirected URL will - then call the ``'results'`` view to display the final page. Note that you - need to use the full name of the view here (including the prefix). - -As mentioned in Tutorial 3, ``request`` is a :class:`~django.http.HttpRequest` -object. For more on :class:`~django.http.HttpRequest` objects, see the -:doc:`request and response documentation </ref/request-response>`. - -After somebody votes in a poll, the ``vote()`` view redirects to the results -page for the poll. Let's write that view:: - - def results(request, poll_id): - p = get_object_or_404(Poll, pk=poll_id) - return render_to_response('polls/results.html', {'poll': p}) - -This is almost exactly the same as the ``detail()`` view from :doc:`Tutorial 3 -</intro/tutorial03>`. The only difference is the template name. We'll fix this -redundancy later. - -Now, create a ``results.html`` template: - -.. code-block:: html+django - - <h1>{{ poll.question }}</h1> - - <ul> - {% for choice in poll.choice_set.all %} - <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> - {% endfor %} - </ul> - - <a href="/polls/{{ poll.id }}/">Vote again?</a> - -Now, go to ``/polls/1/`` in your browser and vote in the poll. You should see a -results page that gets updated each time you vote. If you submit the form -without having chosen a choice, you should see the error message. - -Use generic views: Less code is better -====================================== - -The ``detail()`` (from :doc:`Tutorial 3 </intro/tutorial03>`) and ``results()`` -views are stupidly simple -- and, as mentioned above, redundant. The ``index()`` -view (also from Tutorial 3), which displays a list of polls, is similar. - -These views represent a common case of basic Web development: getting data from -the database according to a parameter passed in the URL, loading a template and -returning the rendered template. Because this is so common, Django provides a -shortcut, called the "generic views" system. - -Generic views abstract common patterns to the point where you don't even need -to write Python code to write an app. - -Let's convert our poll app to use the generic views system, so we can delete a -bunch of our own code. We'll just have to take a few steps to make the -conversion. We will: - - 1. Convert the URLconf. - - 2. Rename a few templates. - - 3. Delete some of the old, unneeded views. - - 4. Fix up URL handling for the new views. - -Read on for details. - -.. admonition:: Why the code-shuffle? - - Generally, when writing a Django app, you'll evaluate whether generic views - are a good fit for your problem, and you'll use them from the beginning, - rather than refactoring your code halfway through. But this tutorial - intentionally has focused on writing the views "the hard way" until now, to - focus on core concepts. - - You should know basic math before you start using a calculator. - -First, open the ``polls/urls.py`` URLconf. It looks like this, according to the -tutorial so far:: - - from django.conf.urls.defaults import * - - urlpatterns = patterns('polls.views', - (r'^$', 'index'), - (r'^(?P<poll_id>\d+)/$', 'detail'), - (r'^(?P<poll_id>\d+)/results/$', 'results'), - (r'^(?P<poll_id>\d+)/vote/$', 'vote'), - ) - -Change it like so:: - - from django.conf.urls.defaults import * - from polls.models import Poll - - info_dict = { - 'queryset': Poll.objects.all(), - } - - urlpatterns = patterns('', - (r'^$', 'django.views.generic.list_detail.object_list', info_dict), - (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict), - url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'), - (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), - ) - -We're using two generic views here: -:func:`~django.views.generic.list_detail.object_list` and -:func:`~django.views.generic.list_detail.object_detail`. Respectively, those two -views abstract the concepts of "display a list of objects" and "display a detail -page for a particular type of object." - - * Each generic view needs to know what data it will be acting upon. This - data is provided in a dictionary. The ``queryset`` key in this dictionary - points to the list of objects to be manipulated by the generic view. - - * The :func:`~django.views.generic.list_detail.object_detail` generic view - expects the ID value captured from the URL to be called ``"object_id"``, - so we've changed ``poll_id`` to ``object_id`` for the generic views. - - * We've added a name, ``poll_results``, to the results view so that we have - a way to refer to its URL later on (see the documentation about - :ref:`naming URL patterns <naming-url-patterns>` for information). We're - also using the :func:`~django.conf.urls.default.url` function from - :mod:`django.conf.urls.defaults` here. It's a good habit to use - :func:`~django.conf.urls.defaults.url` when you are providing a pattern - name like this. - -By default, the :func:`~django.views.generic.list_detail.object_detail` generic -view uses a template called ``<app name>/<model name>_detail.html``. In our -case, it'll use the template ``"polls/poll_detail.html"``. Thus, rename your -``polls/detail.html`` template to ``polls/poll_detail.html``, and change the -:func:`~django.shortcuts.render_to_response` line in ``vote()``. - -Similarly, the :func:`~django.views.generic.list_detail.object_list` generic -view uses a template called ``<app name>/<model 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 -:func:`~django.views.generic.list_detail.object_detail` 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. - -.. note:: :meth:`django.db.models.QuerySet.all` is lazy - - It might look a little frightening to see ``Poll.objects.all()`` being used - in a detail view which only needs one ``Poll`` object, but don't worry; - ``Poll.objects.all()`` is actually a special object called a - :class:`~django.db.models.QuerySet`, which is "lazy" and doesn't hit your - database until it absolutely has to. By the time the database query happens, - the :func:`~django.views.generic.list_detail.object_detail` generic view - will have narrowed its scope down to a single object, so the eventual query - will only select one row from the database. - - If you'd like to know more about how that works, The Django database API - documentation :ref:`explains the lazy nature of QuerySet objects - <querysets-are-lazy>`. - -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. Go through your templates, and modify any reference to -``latest_poll_list`` to ``object_list``, and change any reference to ``poll`` -to ``object``. - -You can now delete the ``index()``, ``detail()`` and ``results()`` views -from ``polls/views.py``. We don't need them anymore -- they have been replaced -by generic views. - -The ``vote()`` view is still required. However, it must be modified to match the -new context variables. In the :func:`~django.shortcuts.render_to_response` call, -rename the ``poll`` context variable to ``object``. - -The last thing to do is fix the URL handling to account for the use of generic -views. In the vote view above, we used the -:func:`~django.core.urlresolvers.reverse` function to avoid hard-coding our -URLs. Now that we've switched to a generic view, we'll need to change the -:func:`~django.core.urlresolvers.reverse` call to point back to our new generic -view. We can't simply use the view function anymore -- generic views can be (and -are) used multiple times -- but we can use the name we've given:: - - return HttpResponseRedirect(reverse('poll_results', args=(p.id,))) - -Run the server, and use your new polling app based on generic views. - -For full details on generic views, see the :doc:`generic views documentation -</topics/http/generic-views>`. - -Coming soon -=========== - -The tutorial ends here for the time being. Future installments of the tutorial -will cover: - - * Advanced form processing - * Using the RSS framework - * Using the cache framework - * Using the comments framework - * Advanced admin features: Permissions - * Advanced admin features: Custom JavaScript - -In the meantime, you might want to check out some pointers on :doc:`where to go -from here </intro/whatsnext>` diff --git a/parts/django/docs/intro/whatsnext.txt b/parts/django/docs/intro/whatsnext.txt deleted file mode 100644 index 00c1654..0000000 --- a/parts/django/docs/intro/whatsnext.txt +++ /dev/null @@ -1,231 +0,0 @@ -================= -What to read next -================= - -So you've read all the :doc:`introductory material </intro/index>` and have -decided you'd like to keep using Django. We've only just scratched the surface -with this intro (in fact, if you've read every single word you've still read -less than 10% of the overall documentation). - -So what's next? - -Well, we've always been big fans of learning by doing. At this point you should -know enough to start a project of your own and start fooling around. As you need -to learn new tricks, come back to the documentation. - -We've put a lot of effort into making Django's documentation useful, easy to -read and as complete as possible. The rest of this document explains more about -how the documentation works so that you can get the most out of it. - -(Yes, this is documentation about documentation. Rest assured we have no plans -to write a document about how to read the document about documentation.) - -Finding documentation -===================== - -Django's got a *lot* of documentation -- almost 200,000 words -- so finding what -you need can sometimes be tricky. A few good places to start are the :ref:`search` -and the :ref:`genindex`. - -Or you can just browse around! - -How the documentation is organized -================================== - -Django's main documentation is broken up into "chunks" designed to fill -different needs: - - * The :doc:`introductory material </intro/index>` is designed for people new - to Django -- or to Web development in general. It doesn't cover anything - in depth, but instead gives a high-level overview of how developing in - Django "feels". - - * The :doc:`topic guides </topics/index>`, on the other hand, dive deep into - individual parts of Django. There are complete guides to Django's - :doc:`model system </topics/db/index>`, :doc:`template engine - </topics/templates>`, :doc:`forms framework </topics/forms/index>`, and much - more. - - This is probably where you'll want to spend most of your time; if you work - your way through these guides you should come out knowing pretty much - everything there is to know about Django. - - * Web development is often broad, not deep -- problems span many domains. - We've written a set of :doc:`how-to guides </howto/index>` that answer - common "How do I ...?" questions. Here you'll find information about - :doc:`generating PDFs with Django </howto/outputting-pdf>`, :doc:`writing - custom template tags </howto/custom-template-tags>`, and more. - - Answers to really common questions can also be found in the :doc:`FAQ - </faq/index>`. - - * The guides and how-to's don't cover every single class, function, and - method available in Django -- that would be overwhelming when you're - trying to learn. Instead, details about individual classes, functions, - methods, and modules are kept in the :doc:`reference </ref/index>`. This is - where you'll turn to find the details of a particular function or - whathaveyou. - - * Finally, there's some "specialized" documentation not usually relevant to - most developers. This includes the :doc:`release notes </releases/index>`, - :doc:`documentation of obsolete features </obsolete/index>`, - :doc:`internals documentation </internals/index>` for those who want to add - code to Django itself, and a :doc:`few other things that simply don't fit - elsewhere </misc/index>`. - - -How documentation is updated -============================ - -Just as the Django code base is developed and improved on a daily basis, our -documentation is consistently improving. We improve documentation for several -reasons: - - * To make content fixes, such as grammar/typo corrections. - - * To add information and/or examples to existing sections that need to be - expanded. - - * To document Django features that aren't yet documented. (The list of - such features is shrinking but exists nonetheless.) - - * To add documentation for new features as new features get added, or as - Django APIs or behaviors change. - -Django's documentation is kept in the same source control system as its code. It -lives in the `django/trunk/docs`_ directory of our Subversion repository. Each -document online is a separate text file in the repository. - -.. _django/trunk/docs: http://code.djangoproject.com/browser/django/trunk/docs - -Where to get it -=============== - -You can read Django documentation in several ways. They are, in order of -preference: - -On the Web ----------- - -The most recent version of the Django documentation lives at -http://docs.djangoproject.com/en/dev/. These HTML pages are generated -automatically from the text files in source control. That means they reflect the -"latest and greatest" in Django -- they include the very latest corrections and -additions, and they discuss the latest Django features, which may only be -available to users of the Django development version. (See "Differences between -versions" below.) - -We encourage you to help improve the docs by submitting changes, corrections and -suggestions in the `ticket system`_. The Django developers actively monitor the -ticket system and use your feedback to improve the documentation for everybody. - -Note, however, that tickets should explicitly relate to the documentation, -rather than asking broad tech-support questions. If you need help with your -particular Django setup, try the `django-users mailing list`_ or the `#django -IRC channel`_ instead. - -.. _ticket system: http://code.djangoproject.com/simpleticket?component=Documentation -.. _django-users mailing list: http://groups.google.com/group/django-users -.. _#django IRC channel: irc://irc.freenode.net/django - -In plain text -------------- - -For offline reading, or just for convenience, you can read the Django -documentation in plain text. - -If you're using an official release of Django, note that the zipped package -(tarball) of the code includes a ``docs/`` directory, which contains all the -documentation for that release. - -If you're using the development version of Django (aka the Subversion "trunk"), -note that the ``docs/`` directory contains all of the documentation. You can -``svn update`` it, just as you ``svn update`` the Python code, in order to get -the latest changes. - -You can check out the latest Django documentation from Subversion using this -shell command: - -.. code-block:: bash - - $ svn co http://code.djangoproject.com/svn/django/trunk/docs/ django_docs - -One low-tech way of taking advantage of the text documentation is by using the -Unix ``grep`` utility to search for a phrase in all of the documentation. For -example, this will show you each mention of the phrase "max_length" in any -Django document: - -.. code-block:: bash - - $ grep -r max_length /path/to/django/docs/ - -As HTML, locally ----------------- - -You can get a local copy of the HTML documentation following a few easy steps: - - * Django's documentation uses a system called Sphinx__ to convert from - plain text to HTML. You'll need to install Sphinx by either downloading - and installing the package from the Sphinx Web site, or by Python's - ``easy_install``: - - .. code-block:: bash - - $ easy_install Sphinx - - * Then, just use the included ``Makefile`` to turn the documentation into - HTML: - - .. code-block:: bash - - $ cd path/to/django/docs - $ make html - - You'll need `GNU Make`__ installed for this. - - * The HTML documentation will be placed in ``docs/_build/html``. - -.. note:: - - Generation of the Django documentation will work with Sphinx version 0.6 - or newer, but we recommend going straight to Sphinx 1.0.2 or newer. - -__ http://sphinx.pocoo.org/ -__ http://www.gnu.org/software/make/ - -Differences between versions -============================ - -As previously mentioned, the text documentation in our Subversion repository -contains the "latest and greatest" changes and additions. These changes often -include documentation of new features added in the Django development version --- the Subversion ("trunk") version of Django. For that reason, it's worth -pointing out our policy on keeping straight the documentation for various -versions of the framework. - -We follow this policy: - - * The primary documentation on djangoproject.com is an HTML version of the - latest docs in Subversion. These docs always correspond to the latest - official Django release, plus whatever features we've added/changed in - the framework *since* the latest release. - - * As we add features to Django's development version, we try to update the - documentation in the same Subversion commit transaction. - - * To distinguish feature changes/additions in the docs, we use the phrase: - "New in version X.Y", being X.Y the next release version (hence, the one - being developed). - - * Documentation for a particular Django release is frozen once the version - has been released officially. It remains a snapshot of the docs as of the - moment of the release. We will make exceptions to this rule in - the case of retroactive security updates or other such retroactive - changes. Once documentation is frozen, we add a note to the top of each - frozen document that says "These docs are frozen for Django version XXX" - and links to the current version of that document. - - * The `main documentation Web page`_ includes links to documentation for - all previous versions. - -.. _main documentation Web page: http://docs.djangoproject.com/en/dev/ |