Ticket #18715: 18715.patch
File 18715.patch, 31.0 KB (added by , 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 10 10 ========== 11 11 12 12 A 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 Weblog13 a specific function and has a specific template. For example, in a blog 14 14 application, you might have the following views: 15 15 16 16 * Blog homepage -- displays the latest few entries. … … In our poll application, we'll have the following four views: 41 41 42 42 In Django, each view is represented by a simple Python function. 43 43 44 Design your URLs 45 ================ 44 Write your first view 45 ===================== 46 46 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. 47 Let's write the first view. Open the file ``polls/views.py`` 48 and put the following Python code in it:: 50 49 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 55 51 56 (regular expression, Python callback function [, optional dictionary]) 52 def index(request): 53 return HttpResponse("Hello, world. You're at the poll index.") 57 54 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. 55 This is the simplest view possible in Django. Now we have a problem, how does 56 this view get called? For that we need to map it to a URL, in Django this is 57 done in a configuration file called a URLconf. To create a URLconf in the 58 polls directory create a file called ``urls.py``. Your app directory should 59 now look like:: 61 60 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 67 68 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`. 69 In the ``polls/urls.py`` file include the following code:: 71 70 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 76 72 77 ROOT_URLCONF = 'mysite.urls'73 from django.conf.urls import patterns, url 78 74 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 84 The 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 86 with:: 80 87 81 88 from django.conf.urls import patterns, include, url 82 89 … … Time for an example. Edit ``mysite/urls.py`` so it looks like this:: 84 91 admin.autodiscover() 85 92 86 93 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')), 91 95 url(r'^admin/', include(admin.site.urls)), 92 96 ) 93 97 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). 98 You have now wired an `index` view into the URLconf. Go to 99 http://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. 109 102 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:: 103 The :func:`~django.conf.urls.url` function is being passed four arguments: 104 ``regex``, ``view``, ``kwargs``, and ``name``. At this point, it's worth 105 reviewing what these arguments are for. 114 106 115 (r'^polls/latest\.php$', 'polls.views.index'), 107 :func:`~django.conf.urls.url` argument: regex 108 --------------------------------------------- 116 109 117 But, don't do that. It's silly. 110 The term `regex` is a commonly used short form meaning `regular expression`, 111 which is a syntax for matching patterns in strings, or in this case, url 112 patterns. Django starts at the first regular expression and makes its way down 113 the list, comparing the requested URL against each regular expression until it 114 finds one that matches. 118 115 119 116 Note 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/``. 117 the domain name. For example, in a request to 118 ``http://www.example.com/myapp/``, the URLconf will look for ``myapp/``. In a 119 request to ``http://www.example.com/myapp/?page=3``, the URLconf will also 120 look for ``myapp/``. 123 121 124 122 If you need help with regular expressions, see `Wikipedia's entry`_ and the 125 123 documentation of the :mod:`re` module. Also, the O'Reilly book "Mastering … … time the URLconf module is loaded. They're super fast. 130 128 131 129 .. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression 132 130 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 -------------------------------------------- 140 133 141 .. code-block:: bash 134 When Django finds a regular expression match, Django calls the specified view 135 function, with an HttpRequest object as the first argument, any “captured” 136 values from the regular expression as other arguments. If the regex uses 137 simple captures, values are passed as positional arguments; if it uses named 138 captures, values are passed as keyword arguments. 142 139 143 python manage.py runserver 140 Using the example below, calling ``/polls/12/`` will match the ``detail`` view 141 and pass a keyword argument of ``poll_id='12'`` to the view. 144 142 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 ---------------------------------------------- 147 145 148 ViewDoesNotExist at /polls/ 146 Arbitrary keyword arguments can be passed in a dictionary to the target view. We 147 aren't going to use this feature of Django in the tutorial. 149 148 150 Could not import polls.views.index. View does not exist in module polls.views. 149 :func:`~django.conf.urls.url` argument: name 150 --------------------------------------------- 151 151 152 This error happened because you haven't written a function ``index()`` in the 153 module ``polls/views.py``. 152 Naming your URL lets you refer to it unambiguously from elsewhere in Django 153 especially templates. This powerful feature allows you to make global changes 154 to the url patterns of your project while only touching a single file. 154 155 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? 158 157 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 HttpResponse163 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. 166 165 167 This is the simplest view possible. Go to "/polls/" in your browser, and you 168 should see your text. 166 Writing more views 167 ================== 169 168 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):: 169 Now let's add a few more views. These views are slightly different, because 170 they take an argument:: 173 171 174 172 def detail(request, poll_id): 175 173 return HttpResponse("You're looking at poll %s." % poll_id) … … captured by the regular expression in the URLconf):: 180 178 def vote(request, poll_id): 181 179 return HttpResponse("You're voting on poll %s." % poll_id) 182 180 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. 181 Wire 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 215 Take a look in your browser, at "/polls/34/". It'll run the ``detail()`` 216 method and display whatever ID you provide in the URL. Try 217 "/polls/34/results/" and "/polls/34/vote/" too -- these will display the 218 placeholder results and voting pages. 219 220 When somebody requests a page from your Web site -- say, "/polls/23/", Django 221 will load this Python module, because it's pointed to by the 222 :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns`` 223 and traverses the regular expressions in order. When it finds a regular 224 expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it calls the 225 function ``detail()`` like so:: 226 227 detail(request=<HttpRequest object>, poll_id='23') 228 229 The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parentheses 230 around a pattern "captures" the text matched by that pattern and sends it as an 231 argument to the view function; the ``?P<poll_id>`` defines the name that will be 232 used to identify the matched pattern; and ``\d+`` is a regular expression to 233 match a sequence of digits (i.e., a number). 234 235 Because the URL patterns are regular expressions, there really is no limit on 236 what 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 238 like this:: 239 240 (r'^polls/latest\.php$', 'polls.views.index'), 241 242 But, don't do that. It's silly. 187 243 188 244 Write views that actually do something 189 245 ====================================== 190 246 191 Each view is responsible for doing one of two things: Returning an247 Each view is responsible for doing one of two things: returning an 192 248 :class:`~django.http.HttpResponse` object containing the content for the 193 249 requested page, or raising an exception such as :exc:`~django.http.Http404`. The 194 250 rest is up to you. … … in :doc:`Tutorial 1 </intro/tutorial01>`. Here's one stab at the ``index()`` 205 261 view, which displays the latest 5 poll questions in the system, separated by 206 262 commas, according to publication date:: 207 263 208 from polls.models import Poll 264 from __future__ import absolute_import 265 209 266 from django.http import HttpResponse 210 267 268 from .models import Poll 269 211 270 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] 213 272 output = ', '.join([p.question for p in latest_poll_list]) 214 273 return HttpResponse(output) 215 274 216 There's a problem here, though: The page's design is hard-coded in the view. If275 There's a problem here, though: the page's design is hard-coded in the view. If 217 276 you 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:: 277 So let's use Django's template system to separate the design from Python. 236 278 237 TemplateDoesNotExist at /polls/ 238 polls/index.html 279 First, create a directory, somewhere on your filesystem, whose contents Django 280 can access. (Django runs as whatever user your server runs.) Don't put them 281 under your document root, though. You probably shouldn't make them public, just 282 for security's sake. Then edit :setting:`TEMPLATE_DIRS` in your ``settings.py`` 283 to tell Django where it can find templates -- just as you did in the "Customize 284 the admin look and feel" section of Tutorial 2. 239 285 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: 286 When you've done that, create a directory ``polls`` in your template 287 directory. Within that, create a file called ``index.html``. Put the following 288 code in that template: 254 289 255 290 .. code-block:: html+django 256 291 … … Put the following code in that template: 264 299 <p>No polls are available.</p> 265 300 {% endif %} 266 301 302 Now 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 319 That code loads the template called ``polls/index.html`` and passes it a 320 context. The context is a dictionary mapping template variable names to Python 321 objects. 322 267 323 Load the page in your Web browser, and you should see a bulleted-list 268 324 containing the "What's up" poll from Tutorial 1. The link points to the poll's 269 325 detail page. 270 326 271 A shortcut: render_to_response()272 -------------------------------- 327 A shortcut: :func:`~django.shortcuts.render` 328 -------------------------------------------- 273 329 274 330 It's a very common idiom to load a template, fill a context and return an 275 331 :class:`~django.http.HttpResponse` object with the result of the rendered 276 332 template. Django provides a shortcut. Here's the full ``index()`` view, 277 333 rewritten:: 278 334 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 281 340 282 341 def index(request): 283 342 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) 285 345 286 346 Note that once we've done this in all these views, we no longer need to import 287 347 :mod:`~django.template.loader`, :class:`~django.template.Context` and 288 348 :class:`~django.http.HttpResponse`. 289 349 290 The :func:`~django.shortcuts.render _to_response` function takes a template name291 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.350 The :func:`~django.shortcuts.render` function takes the request object as its 351 first argument, a template name as its second argument and a dictionary as its 352 optional third argument. It returns an :class:`~django.http.HttpResponse` 353 object of the given template rendered with the given context. 294 354 295 Raising 404296 =========== 355 Raising a 404 error 356 =================== 297 357 298 358 Now, let's tackle the poll detail view -- the page that displays the question 299 359 for a given poll. Here's the view:: … … for a given poll. Here's the view:: 302 362 # ... 303 363 def detail(request, poll_id): 304 364 try: 305 p = Poll.objects.get(pk=poll_id)365 poll = Poll.objects.get(pk=poll_id) 306 366 except Poll.DoesNotExist: 307 367 raise Http404 308 return render _to_response('polls/detail.html', {'poll': p})368 return render(request, 'polls/detail.html', {'poll': poll}) 309 369 310 370 The new concept here: The view raises the :exc:`~django.http.Http404` exception 311 371 if a poll with the requested ID doesn't exist. … … later, but if you'd like to quickly get the above example working, just:: 317 377 318 378 will get you started for now. 319 379 320 A shortcut: get_object_or_404()321 ------------------------------- 380 A shortcut: :func:`~django.shortcuts.get_object_or_404` 381 ------------------------------------------------------- 322 382 323 383 It's a very common idiom to use :meth:`~django.db.models.query.QuerySet.get` 324 384 and raise :exc:`~django.http.Http404` if the object doesn't exist. Django 325 385 provides a shortcut. Here's the ``detail()`` view, rewritten:: 326 386 327 from django.shortcuts import render _to_response, get_object_or_404387 from django.shortcuts import render, get_object_or_404 328 388 # ... 329 389 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}) 332 392 333 393 The :func:`~django.shortcuts.get_object_or_404` function takes a Django model 334 394 as its first argument and an arbitrary number of keyword arguments, which it … … exist. 345 405 :exc:`~django.core.exceptions.ObjectDoesNotExist`? 346 406 347 407 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. 349 410 350 411 There's also a :func:`~django.shortcuts.get_list_or_404` function, which works 351 412 just as :func:`~django.shortcuts.get_object_or_404` -- except using … … special: It's just a normal view. 367 428 You normally won't have to bother with writing 404 views. If you don't set 368 429 ``handler404``, the built-in view :func:`django.views.defaults.page_not_found` 369 430 is used by default. In this case, you still have one obligation: create a 370 ``404.html`` template inthe root of your template directory. The default 404431 ``404.html`` template at the root of your template directory. The default 404 371 432 view will use that template for all 404 errors. If :setting:`DEBUG` is set to 372 433 ``False`` (in your settings module) and if you didn't create a ``404.html`` 373 434 file, an ``Http500`` is raised instead. So remember to create a ``404.html``. … … Similarly, your root URLconf may define a ``handler500``, which points 388 449 to a view to call in case of server errors. Server errors happen when 389 450 you have runtime errors in view code. 390 451 452 Likewise, you should create a ``500.html`` template at the root of your 453 template directory. 454 391 455 Use the template system 392 456 ======================= 393 457 394 458 Back to the ``detail()`` view for our poll application. Given the context 395 variable ``poll``, here's what the "polls/detail.html"template might look459 variable ``poll``, here's what the ``polls/detail.html`` template might look 396 460 like: 397 461 398 462 .. code-block:: html+django … … Method-calling happens in the :ttag:`{% for %}<for>` loop: 415 479 ``poll.choice_set.all()``, which returns an iterable of ``Choice`` objects and is 416 480 suitable for use in the :ttag:`{% for %}<for>` tag. 417 481 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:: 482 Removing hardcoded URLs in templates 483 ==================================== 425 484 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 ) 485 Remember, when we wrote the link to a poll in the polls/index.html template, 486 the link was partially hardcoded like this: 432 487 433 Namely, ``polls.views`` is in every callback. 488 .. code-block:: html+django 434 489 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> 438 491 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 ) 492 The problem with this hardcoded, tightly-coupled approach is that it becomes 493 challenging to change URLs on projects with a lot of templates. However, since 494 you defined the name argument in the :func:`~django.conf.urls.url` functions in 495 the ``polls.urls`` module, you can remove a reliance on specific URL paths 496 defined in your url configurations by using the ``{% url %}`` template tag: 445 497 446 This is functionally identical to the previous formatting. It's just a bit 447 tidier. 498 .. code-block:: html+django 448 499 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> 453 501 454 from django.conf.urls import patterns, include, url 502 The 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 504 defined below:: 455 505 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 ... 458 513 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 ) 514 If you want to change the URL of the polls detail view to something else, 515 perhaps to something like ``polls/specifics/12/`` instead of doing it in the 516 template (or templates) you would change it in ``polls/urls.py``:: 465 517 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 ... 469 525 470 Decoupling the URLconfs 471 ======================= 526 See the :doc:`template guide </topics/templates>` for more about templates. 472 527 473 While we're at it, we should take the time to decouple our poll-app URLs from474 our Django project configuration. Django apps are meant to be pluggable -- that475 is, each particular app should be transferable to another Django installation476 with minimal fuss.477 528 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. 529 Namespacing URL names 530 ====================== 481 531 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. 532 The tutorial project has just one app, ``polls``. In real Django projects, there 533 might be five, ten, twenty apps or more. How does Django differentiate the URL 534 names between them? For example, the ``polls`` app has a ``detail`` view, and so 535 might an app on the same project that is for a blog. How does one make it so 536 that Django knows which app view to create for a url when using the ``{% url %}`` 537 template tag? 485 538 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:: 539 The answer is to add namespaces to your root URLconf. In the 540 ``mysite/urls.py`` file, go ahead and change it to include namespacing:: 489 541 490 542 from django.conf.urls import patterns, include, url 491 543 … … Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change 493 545 admin.autodiscover() 494 546 495 547 urlpatterns = patterns('', 496 url(r'^polls/', include('polls.urls' )),548 url(r'^polls/', include('polls.urls', namespace="polls")), 497 549 url(r'^admin/', include(admin.site.urls)), 498 550 ) 499 551 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. 552 Now change your ``polls/index.html`` template from: 506 553 507 Here's what happens if a user goes to "/polls/34/" in this system: 554 .. code-block:: html+django 508 555 509 * Django will find the match at ``'^polls/'`` 556 <li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li> 510 557 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. 558 to point at the namespaced detail view: 514 559 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 519 561 520 from django.conf.urls import patterns, include, url562 <li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li> 521 563 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 ) 564 About the root URLconf 565 ====================== 566 567 You've probably noticed by now that ``mysite/urls.py`` calls both the polls app 568 and the admin app. It's what is called the root URLconf. 569 570 The :func:`~django.conf.urls.include` functions we are using simply references 571 another URLconf. Note that the regular expression doesn't have a ``$`` 572 (end-of-string match character) but has the trailing slash. Whenever Django 573 encounters :func:`~django.conf.urls.include`, it chops off whatever part of the 574 URL matched up to that point and sends the remaining string to the included 575 URLconf for further processing. 528 576 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. 577 The idea behind :func:`~django.conf.urls.include` is to make it easy to 578 plug-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 581 app will still work. 533 582 534 583 All the poll app cares about is its relative path, not its absolute path. 535 584