summaryrefslogtreecommitdiff
path: root/docs/intro/tutorial04.txt
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2012-10-13 14:37:39 -0400
committerTim Graham <timograham@gmail.com>2012-10-15 19:47:26 -0400
commit07abb7a6b7af2c45be553acf08d85cd2d72057ad (patch)
tree742649553c7bb95e54cc0d6f7059d7c0fc8bcd58 /docs/intro/tutorial04.txt
parent08286ca5d93c142a60edda5ee37b3a8a7bc72274 (diff)
Fixed #18715 - Refactored tutorial 3. Thank-you Daniel Greenfeld!
Diffstat (limited to 'docs/intro/tutorial04.txt')
-rw-r--r--docs/intro/tutorial04.txt108
1 files changed, 21 insertions, 87 deletions
diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt
index 49e597ca29..8909caf98b 100644
--- a/docs/intro/tutorial04.txt
+++ b/docs/intro/tutorial04.txt
@@ -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>`.