Changed overview and tutorial docs to use render_to_response and get_object_or_404, to cut down on code
git-svn-id: http://code.djangoproject.com/svn/django/trunk@678 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
3dcdce4d63
commit
b7528320b6
|
@ -195,20 +195,10 @@ Generally, a view retrieves data according to the parameters, loads a template
|
|||
and renders the template with the retrieved data. Here's an example view for
|
||||
article_detail from above::
|
||||
|
||||
from django.models.news import articles
|
||||
|
||||
def article_detail(request, year, month, article_id):
|
||||
# Use the Django API to find an object matching the URL criteria.
|
||||
try:
|
||||
a = articles.get_object(pub_date__year=year, pub_date__month=month, pk=article_id)
|
||||
except articles.ArticleDoesNotExist:
|
||||
raise Http404
|
||||
t = template_loader.get_template('news/article_detail')
|
||||
c = Context(request, {
|
||||
'article': a,
|
||||
})
|
||||
content = t.render(c)
|
||||
return HttpResponse(content)
|
||||
a = get_object_or_404(articles, pub_date__year=year, pub_date__month=month, pk=article_id)
|
||||
return render_to_response('news/article_detail', {'article': a})
|
||||
|
||||
This example uses Django's template system, which has several key features.
|
||||
|
||||
|
@ -261,7 +251,6 @@ template has to define only what's unique to that template.
|
|||
|
||||
Here's what the "base" template might look like::
|
||||
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
|
|
|
@ -192,14 +192,14 @@ 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::
|
||||
|
||||
from django.core import template_loader
|
||||
from django.core.extensions import DjangoContext as Context
|
||||
from django.core.template import Context
|
||||
from django.models.polls import polls
|
||||
from django.utils.httpwrappers import HttpResponse
|
||||
|
||||
def index(request):
|
||||
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
||||
t = template_loader.get_template('polls/index')
|
||||
c = Context(request, {
|
||||
c = Context({
|
||||
'latest_poll_list': latest_poll_list,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
|
@ -242,6 +242,27 @@ Put the following code in that template::
|
|||
Load the page in your Web browser, and you should see a bulleted-list
|
||||
containing the "What's up" poll from Tutorial 1.
|
||||
|
||||
A shortcut: render_to_response()
|
||||
--------------------------------
|
||||
|
||||
It's a very common idiom to load a template, fill a context and return an
|
||||
``HttpResponse`` object with the result of the rendered template. Django
|
||||
provides a shortcut. Here's the full ``index()`` view, rewritten::
|
||||
|
||||
from django.core.extensions import render_to_response
|
||||
from django.models.polls import polls
|
||||
|
||||
def index(request):
|
||||
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
|
||||
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
|
||||
|
||||
Note that we no longer need to import ``template_loader``, ``Context`` or
|
||||
``HttpResponse``.
|
||||
|
||||
The ``render_to_response()`` function takes a template name as its first
|
||||
argument and a dictionary as its optional second argument. It returns an
|
||||
``HttpResponse`` object of the given template rendered with the given context.
|
||||
|
||||
Raising 404
|
||||
===========
|
||||
|
||||
|
@ -254,15 +275,41 @@ for a given poll. Here's the view::
|
|||
p = polls.get_object(pk=poll_id)
|
||||
except polls.PollDoesNotExist:
|
||||
raise Http404
|
||||
t = template_loader.get_template('polls/detail')
|
||||
c = Context(request, {
|
||||
'poll': p,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
return render_to_response('polls/detail', {'poll': p})
|
||||
|
||||
The new concept here: The view raises the ``django.core.exceptions.Http404``
|
||||
exception if a poll with the requested ID doesn't exist.
|
||||
|
||||
A shortcut: get_object_or_404()
|
||||
-------------------------------
|
||||
|
||||
It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the
|
||||
object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view,
|
||||
rewritten:
|
||||
|
||||
from django.core.extensions import get_object_or_404
|
||||
def detail(request, poll_id):
|
||||
p = get_object_or_404(polls, pk=poll_id)
|
||||
return render_to_response('polls/detail', {'poll': p})
|
||||
|
||||
The ``get_object_or_404()`` function takes a Django model module as its first
|
||||
argument and an arbitrary number of keyword arguments, which it passes to the
|
||||
module's ``get_object()`` function. It raises ``Http404`` if the object doesn't
|
||||
exist.
|
||||
|
||||
.. admonition:: Philosophy
|
||||
|
||||
Why do we use a helper function ``get_object_or_404()`` instead of
|
||||
automatically catching the ``*DoesNotExist`` exceptions at a higher level,
|
||||
or having the model API raise ``Http404`` instead of ``*DoesNotExist``?
|
||||
|
||||
Because that would couple the model layer to the view layer. One of the
|
||||
foremost design goals of Django is to maintain loose coupling.
|
||||
|
||||
There's also a ``get_list_or_404()`` function, which works just as
|
||||
``get_object_or_404()`` -- except using ``get_list()`` instead of
|
||||
``get_object()``. It raises ``Http404`` if the list is empty.
|
||||
|
||||
Write a 404 (page not found) view
|
||||
=================================
|
||||
|
||||
|
|
|
@ -48,27 +48,20 @@ included this line::
|
|||
|
||||
So let's create a ``vote()`` function in ``myproject/apps/polls/views/polls.py``::
|
||||
|
||||
from django.core import template_loader
|
||||
from django.core.extensions import DjangoContext as Context
|
||||
from django.core.extensions import get_object_or_404, render_to_response
|
||||
from django.models.polls import choices, polls
|
||||
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||
from django.core.exceptions import Http404
|
||||
from django.utils.httpwrappers import HttpResponseRedirect
|
||||
|
||||
def vote(request, poll_id):
|
||||
try:
|
||||
p = polls.get_object(pk=poll_id)
|
||||
except polls.PollDoesNotExist:
|
||||
raise Http404
|
||||
p = get_object_or_404(polls, pk=poll_id)
|
||||
try:
|
||||
selected_choice = p.get_choice(pk=request.POST['choice'])
|
||||
except (KeyError, choices.ChoiceDoesNotExist):
|
||||
# Redisplay the poll voting form.
|
||||
t = template_loader.get_template('polls/detail')
|
||||
c = Context(request, {
|
||||
return render_to_response('polls/detail', {
|
||||
'poll': p,
|
||||
'error_message': "You didn't select a choice.",
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
else:
|
||||
selected_choice.votes += 1
|
||||
selected_choice.save()
|
||||
|
@ -109,15 +102,8 @@ 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):
|
||||
try:
|
||||
p = polls.get_object(pk=poll_id)
|
||||
except polls.PollDoesNotExist:
|
||||
raise Http404
|
||||
t = template_loader.get_template('polls/results')
|
||||
c = Context(request, {
|
||||
'poll': p,
|
||||
})
|
||||
return HttpResponse(t.render(c))
|
||||
p = get_object_or_404(polls, pk=poll_id)
|
||||
return render_to_response('polls/results', {'poll': p})
|
||||
|
||||
This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_.
|
||||
The only difference is the template name. We'll fix this redundancy later.
|
||||
|
|
Loading…
Reference in New Issue