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:
Adrian Holovaty 2005-09-23 22:50:05 +00:00
parent 3dcdce4d63
commit b7528320b6
3 changed files with 62 additions and 40 deletions

View File

@ -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 and renders the template with the retrieved data. Here's an example view for
article_detail from above:: article_detail from above::
from django.models.news import articles
def article_detail(request, year, month, article_id): def article_detail(request, year, month, article_id):
# Use the Django API to find an object matching the URL criteria. # Use the Django API to find an object matching the URL criteria.
try: a = get_object_or_404(articles, pub_date__year=year, pub_date__month=month, pk=article_id)
a = articles.get_object(pub_date__year=year, pub_date__month=month, pk=article_id) return render_to_response('news/article_detail', {'article': a})
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)
This example uses Django's template system, which has several key features. 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:: Here's what the "base" template might look like::
<html> <html>
<head> <head>
<title>{% block title %}{% endblock %}</title> <title>{% block title %}{% endblock %}</title>

View File

@ -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:: So let's use Django's template system to separate the design from Python::
from django.core import template_loader 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.models.polls import polls
from django.utils.httpwrappers import HttpResponse from django.utils.httpwrappers import HttpResponse
def index(request): def index(request):
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
t = template_loader.get_template('polls/index') t = template_loader.get_template('polls/index')
c = Context(request, { c = Context({
'latest_poll_list': latest_poll_list, 'latest_poll_list': latest_poll_list,
}) })
return HttpResponse(t.render(c)) 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 Load the page in your Web browser, and you should see a bulleted-list
containing the "What's up" poll from Tutorial 1. 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 Raising 404
=========== ===========
@ -254,15 +275,41 @@ for a given poll. Here's the view::
p = polls.get_object(pk=poll_id) p = polls.get_object(pk=poll_id)
except polls.PollDoesNotExist: except polls.PollDoesNotExist:
raise Http404 raise Http404
t = template_loader.get_template('polls/detail') return render_to_response('polls/detail', {'poll': p})
c = Context(request, {
'poll': p,
})
return HttpResponse(t.render(c))
The new concept here: The view raises the ``django.core.exceptions.Http404`` The new concept here: The view raises the ``django.core.exceptions.Http404``
exception if a poll with the requested ID doesn't exist. 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 Write a 404 (page not found) view
================================= =================================

View File

@ -48,27 +48,20 @@ included this line::
So let's create a ``vote()`` function in ``myproject/apps/polls/views/polls.py``:: 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 get_object_or_404, render_to_response
from django.core.extensions import DjangoContext as Context
from django.models.polls import choices, polls from django.models.polls import choices, polls
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect from django.utils.httpwrappers import HttpResponseRedirect
from django.core.exceptions import Http404
def vote(request, poll_id): def vote(request, poll_id):
try: p = get_object_or_404(polls, pk=poll_id)
p = polls.get_object(pk=poll_id)
except polls.PollDoesNotExist:
raise Http404
try: try:
selected_choice = p.get_choice(pk=request.POST['choice']) selected_choice = p.get_choice(pk=request.POST['choice'])
except (KeyError, choices.ChoiceDoesNotExist): except (KeyError, choices.ChoiceDoesNotExist):
# Redisplay the poll voting form. # Redisplay the poll voting form.
t = template_loader.get_template('polls/detail') return render_to_response('polls/detail', {
c = Context(request, {
'poll': p, 'poll': p,
'error_message': "You didn't select a choice.", 'error_message': "You didn't select a choice.",
}) })
return HttpResponse(t.render(c))
else: else:
selected_choice.votes += 1 selected_choice.votes += 1
selected_choice.save() 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:: page for the poll. Let's write that view::
def results(request, poll_id): def results(request, poll_id):
try: p = get_object_or_404(polls, pk=poll_id)
p = polls.get_object(pk=poll_id) return render_to_response('polls/results', {'poll': p})
except polls.PollDoesNotExist:
raise Http404
t = template_loader.get_template('polls/results')
c = Context(request, {
'poll': p,
})
return HttpResponse(t.render(c))
This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_. 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. The only difference is the template name. We'll fix this redundancy later.