Kaydet (Commit) 07abb7a6 authored tarafından Tim Graham's avatar Tim Graham

Fixed #18715 - Refactored tutorial 3. Thank-you Daniel Greenfeld!

üst 08286ca5
......@@ -440,20 +440,30 @@ Open your settings file (``mysite/settings.py``, remember) and look at the
filesystem directories to check when loading Django templates. It's a search
path.
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
project is a good convention to follow.
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.
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.
'/path/to/mysite/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
your :setting:`TEMPLATE_DIRS` includes ``'/path/to/mysite/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
``/path/to/mysite/mytemplates/admin/base_site.html``. Don't forget that
``admin`` subdirectory.
.. admonition:: Where are the Django source files?
......
This diff is collapsed.
......@@ -18,7 +18,7 @@ tutorial, so that the template contains an HTML ``<form>`` element:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls.views.vote' poll.id %}" method="post">
<form action="{% url 'polls:vote' poll.id %}" method="post">
{% csrf_token %}
{% for choice in poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
......@@ -35,7 +35,7 @@ A quick rundown:
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 ``{% url 'polls.views.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
``method="get"``) is very important, because the act of submitting this
form will alter data server-side. Whenever you create a form that alters
......@@ -52,34 +52,18 @@ A quick rundown:
forms that are targeted at internal URLs should use the
:ttag:`{% csrf_token %}<csrf_token>` template tag.
The :ttag:`{% csrf_token %}<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'),
url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='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.shortcuts import get_object_or_404, render
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):
......@@ -88,17 +72,17 @@ create a real version. Add the following to ``polls/views.py``::
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', {
return render(request, '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,)))
return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
This code includes a few things we haven't covered yet in this tutorial:
......@@ -142,8 +126,7 @@ This code includes a few things we haven't covered yet in this tutorial:
'/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).
then call the ``'results'`` view to display the final page.
As mentioned in Tutorial 3, ``request`` is a :class:`~django.http.HttpRequest`
object. For more on :class:`~django.http.HttpRequest` objects, see the
......@@ -153,14 +136,14 @@ 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})
poll = get_object_or_404(Poll, pk=poll_id)
return render(request, 'polls/results.html', {'poll': poll})
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:
Now, create a ``polls/results.html`` template:
.. code-block:: html+django
......@@ -172,7 +155,7 @@ Now, create a ``results.html`` template:
{% endfor %}
</ul>
<a href="{% url 'polls.views.detail' poll.id %}">Vote again?</a>
<a href="{% url 'polls:detail' 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
......@@ -215,19 +198,7 @@ Read on for details.
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 import patterns, url
urlpatterns = patterns('polls.views',
url(r'^$', 'index'),
url(r'^(?P<poll_id>\d+)/$', 'detail'),
url(r'^(?P<poll_id>\d+)/results/$', 'results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)
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.views.generic import DetailView, ListView
......@@ -239,18 +210,18 @@ Change it like so::
queryset=Poll.objects.order_by('-pub_date')[:5],
context_object_name='latest_poll_list',
template_name='polls/index.html'),
name='poll_index'),
name='index'),
url(r'^(?P<pk>\d+)/$',
DetailView.as_view(
model=Poll,
template_name='polls/detail.html'),
name='poll_detail'),
name='detail'),
url(r'^(?P<pk>\d+)/results/$',
DetailView.as_view(
model=Poll,
template_name='polls/results.html'),
name='poll_results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
name='results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'),
)
We're using two generic views here:
......@@ -267,15 +238,6 @@ two views abstract the concepts of "display a list of objects" and
``"pk"``, so we've changed ``poll_id`` to ``pk`` for the generic
views.
* We've added the ``name`` argument to the views (e.g. ``name='poll_results'``)
so that we have a way to refer to their 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.url` function from
:mod:`django.conf.urls` here. It's a good habit to use
:func:`~django.conf.urls.url` when you are providing a
pattern name like this.
By default, the :class:`~django.views.generic.list.DetailView` generic
view uses a template called ``<app name>/<model name>_detail.html``.
In our case, it'll use the template ``"polls/poll_detail.html"``. The
......@@ -308,41 +270,13 @@ 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 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,)))
The same rule apply for the :ttag:`url` template tag. For example in the
``results.html`` template:
.. code-block:: html+django
<a href="{% url 'poll_detail' poll.id %}">Vote again?</a>
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/class-based-views/index>`.
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
What's next?
============
In the meantime, you might want to check out some pointers on :doc:`where to go
from here </intro/whatsnext>`
The tutorial ends here for the time being. In the meantime, you might want to
check out some pointers on :doc:`where to go from here </intro/whatsnext>`.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment