Fixed #19706 - Tweaks to the tutorial.

Thanks Daniele Procida.
This commit is contained in:
Tim Graham 2013-02-07 05:51:25 -05:00
parent 43efefae69
commit aa85ccf8ce
5 changed files with 116 additions and 98 deletions

View File

@ -50,8 +50,8 @@ projects and ready to publish for others to install and use.
Python package easy for others to install. It can be a little confusing, we
know.
Completing your reusable app
============================
Your project and your reusable app
==================================
After the previous tutorials, our project should look like this::
@ -67,78 +67,28 @@ After the previous tutorials, our project should look like this::
admin.py
models.py
tests.py
urls.py
views.py
You also have a directory somewhere called ``mytemplates`` which you created in
:doc:`Tutorial 2 </intro/tutorial02>`. You specified its location in the
TEMPLATE_DIRS setting. This directory should look like this::
mytemplates/
admin/
base_site.html
polls/
detail.html
index.html
results.html
The polls app is already a Python package, thanks to the ``polls/__init__.py``
file. That's a great start, but we can't just pick up this package and drop it
into a new project. The polls templates are currently stored in the
project-wide ``mytemplates`` directory. To make the app self-contained, it
should also contain the necessary templates.
Inside the ``polls`` app, create a new ``templates`` directory. Now move the
``polls`` template directory from ``mytemplates`` into the new
``templates``. Your project should now look like this::
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
polls/
admin.py
__init__.py
models.py
templates/
polls/
detail.html
index.html
results.html
tests.py
urls.py
views.py
mytemplates/
admin/
base_site.html
Your project-wide templates directory should now look like this::
mytemplates/
admin/
base_site.html
Looking good! Now would be a good time to confirm that your polls application
still works correctly. How does Django know how to find the new location of
the polls templates even though we didn't modify :setting:`TEMPLATE_DIRS`?
Django has a :setting:`TEMPLATE_LOADERS` setting which contains a list
of callables that know how to import templates from various sources. One of
the defaults is :class:`django.template.loaders.app_directories.Loader` which
looks for a "templates" subdirectory in each of the :setting:`INSTALLED_APPS`.
You created ``mysite/mytemplates`` in :doc:`Tutorial 2 </intro/tutorial02>`,
and ``polls/templates`` in :doc:`Tutorial 3 </intro/tutorial03>`. Now perhaps
it is clearer why we chose to have separate template directories for the
project and application: everything that is part of the polls application is in
``polls``. It makes the application self-contained and easier to drop into a
new project.
The ``polls`` directory could now be copied into a new Django project and
immediately reused. It's not quite ready to be published though. For that, we
need to package the app to make it easy for others to install.
.. admonition:: Why nested?
Why create a ``polls`` directory under ``templates`` when we're
already inside the polls app? This directory is needed to avoid conflicts in
Django's ``app_directories`` template loader. For example, if two
apps had a template called ``base.html``, without the extra directory it
wouldn't be possible to distinguish between the two. It's a good convention
to use the name of your app for this directory.
.. _installing-reusable-apps-prerequisites:
Installing some prerequisites

View File

@ -146,7 +146,7 @@ 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
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.)
@ -354,7 +354,7 @@ These concepts are represented by simple Python classes. Edit the
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField()
votes = models.IntegerField(default=0)
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
@ -377,11 +377,15 @@ 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.
Some :class:`~django.db.models.Field` classes have required arguments.
:class:`~django.db.models.CharField`, for example, requires that you give it a
:attr:`~django.db.models.CharField.max_length`. That's used not only in the
database schema, but in validation, as we'll soon see.
A :class:`~django.db.models.Field` can also have various optional arguments; in
this case, we've set the :attr:`~django.db.models.Field.default` value of
``votes`` to 0.
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:

View File

@ -399,6 +399,11 @@ 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.
.. _ref-customizing-your-projects-templates:
Customizing your *project's* templates
--------------------------------------
Create a ``mytemplates`` directory in your project directory. Templates can
live anywhere on your filesystem that Django can access. (Django runs as
whatever user your server runs.) However, keeping your templates within the
@ -446,11 +451,24 @@ 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.
Customizing your *application's* templates
------------------------------------------
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.
each application package, for use as a fallback (don't forget that
``django.contrib.admin`` is an application).
Our poll application is not very complex and doesn't need custom admin
templates. But if it grew more sophisticated and required modification of
Django's standard admin templates for some of its functionality, it would be
more sensible to modify the *application's* templates, rather than those in the
*project*. That way, you could include the polls application in any new project
and be assured that it would find the custom templates it needed.
See the :ref:`template loader documentation <template-loaders>` for more
information about how Django finds its templates.
Customize the admin index page
==============================

View File

@ -39,7 +39,24 @@ In our poll application, we'll have the following four views:
* Vote action -- handles voting for a particular choice in a particular
poll.
In Django, each view is represented by a simple Python function.
In Django, web pages and other content are delivered by views. Each view is
represented by a simple Python function (or method, in the case of class-based
views). Django will choose a view by examining the URL that's requested (to be
precise, the part of the URL after the domain name).
Now in your time on the web you may have come across such beauties as
"ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B".
You will be pleased to know that Django allows us much more elegant
*URL patterns* than that.
A URL pattern is simply the general form of a URL - for example:
``/newsarchive/<year>/<month>/``.
To get from a URL to a view, Django uses what are known as 'URLconfs'. A
URLconf maps URL patterns (described as regular expressions) to views.
This tutorial provides basic instruction in the use of URLconfs, and you can
refer to :mod:`django.core.urlresolvers` for more information.
Write your first view
=====================
@ -52,19 +69,8 @@ and put the following Python code in it::
def index(request):
return HttpResponse("Hello, world. You're at the poll index.")
This is the simplest view possible in Django. Now we have a problem, how does
this view get called? For that we need to map it to a URL, in Django this is
done in a configuration file called a URLconf.
.. admonition:: What is a URLconf?
In Django, web pages and other content are delivered by views and
determining which view is called is done by Python modules informally
titled 'URLconfs'. These modules are pure Python code and are a simple
mapping between URL patterns (as simple regular expressions) to Python
callback functions (your views). This tutorial provides basic instruction
in their use, and you can refer to :mod:`django.core.urlresolvers` for
more information.
This is the simplest view possible in Django. To call the view, we need to map
it to a URL - and for this we need a URLconf.
To create a URLconf in the polls directory, create a file called ``urls.py``.
Your app directory should now look like::
@ -274,10 +280,48 @@ commas, according to publication date::
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.
So let's use Django's template system to separate the design from Python by
creating a template that the view can use.
First, create a directory called ``templates`` in your ``polls`` directory.
Django will look for templates in there.
Django's :setting:`TEMPLATE_LOADERS` setting contains a list of callables that
know how to import templates from various sources. One of the defaults is
:class:`django.template.loaders.app_directories.Loader` which looks for a
"templates" subdirectory in each of the :setting:`INSTALLED_APPS` - this is how
Django knows to find the polls templates even though we didn't modify
:setting:`TEMPLATE_DIRS`, as we did in :ref:`Tutorial 2
<ref-customizing-your-projects-templates>`.
.. admonition:: Organizing templates
We *could* have all our templates together, in one big templates directory,
and it would work perfectly well. However, this template belongs to the
polls application, so unlike the admin template we created in the previous
tutorial, we'll put this one in the application's template directory
(``polls/templates``) rather than the project's (``mytemplates``). We'll
discuss in more detail in the :doc:`reusable apps tutorial
</intro/reusable-apps>` *why* we do this.
Within the ``templates`` directory you have just created, create another
directory called ``polls``, and within that create a file called
``index.html``. In other words, your template should be at
``polls/templates/polls/index.html``. Because of how the ``app_directories``
template loader works as described above, you can refer to this template within
Django simply as ``polls/index.html``.
.. admonition:: Template namespacing
Now we *might* be able to get away with putting our templates directly in
``polls/templates`` (rather than creating another ``polls`` subdirectory),
but it would actually be a bad idea. Django will choose the first template
it finds whose name matches, and if you had a template with the same name
in a *different* application, Django would be unable to distinguish between
them. We need to be able to point Django at the right one, and the easiest
way to ensure this is by *namespacing* them. That is, by putting those
templates inside *another* directory named for the application itself.
First, create a directory ``polls`` in your template directory you specified
in :setting:`TEMPLATE_DIRS`. Within that, create a file called ``index.html``.
Put the following code in that template:
.. code-block:: html+django
@ -311,15 +355,9 @@ 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.
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.
.. admonition:: Organizing Templates
Rather than one big templates directory, you can also store templates
within each app. We'll discuss this in more detail in the :doc:`reusable
apps tutorial</intro/reusable-apps>`.
Load the page by pointing your browser at "/polls/", 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: :func:`~django.shortcuts.render`
--------------------------------------------
@ -536,8 +574,9 @@ view, and so might an app on the same project that is for a blog. How does one
make it so that Django knows which app view to create for a url when using the
``{% url %}`` template tag?
The answer is to add namespaces to your root URLconf. In the
``mysite/urls.py`` file, go ahead and change it to include namespacing::
The answer is to add namespaces to your root URLconf. In the ``mysite/urls.py``
file (the project's ``urls.py``, not the application's), go ahead and change
it to include namespacing::
from django.conf.urls import patterns, include, url

View File

@ -33,7 +33,7 @@ A quick rundown:
``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.
POST data ``choice=3``. This is the basic concept of HTML forms.
* We set the form's ``action`` to ``{% url 'polls:vote' poll.id %}``, and we
set ``method="post"``. Using ``method="post"`` (as opposed to
@ -199,6 +199,9 @@ Read on for details.
You should know basic math before you start using a calculator.
Amend URLconf
-------------
First, open the ``polls/urls.py`` URLconf and change it like so::
from django.conf.urls import patterns, url
@ -225,6 +228,9 @@ First, open the ``polls/urls.py`` URLconf and change it like so::
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'),
)
Amend views
-----------
We're using two generic views here:
:class:`~django.views.generic.list.ListView` and
:class:`~django.views.generic.detail.DetailView`. Respectively, those
@ -267,9 +273,10 @@ As an alternative approach, you could change your templates to match
the new default context variables -- but it's a lot easier to just
tell Django to use the variable you want.
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.
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. You can also delete the import for ``HttpResponse``, which is no
longer required.
Run the server, and use your new polling app based on generic views.