mirror of https://github.com/django/django.git
[1.5.x] Fixed #19706 - Tweaks to the tutorial.
Thanks Daniele Procida.
Backport of aa85ccf8ce
from master.
This commit is contained in:
parent
a81363d85a
commit
ad2311dfc6
|
@ -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
|
Python package easy for others to install. It can be a little confusing, we
|
||||||
know.
|
know.
|
||||||
|
|
||||||
Completing your reusable app
|
Your project and your reusable app
|
||||||
============================
|
==================================
|
||||||
|
|
||||||
After the previous tutorials, our project should look like this::
|
After the previous tutorials, our project should look like this::
|
||||||
|
|
||||||
|
@ -67,78 +67,28 @@ After the previous tutorials, our project should look like this::
|
||||||
__init__.py
|
__init__.py
|
||||||
models.py
|
models.py
|
||||||
tests.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/
|
templates/
|
||||||
polls/
|
polls/
|
||||||
detail.html
|
detail.html
|
||||||
index.html
|
index.html
|
||||||
results.html
|
results.html
|
||||||
tests.py
|
|
||||||
urls.py
|
urls.py
|
||||||
views.py
|
views.py
|
||||||
|
mytemplates/
|
||||||
|
admin/
|
||||||
|
base_site.html
|
||||||
|
|
||||||
Your project-wide templates directory should now look like this::
|
You created ``mysite/mytemplates`` in :doc:`Tutorial 2 </intro/tutorial02>`,
|
||||||
|
and ``polls/templates`` in :doc:`Tutorial 3 </intro/tutorial03>`. Now perhaps
|
||||||
mytemplates/
|
it is clearer why we chose to have separate template directories for the
|
||||||
admin/
|
project and application: everything that is part of the polls application is in
|
||||||
base_site.html
|
``polls``. It makes the application self-contained and easier to drop into a
|
||||||
|
new project.
|
||||||
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`.
|
|
||||||
|
|
||||||
The ``polls`` directory could now be copied into a new Django project and
|
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
|
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.
|
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-reusable-apps-prerequisites:
|
||||||
|
|
||||||
Installing some prerequisites
|
Installing some prerequisites
|
||||||
|
|
|
@ -144,7 +144,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
|
rapidly, without having to deal with configuring a production server -- such as
|
||||||
Apache -- until you're ready for production.
|
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
|
production environment. It's intended only for use while developing. (We're in
|
||||||
the business of making Web frameworks, not Web servers.)
|
the business of making Web frameworks, not Web servers.)
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ These concepts are represented by simple Python classes. Edit the
|
||||||
class Choice(models.Model):
|
class Choice(models.Model):
|
||||||
poll = models.ForeignKey(Poll)
|
poll = models.ForeignKey(Poll)
|
||||||
choice_text = models.CharField(max_length=200)
|
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
|
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
|
subclasses :class:`django.db.models.Model`. Each model has a number of class
|
||||||
|
@ -370,11 +370,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
|
other fields in this model, the field's machine-readable name will suffice as
|
||||||
its human-readable name.
|
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
|
: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
|
:attr:`~django.db.models.CharField.max_length`. That's used not only in the
|
||||||
database schema, but in validation, as we'll soon see.
|
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
|
Finally, note a relationship is defined, using
|
||||||
:class:`~django.db.models.ForeignKey`. That tells Django each ``Choice`` is related
|
:class:`~django.db.models.ForeignKey`. That tells Django each ``Choice`` is related
|
||||||
to a single ``Poll``. Django supports all the common database relationships:
|
to a single ``Poll``. Django supports all the common database relationships:
|
||||||
|
|
|
@ -435,10 +435,10 @@ 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
|
is powered by Django itself, and its interfaces use Django's own template
|
||||||
system.
|
system.
|
||||||
|
|
||||||
Open your settings file (``mysite/settings.py``, remember) and look at the
|
.. _ref-customizing-your-projects-templates:
|
||||||
:setting:`TEMPLATE_DIRS` setting. :setting:`TEMPLATE_DIRS` is a tuple of
|
|
||||||
filesystem directories to check when loading Django templates. It's a search
|
Customizing your *project's* templates
|
||||||
path.
|
--------------------------------------
|
||||||
|
|
||||||
Create a ``mytemplates`` directory in your project directory. Templates can
|
Create a ``mytemplates`` directory in your project directory. Templates can
|
||||||
live anywhere on your filesystem that Django can access. (Django runs as
|
live anywhere on your filesystem that Django can access. (Django runs as
|
||||||
|
@ -489,11 +489,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
|
copy it from the default directory into your custom directory, and make
|
||||||
changes.
|
changes.
|
||||||
|
|
||||||
|
Customizing your *application's* templates
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
Astute readers will ask: But if :setting:`TEMPLATE_DIRS` was empty by default,
|
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
|
how was Django finding the default admin templates? The answer is that, by
|
||||||
default, Django automatically looks for a ``templates/`` subdirectory within
|
default, Django automatically looks for a ``templates/`` subdirectory within
|
||||||
each app package, for use as a fallback. See the :ref:`template loader
|
each application package, for use as a fallback (don't forget that
|
||||||
documentation <template-loaders>` for full information.
|
``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
|
Customize the admin index page
|
||||||
==============================
|
==============================
|
||||||
|
|
|
@ -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
|
* Vote action -- handles voting for a particular choice in a particular
|
||||||
poll.
|
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
|
Write your first view
|
||||||
=====================
|
=====================
|
||||||
|
@ -52,19 +69,8 @@ and put the following Python code in it::
|
||||||
def index(request):
|
def index(request):
|
||||||
return HttpResponse("Hello, world. You're at the poll index.")
|
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 is the simplest view possible in Django. To call the view, we need to map
|
||||||
this view get called? For that we need to map it to a URL, in Django this is
|
it to a URL - and for this we need a URLconf.
|
||||||
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.
|
|
||||||
|
|
||||||
To create a URLconf in the polls directory, create a file called ``urls.py``.
|
To create a URLconf in the polls directory, create a file called ``urls.py``.
|
||||||
Your app directory should now look like::
|
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
|
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.
|
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:
|
Put the following code in that template:
|
||||||
|
|
||||||
.. code-block:: html+django
|
.. 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
|
context. The context is a dictionary mapping template variable names to Python
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
Load the page in your Web browser, and you should see a bulleted-list
|
Load the page by pointing your browser at "/polls/", and you should see a
|
||||||
containing the "What's up" poll from Tutorial 1. The link points to the poll's
|
bulleted-list containing the "What's up" poll from Tutorial 1. The link points
|
||||||
detail page.
|
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>`.
|
|
||||||
|
|
||||||
A shortcut: :func:`~django.shortcuts.render`
|
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
|
make it so that Django knows which app view to create for a url when using the
|
||||||
``{% url %}`` template tag?
|
``{% url %}`` template tag?
|
||||||
|
|
||||||
The answer is to add namespaces to your root URLconf. In the
|
The answer is to add namespaces to your root URLconf. In the ``mysite/urls.py``
|
||||||
``mysite/urls.py`` file, go ahead and change it to include namespacing::
|
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
|
from django.conf.urls import patterns, include, url
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ A quick rundown:
|
||||||
``value`` of each radio button is the associated poll choice's ID. 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
|
``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
|
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
|
* We set the form's ``action`` to ``{% url 'polls:vote' poll.id %}``, and we
|
||||||
set ``method="post"``. Using ``method="post"`` (as opposed to
|
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.
|
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::
|
First, open the ``polls/urls.py`` URLconf and change it like so::
|
||||||
|
|
||||||
from django.conf.urls import patterns, url
|
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'),
|
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Amend views
|
||||||
|
-----------
|
||||||
|
|
||||||
We're using two generic views here:
|
We're using two generic views here:
|
||||||
:class:`~django.views.generic.list.ListView` and
|
:class:`~django.views.generic.list.ListView` and
|
||||||
:class:`~django.views.generic.detail.DetailView`. Respectively, those
|
: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
|
the new default context variables -- but it's a lot easier to just
|
||||||
tell Django to use the variable you want.
|
tell Django to use the variable you want.
|
||||||
|
|
||||||
You can now delete the ``index()``, ``detail()`` and ``results()``
|
You can now delete the ``index()``, ``detail()`` and ``results()`` views from
|
||||||
views from ``polls/views.py``. We don't need them anymore -- they have
|
``polls/views.py``. We don't need them anymore -- they have been replaced by
|
||||||
been replaced by generic views.
|
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.
|
Run the server, and use your new polling app based on generic views.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue