Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #12 from mpdaugherty/chapter03

Updates to Chapter 3.
  • Loading branch information...
commit b58795039d1fba34787bb84de4a219618aac7816 2 parents 5b7e18e + eb3bf62
Jacob Kaplan-Moss authored November 20, 2012
16  chapter02.rst
Source Rendered
@@ -36,11 +36,17 @@ Python 2.5, so using a later version of Python keeps your options open.
36 36
 
37 37
 .. admonition:: Django and Python 3.0
38 38
 
39  
-    At the time of writing, Python 3.0 had been released, but Django only
40  
-    supported it experimentally. Python 3.0 introduced a substantial number of
41  
-    backwards-incompatible changes to the language itself, and, as a result,
42  
-    many major Python libraries and frameworks, including Django, had not yet
43  
-    caught up.  Python 2.6-3.2 will be supported by Django 1.5.
  39
+    At the time of writing, Python 3.0 had been released, but Django
  40
+    only supported it experimentally. Python 3.0 introduced a
  41
+    substantial number of backwards-incompatible changes to the
  42
+    language itself, and, as a result, many major Python libraries and
  43
+    frameworks, including Django, had not yet caught up.
  44
+
  45
+    Django 1.5 will support Python 2.6, 2.7, and 3.2.  However,
  46
+    support for Python 3.2 is considered a "preview", which means the
  47
+    Django developers are not yet confident enough to promise
  48
+    stability in production.  For that, they suggest you wait until
  49
+    Django 1.6.
44 50
 
45 51
 Installation
46 52
 ------------
166  chapter03.rst
Source Rendered
@@ -96,38 +96,38 @@ When you executed ``django-admin.py startproject`` in the previous chapter, the
96 96
 script created a URLconf for you automatically: the file ``urls.py``. By
97 97
 default, it looks something like this::
98 98
 
99  
-    from django.conf.urls.defaults import *
  99
+    from django.conf.urls import patterns, include, url
100 100
 
101 101
     # Uncomment the next two lines to enable the admin:
102 102
     # from django.contrib import admin
103 103
     # admin.autodiscover()
104 104
 
105 105
     urlpatterns = patterns('',
106  
-        # Example:
107  
-        # (r'^mysite/', include('mysite.foo.urls')),
  106
+        # Examples:
  107
+        # url(r'^$', 'mysite.views.home', name='home'),
  108
+        # url(r'^mysite/', include('mysite.foo.urls')),
108 109
 
109  
-        # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
110  
-        # to INSTALLED_APPS to enable admin documentation:
111  
-        # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
  110
+        # Uncomment the admin/doc line below to enable admin documentation:
  111
+        # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
112 112
 
113 113
         # Uncomment the next line to enable the admin:
114  
-        # (r'^admin/', include(admin.site.urls)),
  114
+        # url(r'^admin/', include(admin.site.urls)),
115 115
     )
116 116
 
117 117
 This default URLconf includes some commonly used Django features commented out,
118 118
 so that activating those features is as easy as uncommenting the appropriate
119 119
 lines. If we ignore the commented-out code, here's the essence of a URLconf::
120 120
 
121  
-    from django.conf.urls.defaults import *
  121
+    from django.conf.urls.defaults import patterns, include, url
122 122
 
123 123
     urlpatterns = patterns('',
124 124
     )
125 125
 
126 126
 Let's step through this code one line at a time:
127 127
 
128  
-* The first line imports all objects from the ``django.conf.urls.defaults``
129  
-  module, which is Django's URLconf infrastructure. This includes a
130  
-  function called ``patterns``.
  128
+* The first line imports three functions from the ``django.conf.urls.defaults``
  129
+  module, which is Django's URLconf infrastructure: ``patterns``, ``include``,
  130
+  and ``urls``.
131 131
 
132 132
 * The second line calls the function ``patterns`` and saves the result
133 133
   into a variable called ``urlpatterns``. The ``patterns`` function gets
@@ -143,14 +143,14 @@ note, that's how Django knew to show you the "Welcome to Django" page in the
143 143
 last chapter. If your URLconf is empty, Django assumes you just started a new
144 144
 project and, hence, displays that message.)
145 145
 
146  
-To add a URL and view to the URLconf, just add a Python tuple mapping a URL
147  
-pattern to the view function. Here's how to hook in our ``hello`` view::
  146
+To add a URL and view to the URLconf, just add a mapping between a URL
  147
+pattern and the view function. Here's how to hook in our ``hello`` view::
148 148
 
149  
-    from django.conf.urls.defaults import *
  149
+    from django.conf.urls.defaults import patterns, include, url
150 150
     from mysite.views import hello
151 151
 
152 152
     urlpatterns = patterns('',
153  
-        ('^hello/$', hello),
  153
+        url(r'^hello/$', hello),
154 154
     )
155 155
 
156 156
 (Note that we've removed the commented-out code for brevity. You can choose
@@ -163,11 +163,28 @@ We made two changes here:
163 163
   import syntax. (This assumes ``mysite/views.py`` is on your Python path;
164 164
   see the sidebar for details.)
165 165
 
166  
-* Next, we added the line ``('^hello/$', hello),`` to ``urlpatterns``. This
167  
-  line is referred to as a *URLpattern*. It's a Python tuple in which the
168  
-  first element is a pattern-matching string (a regular expression; more on
169  
-  this in a bit) and the second element is the view function to use for
170  
-  that pattern.
  166
+* Next, we added the line ``url(r'^hello/$', hello),`` to ``urlpatterns``. This
  167
+  line is referred to as a *URLpattern*. The ``url()`` function tells Django how
  168
+  to handle the url that you are configuring. The first argument is a
  169
+  pattern-matching string (a regular expression; more on this in a bit) and the
  170
+  second argument is the view function to use for that pattern. ``url()`` can
  171
+  take other optional arguments as well, which we'll cover in more depth in
  172
+  :doc:`chapter08`.
  173
+
  174
+.. note::
  175
+
  176
+  One more important detail we've introduced here is that ``r`` character in
  177
+  front of the regular expression string. This tells Python that the string is a
  178
+  "raw string" -- its contents should not interpret backslashes. In normal
  179
+  Python strings, backslashes are used for escaping special characters -- such
  180
+  as in the string ``'\n'``, which is a one-character string containing a
  181
+  newline. When you add the ``r`` to make it a raw string, Python does not apply
  182
+  its backslash escaping -- so, ``r'\n'`` is a two-character string containing a
  183
+  literal backslash and a lowercase "n". There's a natural collision between
  184
+  Python's usage of backslashes and the backslashes that are found in regular
  185
+  expressions, so it's strongly suggested that you use raw strings any time
  186
+  you're defining a regular expression in Python. All of the URLpatterns in this
  187
+  book will be raw strings.
171 188
 
172 189
 In a nutshell, we just told Django that any request to the URL ``/hello/`` should
173 190
 be handled by the ``hello`` view function.
@@ -178,12 +195,12 @@ be handled by the ``hello`` view function.
178 195
     looks when you use the Python ``import`` statement.
179 196
 
180 197
     For example, let's say your Python path is set to ``['',
181  
-    '/usr/lib/python2.4/site-packages', '/home/username/djcode']``. If you
  198
+    '/usr/lib/python2.7/site-packages', '/home/username/djcode']``. If you
182 199
     execute the Python statement ``from foo import bar``, Python will look for
183 200
     a module called ``foo.py`` in the current directory. (The first entry in the
184 201
     Python path, an empty string, means "the current directory.") If that file
185 202
     doesn't exist, Python will look for the file
186  
-    ``/usr/lib/python2.4/site-packages/foo.py``. If that file doesn't exist, it
  203
+    ``/usr/lib/python2.7/site-packages/foo.py``. If that file doesn't exist, it
187 204
     will try ``/home/username/djcode/foo.py``. Finally, if *that* file doesn't
188 205
     exist, it will raise ``ImportError``.
189 206
 
@@ -346,7 +363,7 @@ the URLpattern ``'^$'``, which matches an empty string. For example::
346 363
     from mysite.views import hello, my_homepage_view
347 364
 
348 365
     urlpatterns = patterns('',
349  
-        ('^$', my_homepage_view),
  366
+        url(r'^$', my_homepage_view),
350 367
         # ...
351 368
     )
352 369
 
@@ -358,13 +375,13 @@ more about how Django works. Specifically, when you view your "Hello world"
358 375
 message by visiting ``http://127.0.0.1:8000/hello/`` in your Web browser, what
359 376
 does Django do behind the scenes?
360 377
 
361  
-It all starts with the *settings file*. When you run
362  
-``python manage.py runserver``, the script looks for a file called
363  
-``settings.py`` in the same directory as ``manage.py``. This file contains all
364  
-sorts of configuration for this particular Django project, all in uppercase:
365  
-``TEMPLATE_DIRS``, ``DATABASE_NAME``, etc. The most important setting is called
366  
-``ROOT_URLCONF``. ``ROOT_URLCONF`` tells Django which Python module should be
367  
-used as the URLconf for this Web site.
  378
+It all starts with the *settings file*. When you run ``python manage.py
  379
+runserver``, the script looks for a file called ``settings.py`` in the inner
  380
+``mysite`` directory. This file contains all sorts of configuration for this
  381
+particular Django project, all in uppercase: ``TEMPLATE_DIRS``, ``DATABASES``,
  382
+etc. The most important setting is called ``ROOT_URLCONF``. ``ROOT_URLCONF``
  383
+tells Django which Python module should be used as the URLconf for this Web
  384
+site.
368 385
 
369 386
 Remember when ``django-admin.py startproject`` created the files
370 387
 ``settings.py`` and ``urls.py``? The autogenerated ``settings.py`` contains a
@@ -496,12 +513,12 @@ After adding that to ``views.py``, add the URLpattern to ``urls.py`` to tell
496 513
 Django which URL should handle this view. Something like ``/time/`` would make
497 514
 sense::
498 515
 
499  
-    from django.conf.urls.defaults import *
  516
+    from django.conf.urls.defaults import patterns, include, url
500 517
     from mysite.views import hello, current_datetime
501 518
 
502 519
     urlpatterns = patterns('',
503  
-        ('^hello/$', hello),
504  
-        ('^time/$', current_datetime),
  520
+        url(r'^hello/$', hello),
  521
+        url(r'^time/$', current_datetime),
505 522
     )
506 523
 
507 524
 We've made two changes here. First, we imported the ``current_datetime``
@@ -531,7 +548,7 @@ interchangeable. If two pieces of code are loosely coupled, then changes made to
531 548
 one of the pieces will have little or no effect on the other.
532 549
 
533 550
 Django's URLconfs are a good example of this principle in practice. In a Django
534  
-Web application, the URL definitions and the view functions they call are
  551
+web application, the URL definitions and the view functions they call are
535 552
 loosely coupled; that is, the decision of what the URL should be for a given
536 553
 function, and the implementation of the function itself, reside in two separate
537 554
 places. This lets you switch out one piece without affecting the other.
@@ -550,9 +567,9 @@ without having to touch the view code. In this example, our
550 567
 this technique can come in handy::
551 568
 
552 569
     urlpatterns = patterns('',
553  
-        ('^hello/$', hello),
554  
-        ('^time/$', current_datetime),
555  
-        ('^another-time-page/$', current_datetime),
  570
+        url(r'^hello/$', hello),
  571
+        url(r'^time/$', current_datetime),
  572
+        url(r'^another-time-page/$', current_datetime),
556 573
     )
557 574
 
558 575
 URLconfs and views are loose coupling in action. We'll continue to point out
@@ -578,11 +595,11 @@ A novice might think to code a separate view function for each hour offset,
578 595
 which might result in a URLconf like this::
579 596
 
580 597
     urlpatterns = patterns('',
581  
-        ('^time/$', current_datetime),
582  
-        ('^time/plus/1/$', one_hour_ahead),
583  
-        ('^time/plus/2/$', two_hours_ahead),
584  
-        ('^time/plus/3/$', three_hours_ahead),
585  
-        ('^time/plus/4/$', four_hours_ahead),
  598
+        url(r'^time/$', current_datetime),
  599
+        url(r'^time/plus/1/$', one_hour_ahead),
  600
+        url(r'^time/plus/2/$', two_hours_ahead),
  601
+        url(r'^time/plus/3/$', three_hours_ahead),
  602
+        url(r'^time/plus/4/$', four_hours_ahead),
586 603
     )
587 604
 
588 605
 Clearly, this line of thought is flawed. Not only would this result in redundant
@@ -616,7 +633,7 @@ is a regular expression; hence, we can use the regular expression pattern
616 633
 
617 634
     urlpatterns = patterns('',
618 635
         # ...
619  
-        (r'^time/plus/\d+/$', hours_ahead),
  636
+        url(r'^time/plus/\d+/$', hours_ahead),
620 637
         # ...
621 638
     )
622 639
 
@@ -629,7 +646,7 @@ let's limit it so that the maximum allowed offset is 99 hours. That means we
629 646
 want to allow either one- or two-digit numbers -- and in regular expression
630 647
 syntax, that translates into ``\d{1,2}``::
631 648
 
632  
-    (r'^time/plus/\d{1,2}/$', hours_ahead),
  649
+    url(r'^time/plus/\d{1,2}/$', hours_ahead),
633 650
 
634 651
 .. note::
635 652
 
@@ -638,19 +655,6 @@ syntax, that translates into ``\d{1,2}``::
638 655
     should support that input. We've curtailed the outlandishness here by
639 656
     limiting the offset to 99 hours.
640 657
 
641  
-One more important detail we've introduced here is that ``r`` character in
642  
-front of the regular expression string. This tells Python that the string is a
643  
-"raw string" -- its contents should not interpret backslashes. In normal Python
644  
-strings, backslashes are used for escaping special characters -- such as in the
645  
-string ``'\n'``, which is a one-character string containing a newline. When you
646  
-add the ``r`` to make it a raw string, Python does not apply its backslash
647  
-escaping -- so, ``r'\n'`` is a two-character string containing a literal
648  
-backslash and a lowercase "n". There's a natural collision between Python's
649  
-usage of backslashes and the backslashes that are found in regular expressions,
650  
-so it's strongly suggested that you use raw strings any time you're defining a
651  
-regular expression in Python. From now on, all of the URLpatterns in this book
652  
-will be raw strings.
653  
-
654 658
 Now that we've designated a wildcard for the URL, we need a way of passing that
655 659
 wildcard data to the view function, so that we can use a single view function
656 660
 for any arbitrary hour offset. We do this by placing parentheses around the
@@ -658,7 +662,7 @@ data in the URLpattern that we want to save. In the case of our example, we
658 662
 want to save whatever number was entered in the URL, so let's put parentheses
659 663
 around the ``\d{1,2}``, like this::
660 664
 
661  
-    (r'^time/plus/(\d{1,2})/$', hours_ahead),
  665
+    url(r'^time/plus/(\d{1,2})/$', hours_ahead),
662 666
 
663 667
 If you're familiar with regular expressions, you'll be right at home here;
664 668
 we're using parentheses to *capture* data from the matched text.
@@ -669,33 +673,13 @@ The final URLconf, including our previous two views, looks like this::
669 673
     from mysite.views import hello, current_datetime, hours_ahead
670 674
 
671 675
     urlpatterns = patterns('',
672  
-        (r'^hello/$', hello),
673  
-        (r'^time/$', current_datetime),
674  
-        (r'^time/plus/(\d{1,2})/$', hours_ahead),
  676
+        url(r'^hello/$', hello),
  677
+        url(r'^time/$', current_datetime),
  678
+        url(r'^time/plus/(\d{1,2})/$', hours_ahead),
675 679
     )
676 680
 
677 681
 With that taken care of, let's write the ``hours_ahead`` view.
678 682
 
679  
-.. admonition:: Coding Order
680  
-
681  
-    In this example, we wrote the URLpattern first and the view second, but in
682  
-    the previous examples, we wrote the view first, then the URLpattern. Which
683  
-    technique is better?
684  
-
685  
-    Well, every developer is different.
686  
-
687  
-    If you're a big-picture type of person, it may make the most sense to you
688  
-    to write all of the URLpatterns for your application at the same time, at
689  
-    the start of your project, and then code up the views. This has the
690  
-    advantage of giving you a clear to-do list, and it essentially defines the
691  
-    parameter requirements for the view functions you'll need to write.
692  
-
693  
-    If you're more of a bottom-up developer, you might prefer to write the
694  
-    views first, and then anchor them to URLs afterward. That's OK, too.
695  
-
696  
-    In the end, it comes down to which technique fits your brain the best. Both
697  
-    approaches are valid.
698  
-
699 683
 ``hours_ahead`` is very similar to the ``current_datetime`` view we wrote
700 684
 earlier, with a key difference: it takes an extra argument, the number of hours
701 685
 of offset. Here's the view code::
@@ -788,6 +772,26 @@ not found" error in this case, just as we saw in the section "A Quick Note
788 772
 About 404 Errors" earlier. The URL ``http://127.0.0.1:8000/time/plus/`` (with
789 773
 *no* hour designation) should also throw a 404.
790 774
 
  775
+.. admonition:: Coding Order
  776
+
  777
+    In this example, we wrote the URLpattern first and the view second, but in
  778
+    the previous examples, we wrote the view first, then the URLpattern. Which
  779
+    technique is better?
  780
+
  781
+    Well, every developer is different.
  782
+
  783
+    If you're a big-picture type of person, it may make the most sense to you
  784
+    to write all of the URLpatterns for your application at the same time, at
  785
+    the start of your project, and then code up the views. This has the
  786
+    advantage of giving you a clear to-do list, and it essentially defines the
  787
+    parameter requirements for the view functions you'll need to write.
  788
+
  789
+    If you're more of a bottom-up developer, you might prefer to write the
  790
+    views first, and then anchor them to URLs afterward. That's OK, too.
  791
+
  792
+    In the end, it comes down to which technique fits your brain the best. Both
  793
+    approaches are valid.
  794
+
791 795
 Django's Pretty Error Pages
792 796
 ===========================
793 797
 

0 notes on commit b587950

Please sign in to comment.
Something went wrong with that request. Please try again.