Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed errors and inconsistencies in CBV topic documentation.

The code examples should now work correctly.
The `get_context_data` method in the examples was changed when
necessary to adopt a singular style (get context with super(...),
add the extra keys to the dict then return it).

Thanks to Remco Wendt for the initial report and to Tim Graham
for the review.
  • Loading branch information...
commit bd9fbd1497edc585c5bec28c7d4bc8d1afd1943b 1 parent 338ec93
Baptiste Mispelon authored June 22, 2013
25  docs/topics/class-based-views/generic-display.txt
@@ -92,6 +92,15 @@ We'll be using these models::
92 92
         def __unicode__(self):
93 93
             return self.name
94 94
 
  95
+    class Author(models.Model):
  96
+        salutation = models.CharField(max_length=10)
  97
+        name = models.CharField(max_length=200)
  98
+        email = models.EmailField()
  99
+        headshot = models.ImageField(upload_to='author_headshots')
  100
+
  101
+        def __unicode__(self):
  102
+            return self.name
  103
+
95 104
     class Book(models.Model):
96 105
         title = models.CharField(max_length=100)
97 106
         authors = models.ManyToManyField('Author')
@@ -132,11 +141,11 @@ bit is just the lowercased version of the model's name.
132 141
     enabled in :setting:`TEMPLATE_LOADERS`, a template location could be:
133 142
     /path/to/project/books/templates/books/publisher_list.html
134 143
 
135  
-.. highlightlang:: html+django
136  
-
137 144
 This template will be rendered against a context containing a variable called
138 145
 ``object_list`` that contains all the publisher objects. A very simple template
139  
-might look like the following::
  146
+might look like the following:
  147
+
  148
+.. code-block:: html+django
140 149
 
141 150
     {% extends "base.html" %}
142 151
 
@@ -159,8 +168,6 @@ consider some of the common ways you might customize and extend generic views.
159 168
 Making "friendly" template contexts
160 169
 -----------------------------------
161 170
 
162  
-.. highlightlang:: python
163  
-
164 171
 You might have noticed that our sample publisher list template stores all the
165 172
 publishers in a variable named ``object_list``. While this works just fine, it
166 173
 isn't all that "friendly" to template authors: they have to "just know" that
@@ -221,10 +228,10 @@ template, but you can override it to send more::
221 228
 
222 229
 .. note::
223 230
 
224  
-    Generally, get_context_data will merge the context data of all parent
  231
+    Generally, ``get_context_data`` will merge the context data of all parent
225 232
     classes with those of the current class. To preserve this behavior in your
226 233
     own classes where you want to alter the context, you should be sure to call
227  
-    get_context_data on the super class. When no two classes try to define the
  234
+    ``get_context_data`` on the super class. When no two classes try to define the
228 235
     same key, this will give the expected results. However if any class
229 236
     attempts to override a key after parent classes have set it (after the call
230 237
     to super), any children of that class will also need to explicitly set it
@@ -369,7 +376,7 @@ Performing extra work
369 376
 The last common pattern we'll look at involves doing some extra work before
370 377
 or after calling the generic view.
371 378
 
372  
-Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
  379
+Imagine we had a ``last_accessed`` field on our ``Author`` model that we were
373 380
 using to keep track of the last time anybody looked at that author::
374 381
 
375 382
     # models.py
@@ -379,7 +386,7 @@ using to keep track of the last time anybody looked at that author::
379 386
         salutation = models.CharField(max_length=10)
380 387
         name = models.CharField(max_length=200)
381 388
         email = models.EmailField()
382  
-        headshot = models.ImageField(upload_to='/tmp')
  389
+        headshot = models.ImageField(upload_to='author_headshots')
383 390
         last_accessed = models.DateTimeField()
384 391
 
385 392
 The generic ``DetailView`` class, of course, wouldn't know anything about this
5  docs/topics/class-based-views/generic-editing.txt
@@ -190,8 +190,8 @@ the foreign key relation to the model::
190 190
 
191 191
         # ...
192 192
 
193  
-In the view, ensure that you exclude ``created_by`` in the list of fields to
194  
-edit, and override
  193
+In the view, ensure that you don't include ``created_by`` in the list of fields
  194
+to edit, and override
195 195
 :meth:`~django.views.generic.edit.ModelFormMixin.form_valid()` to add the user::
196 196
 
197 197
     # views.py
@@ -256,3 +256,4 @@ works for AJAX requests as well as 'normal' form POSTs::
256 256
 
257 257
     class AuthorCreate(AjaxableResponseMixin, CreateView):
258 258
         model = Author
  259
+        fields = ['name']
2  docs/topics/class-based-views/intro.txt
@@ -208,7 +208,7 @@ A similar class-based view might look like::
208 208
 
209 209
         def get(self, request, *args, **kwargs):
210 210
             form = self.form_class(initial=self.initial)
211  
-            return render(request,  self.template_name, {'form': form})
  211
+            return render(request, self.template_name, {'form': form})
212 212
 
213 213
         def post(self, request, *args, **kwargs):
214 214
             form = self.form_class(request.POST)
102  docs/topics/class-based-views/mixins.txt
@@ -286,12 +286,17 @@ One way to do this is to combine :class:`ListView` with
286 286
 for the paginated list of books can hang off the publisher found as the single
287 287
 object. In order to do this, we need to have two different querysets:
288 288
 
289  
-**Publisher queryset for use in get_object**
290  
-    We'll set that up directly when we call ``get_object()``.
291  
-
292  
-**Book queryset for use by ListView**
293  
-    We'll figure that out ourselves in ``get_queryset()`` so we
294  
-    can take into account the ``Publisher`` we're looking at.
  289
+**``Publisher`` queryset for use in ``get_object``**
  290
+    We'll set the ``model`` attribute on the view and rely on the default
  291
+    implementation of ``get_object()`` to fetch the correct ``Publisher``
  292
+    object.
  293
+
  294
+**``Book`` queryset for use by ``ListView``**
  295
+    The default implementation of ``get_queryset`` uses the ``model`` attribute
  296
+    to construct the queryset. This conflicts with our use of this attribute
  297
+    for ``get_object`` so we'll override that method and have it return
  298
+    the queryset of ``Book`` objects linked to the ``Publisher`` we're looking
  299
+    at.
295 300
 
296 301
 .. note::
297 302
 
@@ -300,7 +305,7 @@ object. In order to do this, we need to have two different querysets:
300 305
     :class:`ListView` will
301 306
     put things in the context data under the value of
302 307
     ``context_object_name`` if it's set, we'll instead explictly
303  
-    ensure the Publisher is in the context data. :class:`ListView`
  308
+    ensure the ``Publisher`` is in the context data. :class:`ListView`
304 309
     will add in the suitable ``page_obj`` and ``paginator`` for us
305 310
     providing we remember to call ``super()``.
306 311
 
@@ -311,31 +316,36 @@ Now we can write a new ``PublisherDetail``::
311 316
     from books.models import Publisher
312 317
 
313 318
     class PublisherDetail(SingleObjectMixin, ListView):
  319
+        model = Publisher  # for SingleObjectMixin.get_object
314 320
         paginate_by = 2
315 321
         template_name = "books/publisher_detail.html"
316 322
 
  323
+        def get(self, request, *args, **kwargs):
  324
+            self.object = self.get_object()
  325
+            return super(PublisherDetail, self).get(request, *args, **kwargs)
  326
+
317 327
         def get_context_data(self, **kwargs):
318  
-            kwargs['publisher'] = self.object
319  
-            return super(PublisherDetail, self).get_context_data(**kwargs)
  328
+            context = super(PublisherDetail, self).get_context_data(**kwargs)
  329
+            context['publisher'] = self.object
  330
+            return context
320 331
 
321 332
         def get_queryset(self):
322  
-            self.object = self.get_object(Publisher.objects.all())
323 333
             return self.object.book_set.all()
324 334
 
325  
-Notice how we set ``self.object`` within ``get_queryset()`` so we
326  
-can use it again later in ``get_context_data()``. If you don't set
327  
-``template_name``, the template will default to the normal
  335
+Notice how we set ``self.object`` within ``get()`` so we
  336
+can use it again later in ``get_context_data()`` and ``get_queryset()``.
  337
+If you don't set ``template_name``, the template will default to the normal
328 338
 :class:`ListView` choice, which in this case would be
329 339
 ``"books/book_list.html"`` because it's a list of books;
330 340
 :class:`ListView` knows nothing about
331 341
 :class:`~django.views.generic.detail.SingleObjectMixin`, so it doesn't have
332  
-any clue this view is anything to do with a Publisher.
333  
-
334  
-.. highlightlang:: html+django
  342
+any clue this view is anything to do with a ``Publisher``.
335 343
 
336 344
 The ``paginate_by`` is deliberately small in the example so you don't
337 345
 have to create lots of books to see the pagination working! Here's the
338  
-template you'd want to use::
  346
+template you'd want to use:
  347
+
  348
+.. code-block: html+django
339 349
 
340 350
     {% extends "base.html" %}
341 351
 
@@ -427,8 +437,6 @@ code so that on ``POST`` the form gets called appropriately.
427 437
     both of the views implement ``get()``, and things would get much more
428 438
     confusing.
429 439
 
430  
-.. highlightlang:: python
431  
-
432 440
 Our new ``AuthorDetail`` looks like this::
433 441
 
434 442
     # CAUTION: you almost certainly do not want to do this.
@@ -451,21 +459,18 @@ Our new ``AuthorDetail`` looks like this::
451 459
         form_class = AuthorInterestForm
452 460
 
453 461
         def get_success_url(self):
454  
-            return reverse(
455  
-                'author-detail',
456  
-                kwargs = {'pk': self.object.pk},
457  
-            )
  462
+            return reverse('author-detail', kwargs={'pk': self.object.pk})
458 463
 
459 464
         def get_context_data(self, **kwargs):
  465
+            context = super(AuthorDetail, self).get_context_data(**kwargs)
460 466
             form_class = self.get_form_class()
461  
-            form = self.get_form(form_class)
462  
-            context = {
463  
-                'form': form
464  
-            }
465  
-            context.update(kwargs)
466  
-            return super(AuthorDetail, self).get_context_data(**context)
  467
+            context['form'] = self.get_form(form_class)
  468
+            return context
467 469
 
468 470
         def post(self, request, *args, **kwargs):
  471
+            if not request.user.is_authenticated():
  472
+                return HttpResponseForbidden()
  473
+            self.object = self.get_object()
469 474
             form_class = self.get_form_class()
470 475
             form = self.get_form(form_class)
471 476
             if form.is_valid():
@@ -474,10 +479,8 @@ Our new ``AuthorDetail`` looks like this::
474 479
                 return self.form_invalid(form)
475 480
 
476 481
         def form_valid(self, form):
477  
-            if not self.request.user.is_authenticated():
478  
-                return HttpResponseForbidden()
479  
-            self.object = self.get_object()
480  
-            # record the interest using the message in form.cleaned_data
  482
+            # Here, we would record the user's interest using the message
  483
+            # passed in form.cleaned_data['message']
481 484
             return super(AuthorDetail, self).form_valid(form)
482 485
 
483 486
 ``get_success_url()`` is just providing somewhere to redirect to,
@@ -530,15 +533,12 @@ write our own ``get_context_data()`` to make the
530 533
         message = forms.CharField()
531 534
 
532 535
     class AuthorDisplay(DetailView):
533  
-
534  
-        queryset = Author.objects.all()
  536
+        model = Author
535 537
 
536 538
         def get_context_data(self, **kwargs):
537  
-            context = {
538  
-                'form': AuthorInterestForm(),
539  
-            }
540  
-            context.update(kwargs)
541  
-            return super(AuthorDisplay, self).get_context_data(**context)
  539
+            context = super(AuthorDisplay, self).get_context_data(**kwargs)
  540
+            context['form'] = AuthorInterestForm()
  541
+            return context
542 542
 
543 543
 Then the ``AuthorInterest`` is a simple :class:`FormView`, but we
544 544
 have to bring in :class:`~django.views.generic.detail.SingleObjectMixin` so we
@@ -558,24 +558,14 @@ template as ``AuthorDisplay`` is using on ``GET``.
558 558
         form_class = AuthorInterestForm
559 559
         model = Author
560 560
 
561  
-        def get_context_data(self, **kwargs):
562  
-            context = {
563  
-                'object': self.get_object(),
564  
-            }
565  
-            return super(AuthorInterest, self).get_context_data(**context)
566  
-
567  
-        def get_success_url(self):
568  
-            return reverse(
569  
-                'author-detail',
570  
-                kwargs = {'pk': self.object.pk},
571  
-            )
572  
-
573  
-        def form_valid(self, form):
574  
-            if not self.request.user.is_authenticated():
  561
+        def post(self, request, *args, **kwargs):
  562
+            if not request.user.is_authenticated():
575 563
                 return HttpResponseForbidden()
576 564
             self.object = self.get_object()
577  
-            # record the interest using the message in form.cleaned_data
578  
-            return super(AuthorInterest, self).form_valid(form)
  565
+            return super(AuthorInterest, self).post(request, *args, **kwargs)
  566
+
  567
+        def get_success_url(self):
  568
+            return reverse('author-detail', kwargs={'pk': self.object.pk})
579 569
 
580 570
 Finally we bring this together in a new ``AuthorDetail`` view. We
581 571
 already know that calling :meth:`~django.views.generic.base.View.as_view()` on

0 notes on commit bd9fbd1

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