Ticket #18715: 18715.patch

File 18715.patch, 31.0 KB (added by Aymeric Augustin, 12 years ago)
  • docs/intro/tutorial03.txt

    diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt
    index d15b2f4..d329f80 100644
    a b Philosophy  
    1010==========
    1111
    1212A view is a "type" of Web page in your Django application that generally serves
    13 a specific function and has a specific template. For example, in a Weblog
     13a specific function and has a specific template. For example, in a blog
    1414application, you might have the following views:
    1515
    1616* Blog homepage -- displays the latest few entries.
    In our poll application, we'll have the following four views:  
    4141
    4242In Django, each view is represented by a simple Python function.
    4343
    44 Design your URLs
    45 ================
     44Write your first view
     45=====================
    4646
    47 The first step of writing views is to design your URL structure. You do this by
    48 creating a Python module, called a URLconf. URLconfs are how Django associates
    49 a given URL with given Python code.
     47Let's write the first view. Open the file ``polls/views.py``
     48and put the following Python code in it::
    5049
    51 When a user requests a Django-powered page, the system looks at the
    52 :setting:`ROOT_URLCONF` setting, which contains a string in Python dotted
    53 syntax. Django loads that module and looks for a module-level variable called
    54 ``urlpatterns``, which is a sequence of tuples in the following format::
     50    from django.http import HttpResponse
    5551
    56     (regular expression, Python callback function [, optional dictionary])
     52    def index(request):
     53        return HttpResponse("Hello, world. You're at the poll index.")
    5754
    58 Django starts at the first regular expression and makes its way down the list,
    59 comparing the requested URL against each regular expression until it finds one
    60 that matches.
     55This is the simplest view possible in Django. Now we have a problem, how does
     56this view get called? For that we need to map it to a URL, in Django this is
     57done in a configuration file called a URLconf. To create a URLconf in the
     58polls directory create a file called ``urls.py``. Your app directory should
     59now look like::
    6160
    62 When it finds a match, Django calls the Python callback function, with an
    63 :class:`~django.http.HttpRequest` object as the first argument, any "captured"
    64 values from the regular expression as keyword arguments, and, optionally,
    65 arbitrary keyword arguments from the dictionary (an optional third item in the
    66 tuple).
     61    polls/
     62        __init__.py
     63        admin.py
     64        models.py
     65        tests.py
     66        urls.py
     67        views.py
    6768
    68 For more on :class:`~django.http.HttpRequest` objects, see the
    69 :doc:`/ref/request-response`. For more details on URLconfs, see the
    70 :doc:`/topics/http/urls`.
     69In the ``polls/urls.py`` file include the following code::
    7170
    72 When you ran ``django-admin.py startproject mysite`` at the beginning of
    73 Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
    74 automatically set your :setting:`ROOT_URLCONF` setting (in ``settings.py``) to
    75 point at that file::
     71    from __future__ import absolute_import
    7672
    77     ROOT_URLCONF = 'mysite.urls'
     73    from django.conf.urls import patterns, url
    7874
    79 Time for an example. Edit ``mysite/urls.py`` so it looks like this::
     75    from . import views
     76
     77    urlpatterns = patterns('',
     78        url(regex=r'^$',
     79            view=views.index,
     80            kwargs={},
     81            name='index')
     82    )
     83
     84The next step is to point the root URLconf at the ``polls.urls`` module. In
     85``mysite/urls.py`` insert an :func:`~django.conf.urls.include`, leaving you
     86with::
    8087
    8188    from django.conf.urls import patterns, include, url
    8289
    Time for an example. Edit ``mysite/urls.py`` so it looks like this::  
    8491    admin.autodiscover()
    8592
    8693    urlpatterns = patterns('',
    87         url(r'^polls/$', 'polls.views.index'),
    88         url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
    89         url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
    90         url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
     94        url(r'^polls/', include('polls.urls')),
    9195        url(r'^admin/', include(admin.site.urls)),
    9296    )
    9397
    94 This is worth a review. When somebody requests a page from your Web site -- say,
    95 "/polls/23/", Django will load this Python module, because it's pointed to by
    96 the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
    97 and traverses the regular expressions in order. When it finds a regular
    98 expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
    99 function ``detail()`` from ``polls/views.py``. Finally, it calls that
    100 ``detail()`` function like so::
    101 
    102     detail(request=<HttpRequest object>, poll_id='23')
    103 
    104 The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses
    105 around a pattern "captures" the text matched by that pattern and sends it as an
    106 argument to the view function; the ``?P<poll_id>`` defines the name that will be
    107 used to identify the matched pattern; and ``\d+`` is a regular expression to
    108 match a sequence of digits (i.e., a number).
     98You have now wired an `index` view into the URLconf. Go to
     99http://localhost:8000/polls/ in your browser, and you should see the text
     100"*Hello, world. You're at the poll index.*", which you defined in the
     101``index`` view.
    109102
    110 Because the URL patterns are regular expressions, there really is no limit on
    111 what you can do with them. And there's no need to add URL cruft such as ``.php``
    112 -- unless you have a sick sense of humor, in which case you can do something
    113 like this::
     103The :func:`~django.conf.urls.url` function is being passed four arguments:
     104``regex``, ``view``, ``kwargs``, and ``name``. At this point, it's worth
     105reviewing what these arguments are for.
    114106
    115     (r'^polls/latest\.php$', 'polls.views.index'),
     107:func:`~django.conf.urls.url` argument: regex
     108---------------------------------------------
    116109
    117 But, don't do that. It's silly.
     110The term `regex` is a commonly used short form meaning `regular expression`,
     111which is a syntax for matching patterns in strings, or in this case, url
     112patterns. Django starts at the first regular expression and makes its way down
     113the list,  comparing the requested URL against each regular expression until it
     114finds one that matches.
    118115
    119116Note that these regular expressions do not search GET and POST parameters, or
    120 the domain name. For example, in a request to ``http://www.example.com/myapp/``,
    121 the URLconf will look for ``myapp/``. In a request to
    122 ``http://www.example.com/myapp/?page=3``, the URLconf will look for ``myapp/``.
     117the domain name. For example, in a request to
     118``http://www.example.com/myapp/``, the URLconf will look for ``myapp/``. In a
     119request to ``http://www.example.com/myapp/?page=3``, the URLconf will also
     120look for ``myapp/``.
    123121
    124122If you need help with regular expressions, see `Wikipedia's entry`_ and the
    125123documentation of the :mod:`re` module. Also, the O'Reilly book "Mastering
    time the URLconf module is loaded. They're super fast.  
    130128
    131129.. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression
    132130
    133 Write your first view
    134 =====================
    135 
    136 Well, we haven't created any views yet -- we just have the URLconf. But let's
    137 make sure Django is following the URLconf properly.
    138 
    139 Fire up the Django development Web server:
     131:func:`~django.conf.urls.url` argument: view
     132--------------------------------------------
    140133
    141 .. code-block:: bash
     134When Django finds a regular expression match, Django calls the specified view
     135function, with an HttpRequest object as the first argument, any “captured”
     136values from the regular expression as other arguments. If the regex uses
     137simple captures, values are passed as positional arguments; if it uses named
     138captures, values are passed as keyword arguments.
    142139
    143     python manage.py runserver
     140Using the example below, calling ``/polls/12/`` will match the ``detail`` view
     141and pass a keyword argument of ``poll_id='12'`` to the view.
    144142
    145 Now go to "http://localhost:8000/polls/" on your domain in your Web browser.
    146 You should get a pleasantly-colored error page with the following message::
     143:func:`~django.conf.urls.url` argument: kwargs
     144----------------------------------------------
    147145
    148     ViewDoesNotExist at /polls/
     146Arbitrary keyword arguments can be passed in a dictionary to the target view. We
     147aren't going to use this feature of Django in the tutorial.
    149148
    150     Could not import polls.views.index. View does not exist in module polls.views.
     149:func:`~django.conf.urls.url` argument: name
     150---------------------------------------------
    151151
    152 This error happened because you haven't written a function ``index()`` in the
    153 module ``polls/views.py``.
     152Naming your URL lets you refer to it unambiguously from elsewhere in Django
     153especially templates. This powerful feature allows you to make  global changes
     154to the url patterns of your project while only touching a single file.
    154155
    155 Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error
    156 messages tell you which view Django tried (and failed to find, because you
    157 haven't written any views yet).
     156.. admonition:: What is a URLconf?
    158157
    159 Time to write the first view. Open the file ``polls/views.py``
    160 and put the following Python code in it::
    161 
    162     from django.http import HttpResponse
    163 
    164     def index(request):
    165         return HttpResponse("Hello, world. You're at the poll index.")
     158    In Django, web pages and other content are delivered by views and
     159    determining which view is called is done by Python modules informally
     160    titled 'URLconfs'. These modules are pure Python code and are a simple
     161    mapping between URL patterns (as simple regular expressions) to Python
     162    callback functions (your views). This tutorial provides basic instruction
     163    in their use, and you can refer to :mod:`django.core.urlresolvers` for
     164    more information.
    166165
    167 This is the simplest view possible. Go to "/polls/" in your browser, and you
    168 should see your text.
     166Writing more views
     167==================
    169168
    170 Now lets add a few more views. These views are slightly different, because
    171 they take an argument (which, remember, is passed in from whatever was
    172 captured by the regular expression in the URLconf)::
     169Now let's add a few more views. These views are slightly different, because
     170they take an argument::
    173171
    174172    def detail(request, poll_id):
    175173        return HttpResponse("You're looking at poll %s." % poll_id)
    captured by the regular expression in the URLconf)::  
    180178    def vote(request, poll_id):
    181179        return HttpResponse("You're voting on poll %s." % poll_id)
    182180
    183 Take a look in your browser, at "/polls/34/". It'll run the `detail()` method
    184 and display whatever ID you provide in the URL. Try "/polls/34/results/" and
    185 "/polls/34/vote/" too -- these will display the placeholder results and voting
    186 pages.
     181Wire these news views into the ``polls.urls`` module by adding the following
     182:func:`~django.conf.urls.url` calls::
     183
     184    from __future__ import absolute_import
     185
     186    from django.conf.urls import patterns, url
     187
     188    from . import views
     189
     190    urlpatterns = patterns('',
     191        url(regex=r'^$',  # ex: /polls/
     192            view=views.index,
     193            kwargs={},
     194            name='index'),
     195
     196        # call the detail view
     197        url(regex=r'^(?P<poll_id>\d+)/$',  # ex: /polls/5/
     198            view=views.detail,
     199            kwargs={},
     200            name='detail'),
     201
     202        # call the results view
     203        url(regex=r'^(?P<poll_id>\d+)/results/$',  # ex: /polls/5/results/
     204            view=views.results,
     205            kwargs={},
     206            name='results'),
     207
     208        # call the vote view
     209        url(regex=r'^(?P<poll_id>\d+)/vote/$',  # ex: /polls/5/vote/
     210            view=views.vote,
     211            kwargs={},
     212            name='vote')
     213    )
     214
     215Take a look in your browser, at "/polls/34/". It'll run the ``detail()``
     216method and display whatever ID you provide in the URL. Try
     217"/polls/34/results/" and "/polls/34/vote/" too -- these will display the
     218placeholder results and voting pages.
     219
     220When somebody requests a page from your Web site -- say, "/polls/23/", Django
     221will load this Python module, because it's pointed to by the
     222:setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
     223and traverses the regular expressions in order. When it finds a regular
     224expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it calls the
     225function ``detail()`` like so::
     226
     227    detail(request=<HttpRequest object>, poll_id='23')
     228
     229The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses
     230around a pattern "captures" the text matched by that pattern and sends it as an
     231argument to the view function; the ``?P<poll_id>`` defines the name that will be
     232used to identify the matched pattern; and ``\d+`` is a regular expression to
     233match a sequence of digits (i.e., a number).
     234
     235Because the URL patterns are regular expressions, there really is no limit on
     236what you can do with them. And there's no need to add URL cruft such as ``.php``
     237-- unless you have a sick sense of humor, in which case you can do something
     238like this::
     239
     240    (r'^polls/latest\.php$', 'polls.views.index'),
     241
     242But, don't do that. It's silly.
    187243
    188244Write views that actually do something
    189245======================================
    190246
    191 Each view is responsible for doing one of two things: Returning an
     247Each view is responsible for doing one of two things: returning an
    192248:class:`~django.http.HttpResponse` object containing the content for the
    193249requested page, or raising an exception such as :exc:`~django.http.Http404`. The
    194250rest is up to you.
    in :doc:`Tutorial 1 </intro/tutorial01>`. Here's one stab at the ``index()``  
    205261view, which displays the latest 5 poll questions in the system, separated by
    206262commas, according to publication date::
    207263
    208     from polls.models import Poll
     264    from __future__ import absolute_import
     265
    209266    from django.http import HttpResponse
    210267
     268    from .models import Poll
     269
    211270    def index(request):
    212         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
     271        latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
    213272        output = ', '.join([p.question for p in latest_poll_list])
    214273        return HttpResponse(output)
    215274
    216 There's a problem here, though: The page's design is hard-coded in the view. If
     275There's a problem here, though: the page's design is hard-coded in the view. If
    217276you want to change the way the page looks, you'll have to edit this Python code.
    218 So let's use Django's template system to separate the design from Python::
    219 
    220     from django.template import Context, loader
    221     from polls.models import Poll
    222     from django.http import HttpResponse
    223 
    224     def index(request):
    225         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    226         t = loader.get_template('polls/index.html')
    227         c = Context({
    228             'latest_poll_list': latest_poll_list,
    229         })
    230         return HttpResponse(t.render(c))
    231 
    232 That code loads the template called "polls/index.html" and passes it a context.
    233 The context is a dictionary mapping template variable names to Python objects.
    234 
    235 Reload the page. Now you'll see an error::
     277So let's use Django's template system to separate the design from Python.
    236278
    237     TemplateDoesNotExist at /polls/
    238     polls/index.html
     279First, create a directory, somewhere on your filesystem, whose contents Django
     280can access. (Django runs as whatever user your server runs.) Don't put them
     281under your document root, though. You probably shouldn't make them public, just
     282for security's sake. Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py``
     283to tell Django where it can find templates -- just as you did in the "Customize
     284the admin look and feel" section of Tutorial 2.
    239285
    240 Ah. There's no template yet. First, create a directory, somewhere on your
    241 filesystem, whose contents Django can access. (Django runs as whatever user your
    242 server runs.) Don't put them under your document root, though. You probably
    243 shouldn't make them public, just for security's sake.
    244 Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py`` to tell Django where
    245 it can find templates -- just as you did in the "Customize the admin look and
    246 feel" section of Tutorial 2.
    247 
    248 When you've done that, create a directory ``polls`` in your template directory.
    249 Within that, create a file called ``index.html``. Note that our
    250 ``loader.get_template('polls/index.html')`` code from above maps to
    251 "[template_directory]/polls/index.html" on the filesystem.
    252 
    253 Put the following code in that template:
     286When you've done that, create a directory ``polls`` in your template
     287directory. Within that, create a file called ``index.html``. Put the following
     288code in that template:
    254289
    255290.. code-block:: html+django
    256291
    Put the following code in that template:  
    264299        <p>No polls are available.</p>
    265300    {% endif %}
    266301
     302Now let's use that html template in an index view::
     303
     304    from __future__ import absolute_import
     305
     306    from django.http import HttpResponse
     307    from django.template import Context, loader
     308
     309    from .models import Poll
     310
     311    def index(request):
     312        latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
     313        template = loader.get_template('polls/index.html')
     314        context = Context({
     315            'latest_poll_list': latest_poll_list,
     316        })
     317        return HttpResponse(template.render(context))
     318
     319That code loads the template called  ``polls/index.html`` and passes it a
     320context. The context is a dictionary mapping template variable names to Python
     321objects.
     322
    267323Load the page in your Web browser, and you should see a bulleted-list
    268324containing the "What's up" poll from Tutorial 1. The link points to the poll's
    269325detail page.
    270326
    271 A shortcut: render_to_response()
    272 --------------------------------
     327A shortcut: :func:`~django.shortcuts.render`
     328--------------------------------------------
    273329
    274330It's a very common idiom to load a template, fill a context and return an
    275331:class:`~django.http.HttpResponse` object with the result of the rendered
    276332template. Django provides a shortcut. Here's the full ``index()`` view,
    277333rewritten::
    278334
    279     from django.shortcuts import render_to_response
    280     from polls.models import Poll
     335    from __future__ import absolute_import
     336
     337    from django.shortcuts import render
     338
     339    from .models import Poll
    281340
    282341    def index(request):
    283342        latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    284         return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
     343        context = {'latest_poll_list': latest_poll_list}
     344        return render(request, 'polls/index.html', context)
    285345
    286346Note that once we've done this in all these views, we no longer need to import
    287347:mod:`~django.template.loader`, :class:`~django.template.Context` and
    288348:class:`~django.http.HttpResponse`.
    289349
    290 The :func:`~django.shortcuts.render_to_response` function takes a template name
    291 as its first argument and a dictionary as its optional second argument. It
    292 returns an :class:`~django.http.HttpResponse` object of the given template
    293 rendered with the given context.
     350The :func:`~django.shortcuts.render` function takes the request object as its
     351first argument, a template name as its second argument and a dictionary as its
     352optional third argument. It returns an :class:`~django.http.HttpResponse`
     353object of the given template rendered with the given context.
    294354
    295 Raising 404
    296 ===========
     355Raising a 404 error
     356===================
    297357
    298358Now, let's tackle the poll detail view -- the page that displays the question
    299359for a given poll. Here's the view::
    for a given poll. Here's the view::  
    302362    # ...
    303363    def detail(request, poll_id):
    304364        try:
    305             p = Poll.objects.get(pk=poll_id)
     365            poll = Poll.objects.get(pk=poll_id)
    306366        except Poll.DoesNotExist:
    307367            raise Http404
    308         return render_to_response('polls/detail.html', {'poll': p})
     368        return render(request, 'polls/detail.html', {'poll': poll})
    309369
    310370The new concept here: The view raises the :exc:`~django.http.Http404` exception
    311371if a poll with the requested ID doesn't exist.
    later, but if you'd like to quickly get the above example working, just::  
    317377
    318378will get you started for now.
    319379
    320 A shortcut: get_object_or_404()
    321 -------------------------------
     380A shortcut: :func:`~django.shortcuts.get_object_or_404`
     381-------------------------------------------------------
    322382
    323383It's a very common idiom to use :meth:`~django.db.models.query.QuerySet.get`
    324384and raise :exc:`~django.http.Http404` if the object doesn't exist. Django
    325385provides a shortcut. Here's the ``detail()`` view, rewritten::
    326386
    327     from django.shortcuts import render_to_response, get_object_or_404
     387    from django.shortcuts import render, get_object_or_404
    328388    # ...
    329389    def detail(request, poll_id):
    330         p = get_object_or_404(Poll, pk=poll_id)
    331         return render_to_response('polls/detail.html', {'poll': p})
     390        poll = get_object_or_404(Poll, pk=poll_id)
     391        return render(request, 'polls/detail.html', {'poll': poll})
    332392
    333393The :func:`~django.shortcuts.get_object_or_404` function takes a Django model
    334394as its first argument and an arbitrary number of keyword arguments, which it
    exist.  
    345405    :exc:`~django.core.exceptions.ObjectDoesNotExist`?
    346406
    347407    Because that would couple the model layer to the view layer. One of the
    348     foremost design goals of Django is to maintain loose coupling.
     408    foremost design goals of Django is to maintain loose coupling. Some
     409    controlled coupling is introduced in the :mod:`django.shortcuts` module.
    349410
    350411There's also a :func:`~django.shortcuts.get_list_or_404` function, which works
    351412just as :func:`~django.shortcuts.get_object_or_404` -- except using
    special: It's just a normal view.  
    367428You normally won't have to bother with writing 404 views. If you don't set
    368429``handler404``, the built-in view :func:`django.views.defaults.page_not_found`
    369430is used by default. In this case, you still have one obligation: create a
    370 ``404.html`` template in the root of your template directory. The default 404
     431``404.html`` template at the root of your template directory. The default 404
    371432view will use that template for all 404 errors. If :setting:`DEBUG` is set to
    372433``False`` (in your settings module) and if you didn't create a ``404.html``
    373434file, an ``Http500`` is raised instead. So remember to create a ``404.html``.
    Similarly, your root URLconf may define a ``handler500``, which points  
    388449to a view to call in case of server errors. Server errors happen when
    389450you have runtime errors in view code.
    390451
     452Likewise, you should create a ``500.html`` template at the root of your
     453template directory.
     454
    391455Use the template system
    392456=======================
    393457
    394458Back to the ``detail()`` view for our poll application. Given the context
    395 variable ``poll``, here's what the "polls/detail.html" template might look
     459variable ``poll``, here's what the ``polls/detail.html`` template might look
    396460like:
    397461
    398462.. code-block:: html+django
    Method-calling happens in the :ttag:`{% for %}<for>` loop:  
    415479``poll.choice_set.all()``, which returns an iterable of ``Choice`` objects and is
    416480suitable for use in the :ttag:`{% for %}<for>` tag.
    417481
    418 See the :doc:`template guide </topics/templates>` for more about templates.
    419 
    420 Simplifying the URLconfs
    421 ========================
    422 
    423 Take some time to play around with the views and template system. As you edit
    424 the URLconf, you may notice there's a fair bit of redundancy in it::
     482Removing hardcoded URLs in templates
     483====================================
    425484
    426     urlpatterns = patterns('',
    427         url(r'^polls/$', 'polls.views.index'),
    428         url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
    429         url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
    430         url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
    431     )
     485Remember, when we wrote the link to a poll in the polls/index.html template,
     486the link was partially hardcoded like this:
    432487
    433 Namely, ``polls.views`` is in every callback.
     488.. code-block:: html+django
    434489
    435 Because this is a common case, the URLconf framework provides a shortcut for
    436 common prefixes. You can factor out the common prefixes and add them as the
    437 first argument to :func:`~django.conf.urls.patterns`, like so::
     490    <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    438491
    439     urlpatterns = patterns('polls.views',
    440         url(r'^polls/$', 'index'),
    441         url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
    442         url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
    443         url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
    444     )
     492The problem with this hardcoded, tightly-coupled approach is that it becomes
     493challenging to change URLs on projects with a lot of templates. However, since
     494you defined the name argument in the :func:`~django.conf.urls.url` functions in
     495the ``polls.urls`` module, you can remove a reliance on specific URL paths
     496defined in your url configurations by using the ``{% url %}`` template tag:
    445497
    446 This is functionally identical to the previous formatting. It's just a bit
    447 tidier.
     498.. code-block:: html+django
    448499
    449 Since you generally don't want the prefix for one app to be applied to every
    450 callback in your URLconf, you can concatenate multiple
    451 :func:`~django.conf.urls.patterns`. Your full ``mysite/urls.py`` might
    452 now look like this::
     500    <li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
    453501
    454     from django.conf.urls import patterns, include, url
     502The way this works is by looking up the URL definition as specified in the
     503``polls.urls`` module. You can see exactly where the URL name of 'detail' is
     504defined below::
    455505
    456     from django.contrib import admin
    457     admin.autodiscover()
     506    ...
     507    # call the detail view
     508    url(regex=r'^(?P<poll_id>\d+)/$',
     509        view=views.detail,
     510        kwargs={},
     511        name='detail'), # the 'name' value as called by the {% url %} template tag
     512    ...
    458513
    459     urlpatterns = patterns('polls.views',
    460         url(r'^polls/$', 'index'),
    461         url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
    462         url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
    463         url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
    464     )
     514If you want to change the URL of the polls detail view to something else,
     515perhaps to something like ``polls/specifics/12/`` instead of doing it in the
     516template (or templates) you would change it in ``polls/urls.py``::
    465517
    466     urlpatterns += patterns('',
    467         url(r'^admin/', include(admin.site.urls)),
    468     )
     518    ...
     519    # call the detail view
     520    url(regex=r'^specifics/(?P<poll_id>\d+)/$', # added the word 'specifics'
     521        view=views.detail,
     522        kwargs={},
     523        name='detail'), # the 'name' value as called by the {% url %} template tag
     524    ...
    469525
    470 Decoupling the URLconfs
    471 =======================
     526See the :doc:`template guide </topics/templates>` for more about templates.
    472527
    473 While we're at it, we should take the time to decouple our poll-app URLs from
    474 our Django project configuration. Django apps are meant to be pluggable -- that
    475 is, each particular app should be transferable to another Django installation
    476 with minimal fuss.
    477528
    478 Our poll app is pretty decoupled at this point, thanks to the strict directory
    479 structure that ``python manage.py startapp`` created, but one part of it is
    480 coupled to the Django settings: The URLconf.
     529Namespacing URL names
     530======================
    481531
    482 We've been editing the URLs in ``mysite/urls.py``, but the URL design of an
    483 app is specific to the app, not to the Django installation -- so let's move the
    484 URLs within the app directory.
     532The tutorial project has just one app, ``polls``. In real Django projects, there
     533might be five, ten, twenty apps or more. How does Django differentiate the URL
     534names between them? For example, the ``polls`` app has a ``detail`` view, and so
     535might an app on the same project that is for a blog. How does one make it so
     536that Django knows which app view to create for a url when using the ``{% url %}``
     537template tag?
    485538
    486 Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change
    487 ``mysite/urls.py`` to remove the poll-specific URLs and insert an
    488 :func:`~django.conf.urls.include`, leaving you with::
     539The answer is to add namespaces to your root URLconf. In the
     540``mysite/urls.py`` file, go ahead and change it to include namespacing::
    489541
    490542    from django.conf.urls import patterns, include, url
    491543
    Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change  
    493545    admin.autodiscover()
    494546
    495547    urlpatterns = patterns('',
    496         url(r'^polls/', include('polls.urls')),
     548        url(r'^polls/', include('polls.urls', namespace="polls")),
    497549        url(r'^admin/', include(admin.site.urls)),
    498550    )
    499551
    500 :func:`~django.conf.urls.include` simply references another URLconf.
    501 Note that the regular expression doesn't have a ``$`` (end-of-string match
    502 character) but has the trailing slash. Whenever Django encounters
    503 :func:`~django.conf.urls.include`, it chops off whatever part of the
    504 URL matched up to that point and sends the remaining string to the included
    505 URLconf for further processing.
     552Now change your ``polls/index.html`` template from:
    506553
    507 Here's what happens if a user goes to "/polls/34/" in this system:
     554.. code-block:: html+django
    508555
    509 * Django will find the match at ``'^polls/'``
     556    <li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
    510557
    511 * Then, Django will strip off the matching text (``"polls/"``) and send the
    512   remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for
    513   further processing.
     558to point at the namespaced detail view:
    514559
    515 Now that we've decoupled that, we need to decouple the ``polls.urls``
    516 URLconf by removing the leading "polls/" from each line, and removing the
    517 lines registering the admin site. Your ``polls/urls.py`` file should now look like
    518 this::
     560.. code-block:: html+django
    519561
    520     from django.conf.urls import patterns, include, url
     562    <li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>
    521563
    522     urlpatterns = patterns('polls.views',
    523         url(r'^$', 'index'),
    524         url(r'^(?P<poll_id>\d+)/$', 'detail'),
    525         url(r'^(?P<poll_id>\d+)/results/$', 'results'),
    526         url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
    527     )
     564About the root URLconf
     565======================
     566
     567You've probably noticed by now that ``mysite/urls.py`` calls both the polls app
     568and the admin app. It's what is called the root URLconf.
     569
     570The :func:`~django.conf.urls.include` functions we are using  simply references
     571another URLconf. Note that the regular expression doesn't have a ``$``
     572(end-of-string match character) but has the trailing slash. Whenever Django
     573encounters :func:`~django.conf.urls.include`, it chops off whatever part of the
     574URL matched up to that point and sends the remaining string to the included
     575URLconf for further processing.
    528576
    529 The idea behind :func:`~django.conf.urls.include` and URLconf
    530 decoupling is to make it easy to plug-and-play URLs. Now that polls are in their
    531 own URLconf, they can be placed under "/polls/", or under "/fun_polls/", or
    532 under "/content/polls/", or any other path root, and the app will still work.
     577The idea behind :func:`~django.conf.urls.include` is to make it easy to
     578plug-and-play URLs. Since polls are in their own URLconf
     579(``polls/urls.py``), they can be placed under "/polls/", or under
     580"/fun_polls/", or under "/content/polls/", or any other path root, and the
     581app will still work.
    533582
    534583All the poll app cares about is its relative path, not its absolute path.
    535584
Back to Top