Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

magic-removal: Fixes #1599, Refs #1464 -- Updated all tutorials for n…

…ew syntax, changes in manage.py, etc.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2632 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit d1083f15fbdf073d768677f683a1e3b5136e3e41 1 parent 218035c
Russell Keith-Magee authored April 08, 2006
50  docs/tutorial01.txt
@@ -24,7 +24,7 @@ Initial setup
24 24
 If this is your first time using Django, you'll have to take care of some
25 25
 initial setup.
26 26
 
27  
-Run the command ``django-admin.py startproject myproject``. That'll create a
  27
+Run the command ``django-admin.py startproject myproject``. This will create a
28 28
 ``myproject`` directory in your current directory.
29 29
 
30 30
 (``django-admin.py`` should be on your system path if you installed Django via
@@ -125,9 +125,10 @@ database's connection parameters:
125 125
     database's interactive prompt.
126 126
 
127 127
 While you're editing ``settings.py``, take note of the ``INSTALLED_APPS``
128  
-setting. That variable holds the names of all Django applications that are
129  
-activated in this Django instance. Apps can be used in multiple projects,
130  
-and you can distribute them.
  128
+setting towards the bottom of the file. That variable holds the names of all 
  129
+Django applications that are activated in this Django instance. Apps can be 
  130
+used in multiple projects, and you can package and distribute them for use
  131
+by others in their projects.
131 132
 
132 133
 By default, ``INSTALLED_APPS`` contains the following apps, all of which come
133 134
 with Django::
@@ -285,12 +286,9 @@ to include the string ``'myproject.polls'``. So it'll look like this::
285 286
         'django.contrib.contenttypes',
286 287
         'django.contrib.sessions',
287 288
         'django.contrib.sites',
288  
-        'myproject.polls',
  289
+        'myproject.polls'
289 290
     )
290 291
 
291  
-(Don't forget the trailing comma, because of Python's rule about single-value
292  
-tuples: Without a trailing comma, Python wouldn't know this was a tuple.)
293  
-
294 292
 Now Django knows ``myproject`` includes the ``polls`` app. Let's run another command::
295 293
 
296 294
     python manage.py sql polls
@@ -331,6 +329,12 @@ Note the following:
331 329
       quotes. The author of this tutorial runs PostgreSQL, so the example
332 330
       output is in PostgreSQL syntax.
333 331
 
  332
+    * The `sql` command doesn't actually run the SQL in your database - it just 
  333
+      prints it to the screen so that you can see what SQL Django thinks is required.
  334
+      If you wanted to, you could copy and paste this SQL into your database prompt.
  335
+      However, as we will see shortly, Django provides an easier way of committing
  336
+      the SQL to the database.
  337
+
334 338
 If you're interested, also run the following commands:
335 339
 
336 340
     * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data
@@ -343,8 +347,8 @@ If you're interested, also run the following commands:
343 347
     * ``python manage.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
344 348
       statements for this app.
345 349
 
346  
-    * ``python manage.py sqlall polls`` -- A combination of 'sql' and
347  
-      'sqlinitialdata'.
  350
+    * ``python manage.py sqlall polls`` -- A combination of all the SQL from
  351
+      the 'sql', 'sqlinitialdata', and 'sqlindexes' commands.
348 352
 
349 353
 Looking at the output of those commands can help you understand what's actually
350 354
 happening under the hood.
@@ -353,9 +357,11 @@ Now, run ``syncdb`` again to create those model tables in your database::
353 357
 
354 358
     python manage.py syncdb
355 359
 
356  
-As a review, the ``syncdb`` command creates the tables for all apps in
357  
-``INSTALLED_APPS`` that don't already exist in your database. So you can run it
358  
-again and again, and it'll always just create the tables that don't exist.
  360
+The ``syncdb`` command runs the sql from 'sqlall' on your database for all apps
  361
+in ``INSTALLED_APPS`` that don't already exist in your database. This creates
  362
+all the tables, initial data and indexes for any apps you have added to your 
  363
+project since the last time you ran syncdb. ``syncdb`` can be called as often
  364
+as you like, and it will only ever create the tables that don't exist.
359 365
 
360 366
 Read the `django-admin.py documentation`_ for full information on what the
361 367
 ``manage.py`` utility can do.
@@ -454,10 +460,11 @@ representations are used throughout Django's automatically-generated admin.
454 460
 Note these are normal Python methods. Let's add a custom method, just for
455 461
 demonstration::
456 462
 
  463
+    import datetime
  464
+    # ...
457 465
     class Poll(models.Model):
458 466
         # ...
459 467
         def was_published_today(self):
460  
-            import datetime
461 468
             return self.pub_date.date() == datetime.date.today()
462 469
 
463 470
 Note the addition of ``import datetime`` to reference Python's standard
@@ -488,8 +495,6 @@ Let's jump back into the Python interactive shell by running
488 495
     Traceback (most recent call last):
489 496
         ...
490 497
     DoesNotExist: Poll does not exist for {'id': 2}
491  
-    >>> Poll.objects.filter(question__startswith='What')
492  
-    [What's up?]
493 498
 
494 499
     # Lookup by a primary key is the most common case, so Django provides a
495 500
     # shortcut for primary-key exact lookups.
@@ -502,14 +507,15 @@ Let's jump back into the Python interactive shell by running
502 507
     >>> p.was_published_today()
503 508
     False
504 509
 
505  
-    # Give the Poll a couple of Choices. Each one of these method calls does an
506  
-    # INSERT statement behind the scenes and returns the new Choice object.
  510
+    # Give the Poll a couple of Choices. The create call constructs a new 
  511
+    # choice object, does the INSERT statement, adds the choice to the set
  512
+    # of available choices and returns the new Choice object.
507 513
     >>> p = Poll.objects.get(pk=1)
508  
-    >>> p.choice_set.add(choice='Not much', votes=0)
  514
+    >>> p.choice_set.create(choice='Not much', votes=0)
509 515
     Not much
510  
-    >>> p.choice_set.add(choice='The sky', votes=0)
  516
+    >>> p.choice_set.create(choice='The sky', votes=0)
511 517
     The sky
512  
-    >>> c = p.choice_set.add(choice='Just hacking again', votes=0)
  518
+    >>> c = p.choice_set.create(choice='Just hacking again', votes=0)
513 519
 
514 520
     # Choice objects have API access to their related Poll objects.
515 521
     >>> c.poll
@@ -518,7 +524,7 @@ Let's jump back into the Python interactive shell by running
518 524
     # And vice versa: Poll objects get access to Choice objects.
519 525
     >>> p.choice_set.all()
520 526
     [Not much, The sky, Just hacking again]
521  
-    >>> p.choice_set.all().count()
  527
+    >>> p.choice_set.count()
522 528
     3
523 529
 
524 530
     # The API automatically follows relationships as far as you need.
16  docs/tutorial02.txt
@@ -31,22 +31,13 @@ The Django admin site is not activated by default -- it's an opt-in thing. To
31 31
 activate the admin site for your installation, do these three things:
32 32
 
33 33
     * Add ``"django.contrib.admin"`` to your ``INSTALLED_APPS`` setting.
34  
-    * Run the command ``python manage.py install admin``. This will create an
35  
-      extra database table that the admin needs.
  34
+    * Run ``python manage.py syncdb``. Since you have added a new application
  35
+      to ``INSTALLED_APPS``, the database tables need to be updated.
36 36
     * Edit your ``myproject/urls.py`` file and uncomment the line below
37 37
       "Uncomment this for admin:". This file is a URLconf; we'll dig into
38 38
       URLconfs in the next tutorial. For now, all you need to know is that it
39 39
       maps URL roots to applications.
40 40
 
41  
-Create a user account
42  
-=====================
43  
-
44  
-Run the following command to create a superuser account for your admin site::
45  
-
46  
-    python manage.py createsuperuser
47  
-
48  
-The script will prompt you for a username, e-mail address and password (twice).
49  
-
50 41
 Start the development server
51 42
 ============================
52 43
 
@@ -96,7 +87,8 @@ creating an empty class means "give this object an admin interface using
96 87
 all the default options."
97 88
 
98 89
 Now reload the Django admin page to see your changes. Note that you don't have
99  
-to restart the development server -- it auto-reloads code.
  90
+to restart the development server -- the server will auto-reloads your project,
  91
+so any modifications code will be seen immediately in your browser.
100 92
 
101 93
 Explore the free admin functionality
102 94
 ====================================
72  docs/tutorial03.txt
@@ -74,25 +74,27 @@ Time for an example. Edit ``myproject/urls.py`` so it looks like this::
74 74
 
75 75
     urlpatterns = patterns('',
76 76
         (r'^polls/$', 'myproject.polls.views.index'),
77  
-        (r'^polls/(\d+)/$', 'myproject.polls.views.detail'),
78  
-        (r'^polls/(\d+)/results/$', 'myproject.polls.views.results'),
79  
-        (r'^polls/(\d+)/vote/$', 'myproject.polls.views.vote'),
  77
+        (r'^polls/(?P<poll_id>\d+)/$', 'myproject.polls.views.detail'),
  78
+        (r'^polls/(?P<poll_id>\d+)/results/$', 'myproject.polls.views.results'),
  79
+        (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
80 80
     )
81 81
 
82 82
 This is worth a review. When somebody requests a page from your Web site --
83 83
 say, "/polls/23/", Django will load this Python module, because it's pointed to
84 84
 by the ``ROOT_URLCONF`` setting. It finds the variable named ``urlpatterns``
85 85
 and traverses the regular expressions in order. When it finds a regular
86  
-expression that matches -- ``r'^polls/(\d+)/$'`` -- it loads the
  86
+expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
87 87
 associated Python package/module: ``myproject.polls.views.detail``. That
88 88
 corresponds to the function ``detail()`` in ``myproject/polls/views.py``.
89 89
 Finally, it calls that ``detail()`` function like so::
90 90
 
91 91
     detail(request=<HttpRequest object>, poll_id='23')
92 92
 
93  
-The ``poll_id='23'`` part comes from ``(\d+)``. Using parenthesis around a
  93
+The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
94 94
 pattern "captures" the text matched by that pattern and sends it as an argument
95  
-to the view function.
  95
+to the view function; the ``?P<poll_id>`` defines the name that will be used to 
  96
+identify the matched pattern; and \d+ is a regular experession to match a sequence of
  97
+digits (i.e., a number).
96 98
 
97 99
 Because the URL patterns are regular expressions, there really is no limit on
98 100
 what you can do with them. And there's no need to add URL cruft such as
@@ -185,29 +187,29 @@ in Tutorial 1. Here's one stab at the ``index()`` view, which displays the
185 187
 latest 5 poll questions in the system, separated by commas, according to
186 188
 publication date::
187 189
 
188  
-    from django.models.polls import polls
189  
-    from django.http import HttpResponse
  190
+	from myproject.polls.models import Poll
  191
+	from django.http import HttpResponse
190 192
 
191  
-    def index(request):
192  
-        latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
193  
-        output = ', '.join([p.question for p in latest_poll_list])
194  
-        return HttpResponse(output)
  193
+	def index(request):
  194
+		latest_poll_list = Poll.objects.all().order_by('-pub_date')
  195
+		output = ', '.join([p.question for p in latest_poll_list])
  196
+		return HttpResponse(output)
195 197
 
196 198
 There's a problem here, though: The page's design is hard-coded in the view. If
197 199
 you want to change the way the page looks, you'll have to edit this Python code.
198 200
 So let's use Django's template system to separate the design from Python::
199 201
 
200  
-    from django.template import Context, loader
201  
-    from django.models.polls import polls
202  
-    from django.http import HttpResponse
  202
+	from django.template import Context, loader
  203
+	from myproject.polls.models import Poll
  204
+	from django.http import HttpResponse
203 205
 
204  
-    def index(request):
205  
-        latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
206  
-        t = loader.get_template('polls/index')
207  
-        c = Context({
208  
-            'latest_poll_list': latest_poll_list,
209  
-        })
210  
-        return HttpResponse(t.render(c))
  206
+	def index(request):
  207
+		latest_poll_list = Poll.objects.all().order_by('-pub_date')
  208
+		t = loader.get_template('polls/index')
  209
+		c = Context({
  210
+		    'latest_poll_list': latest_poll_list,
  211
+		})
  212
+		return HttpResponse(t.render(c))
211 213
 
212 214
 That code loads the template called "polls/index" and passes it a context. The
213 215
 context is a dictionary mapping template variable names to Python objects.
@@ -254,11 +256,11 @@ It's a very common idiom to load a template, fill a context and return an
254 256
 ``HttpResponse`` object with the result of the rendered template. Django
255 257
 provides a shortcut. Here's the full ``index()`` view, rewritten::
256 258
 
257  
-    from django.shortcuts import render_to_response
258  
-    from django.models.polls import polls
  259
+	from django.shortcuts import render_to_response
  260
+	from myproject.polls.models import Poll
259 261
 
260  
-    def index(request):
261  
-        latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
  262
+	def index(request):
  263
+		latest_poll_list = Poll.objects.all().order_by('-pub_date')
262 264
         return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
263 265
 
264 266
 Note that we no longer need to import ``loader``, ``Context`` or
@@ -275,12 +277,13 @@ Now, let's tackle the poll detail view -- the page that displays the question
275 277
 for a given poll. Here's the view::
276 278
 
277 279
     from django.http import Http404
278  
-    def detail(request, poll_id):
279  
-        try:
280  
-            p = polls.get_object(pk=poll_id)
281  
-        except polls.PollDoesNotExist:
282  
-            raise Http404
283  
-        return render_to_response('polls/detail', {'poll': p})
  280
+    # ...
  281
+	def detail(request, poll_id):
  282
+	    try:
  283
+	        p = Poll.objects.get(pk=poll_id)
  284
+	    except Poll.DoesNotExist:
  285
+	        raise Http404
  286
+	    return render_to_response('polls/detail', {'poll': p})
284 287
 
285 288
 The new concept here: The view raises the ``django.http.Http404``
286 289
 exception if a poll with the requested ID doesn't exist.
@@ -292,9 +295,10 @@ It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the
292 295
 object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view,
293 296
 rewritten::
294 297
 
295  
-    from django.shortcuts import get_object_or_404
  298
+    from django.shortcuts import render_to_response, get_object_or_404
  299
+    # ...
296 300
     def detail(request, poll_id):
297  
-        p = get_object_or_404(polls, pk=poll_id)
  301
+        p = get_object_or_404(Poll, pk=poll_id)
298 302
         return render_to_response('polls/detail', {'poll': p})
299 303
 
300 304
 The ``get_object_or_404()`` function takes a Django model module as its first
56  docs/tutorial04.txt
@@ -18,7 +18,7 @@ template contains an HTML ``<form>`` element::
18 18
     {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
19 19
 
20 20
     <form action="/polls/{{ poll.id }}/vote/" method="post">
21  
-    {% for choice in poll.get_choice_list %}
  21
+    {% for choice in poll.choice_set.all %}
22 22
         <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
23 23
         <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
24 24
     {% endfor %}
@@ -41,22 +41,22 @@ A quick rundown:
41 41
       Django; it's just good Web development practice.
42 42
 
43 43
 Now, let's create a Django view that handles the submitted data and does
44  
-something with it. Remember, in `Tutorial 3`_, we create a URLconf that
45  
-included this line::
  44
+something with it. Remember, in `Tutorial 3`_, we create a URLconf for the
  45
+polls application that includes this line::
46 46
 
47  
-    (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
  47
+    (r'^(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
48 48
 
49 49
 So let's create a ``vote()`` function in ``myproject/polls/views.py``::
50 50
 
51 51
     from django.shortcuts import get_object_or_404, render_to_response
52  
-    from django.http import HttpResponseRedirect
  52
+    from django.http import Http404,HttpResponseRedirect
53 53
     from myproject.polls.models import Choice, Poll
54  
-
  54
+    # ...
55 55
     def vote(request, poll_id):
56 56
         p = get_object_or_404(Poll, pk=poll_id)
57 57
         try:
58 58
             selected_choice = p.choice_set.filter(pk=request.POST['choice'])
59  
-        except (KeyError, choices.ChoiceDoesNotExist):
  59
+        except (KeyError, Choice.DoesNotExist):
60 60
             # Redisplay the poll voting form.
61 61
             return render_to_response('polls/detail', {
62 62
                 'poll': p,
@@ -113,7 +113,7 @@ Now, create a ``results.html`` template::
113 113
     <h1>{{ poll.question }}</h1>
114 114
 
115 115
     <ul>
116  
-    {% for choice in poll.get_choice_list %}
  116
+    {% for choice in poll.choice_set.all %}
117 117
         <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
118 118
     {% endfor %}
119 119
     </ul>
@@ -185,37 +185,45 @@ We're using two generic views here: ``object_list`` and ``object_detail``.
185 185
 Respectively, those two views abstract the concepts of "display a list of
186 186
 objects" and "display a detail page for a particular type of object."
187 187
 
188  
-    * Each generic view needs to know which model its acting on. This 
189  
-      is done using a QuerySet. 
  188
+    * Each generic view needs to know what data it will be acting upon. This
  189
+      data is provided in a dictionary. The ``queryset`` key in this dictionary
  190
+      points to the list of objects to be manipulated by the generic view.
190 191
 
191  
-    * The ``object_detail`` generic view expects that the ID value captured
192  
-      from the URL is called ``"object_id"``, so we've changed ``poll_id`` to
  192
+    * The ``object_detail`` generic view expects the ID value captured
  193
+      from the URL to be called ``"object_id"``, so we've changed ``poll_id`` to
193 194
       ``object_id`` for the generic views.
194 195
 
195 196
 By default, the ``object_detail`` generic view uses a template called
196  
-``<app_label>/<module_name>_detail``. In our case, it'll use the template
197  
-``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to
198  
-``polls/polls_detail.html``, and change the ``render_to_response()`` line in
  197
+``<app name>/<module name>_detail``. In our case, it'll use the template
  198
+``"polls/poll_detail"``. Thus, rename your ``polls/detail.html`` template to
  199
+``polls/poll_detail.html``, and change the ``render_to_response()`` line in
199 200
 ``vote()``.
200 201
 
201 202
 Similarly, the ``object_list`` generic view uses a template called
202  
-``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to
203  
-``polls/polls_list.html``.
  203
+``<app name>/<module name>_list``. Thus, rename ``poll/index.html`` to
  204
+``polls/poll_list.html``.
204 205
 
205 206
 Because we have more than one entry in the URLconf that uses ``object_detail``
206 207
 for the polls app, we manually specify a template name for the results view:
207 208
 ``template_name='polls/results'``. Otherwise, both views would use the same
208 209
 template. Note that we use ``dict()`` to return an altered dictionary in place.
209 210
 
210  
-The generic views pass ``object`` and ``object_list`` to their templates, so
211  
-change your templates so that ``latest_poll_list`` becomes ``object_list`` and
212  
-``poll`` becomes ``object``.
  211
+In previous versions of the tutorial, the templates have been provided with a context
  212
+that contains the ``poll` and ``latest_poll_list`` context variables. However, 
  213
+the generic views provide the variables ``object`` and ``object_list`` as context. 
  214
+Therefore, you need to change your templates to match the new context variables. 
  215
+Go through your templates, and modify any reference to ``latest_poll_list`` to
  216
+``object_list``, and change any reference to ``poll`` to ``object``. 
  217
+
  218
+You can now delete the ``index()``, ``detail()`` and ``results()`` views
  219
+from ``polls/views.py``. We don't need them anymore -- they have been replaced
  220
+by generic views.
213 221
 
214  
-In the ``vote()`` view, change the template call from ``polls/detail`` to
215  
-``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``.
  222
+The ``vote()`` view is still required. However, it must be modified to match
  223
+the new templates and context variables. Change the template call from ``polls/detail`` 
  224
+to ``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``.
216 225
 
217  
-Finally, you can delete the ``index()``, ``detail()`` and ``results()`` views
218  
-from ``polls/views.py``. We don't need them anymore.
  226
+Run the server, and use your new polling app based on generic views.
219 227
 
220 228
 For full details on generic views, see the `generic views documentation`_.
221 229
 

0 notes on commit d1083f1

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