parent
43efefae69
commit
aa85ccf8ce
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
==============================
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue