Code

Ticket #18033: 18033-wip.diff

File 18033-wip.diff, 142.4 KB (added by claudep, 2 years ago)

Remove function-based generic views - WIP

Line 
1commit 74498e176f616cce409b1b95d7f8d6d61f312f64
2Author: Claude Paroz <claude@2xlibre.net>
3Date:   Sat Mar 31 21:26:00 2012 +0200
4
5    Remove function-based generic views - WIP
6
7diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py
8deleted file mode 100644
9index 59760b4..0000000
10--- a/django/views/generic/create_update.py
11+++ /dev/null
12@@ -1,221 +0,0 @@
13-from django.forms.models import ModelFormMetaclass, ModelForm
14-from django.template import RequestContext, loader
15-from django.http import Http404, HttpResponse, HttpResponseRedirect
16-from django.core.xheaders import populate_xheaders
17-from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
18-from django.utils.translation import ugettext
19-from django.contrib.auth.views import redirect_to_login
20-from django.views.generic import GenericViewError
21-from django.contrib import messages
22-
23-import warnings
24-warnings.warn(
25-    'Function-based generic views have been deprecated; use class-based views instead.',
26-    DeprecationWarning
27-)
28-
29-
30-def apply_extra_context(extra_context, context):
31-    """
32-    Adds items from extra_context dict to context.  If a value in extra_context
33-    is callable, then it is called and the result is added to context.
34-    """
35-    for key, value in extra_context.iteritems():
36-        if callable(value):
37-            context[key] = value()
38-        else:
39-            context[key] = value
40-
41-def get_model_and_form_class(model, form_class):
42-    """
43-    Returns a model and form class based on the model and form_class
44-    parameters that were passed to the generic view.
45-
46-    If ``form_class`` is given then its associated model will be returned along
47-    with ``form_class`` itself.  Otherwise, if ``model`` is given, ``model``
48-    itself will be returned along with a ``ModelForm`` class created from
49-    ``model``.
50-    """
51-    if form_class:
52-        return form_class._meta.model, form_class
53-    if model:
54-        # The inner Meta class fails if model = model is used for some reason.
55-        tmp_model = model
56-        # TODO: we should be able to construct a ModelForm without creating
57-        # and passing in a temporary inner class.
58-        class Meta:
59-            model = tmp_model
60-        class_name = model.__name__ + 'Form'
61-        form_class = ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta})
62-        return model, form_class
63-    raise GenericViewError("Generic view must be called with either a model or"
64-                           " form_class argument.")
65-
66-def redirect(post_save_redirect, obj):
67-    """
68-    Returns a HttpResponseRedirect to ``post_save_redirect``.
69-
70-    ``post_save_redirect`` should be a string, and can contain named string-
71-    substitution place holders of ``obj`` field names.
72-
73-    If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned
74-    by ``get_absolute_url()``.  If ``obj`` has no ``get_absolute_url`` method,
75-    then raise ImproperlyConfigured.
76-
77-    This function is meant to handle the post_save_redirect parameter to the
78-    ``create_object`` and ``update_object`` views.
79-    """
80-    if post_save_redirect:
81-        return HttpResponseRedirect(post_save_redirect % obj.__dict__)
82-    elif hasattr(obj, 'get_absolute_url'):
83-        return HttpResponseRedirect(obj.get_absolute_url())
84-    else:
85-        raise ImproperlyConfigured(
86-            "No URL to redirect to.  Either pass a post_save_redirect"
87-            " parameter to the generic view or define a get_absolute_url"
88-            " method on the Model.")
89-
90-def lookup_object(model, object_id, slug, slug_field):
91-    """
92-    Return the ``model`` object with the passed ``object_id``.  If
93-    ``object_id`` is None, then return the object whose ``slug_field``
94-    equals the passed ``slug``.  If ``slug`` and ``slug_field`` are not passed,
95-    then raise Http404 exception.
96-    """
97-    lookup_kwargs = {}
98-    if object_id:
99-        lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id
100-    elif slug and slug_field:
101-        lookup_kwargs['%s__exact' % slug_field] = slug
102-    else:
103-        raise GenericViewError(
104-            "Generic view must be called with either an object_id or a"
105-            " slug/slug_field.")
106-    try:
107-        return model.objects.get(**lookup_kwargs)
108-    except ObjectDoesNotExist:
109-        raise Http404("No %s found for %s"
110-                      % (model._meta.verbose_name, lookup_kwargs))
111-
112-def create_object(request, model=None, template_name=None,
113-        template_loader=loader, extra_context=None, post_save_redirect=None,
114-        login_required=False, context_processors=None, form_class=None):
115-    """
116-    Generic object-creation function.
117-
118-    Templates: ``<app_label>/<model_name>_form.html``
119-    Context:
120-        form
121-            the form for the object
122-    """
123-    if extra_context is None: extra_context = {}
124-    if login_required and not request.user.is_authenticated():
125-        return redirect_to_login(request.path)
126-
127-    model, form_class = get_model_and_form_class(model, form_class)
128-    if request.method == 'POST':
129-        form = form_class(request.POST, request.FILES)
130-        if form.is_valid():
131-            new_object = form.save()
132-
133-            msg = ugettext("The %(verbose_name)s was created successfully.") %\
134-                                    {"verbose_name": model._meta.verbose_name}
135-            messages.success(request, msg, fail_silently=True)
136-            return redirect(post_save_redirect, new_object)
137-    else:
138-        form = form_class()
139-
140-    # Create the template, context, response
141-    if not template_name:
142-        template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
143-    t = template_loader.get_template(template_name)
144-    c = RequestContext(request, {
145-        'form': form,
146-    }, context_processors)
147-    apply_extra_context(extra_context, c)
148-    return HttpResponse(t.render(c))
149-
150-def update_object(request, model=None, object_id=None, slug=None,
151-        slug_field='slug', template_name=None, template_loader=loader,
152-        extra_context=None, post_save_redirect=None, login_required=False,
153-        context_processors=None, template_object_name='object',
154-        form_class=None):
155-    """
156-    Generic object-update function.
157-
158-    Templates: ``<app_label>/<model_name>_form.html``
159-    Context:
160-        form
161-            the form for the object
162-        object
163-            the original object being edited
164-    """
165-    if extra_context is None: extra_context = {}
166-    if login_required and not request.user.is_authenticated():
167-        return redirect_to_login(request.path)
168-
169-    model, form_class = get_model_and_form_class(model, form_class)
170-    obj = lookup_object(model, object_id, slug, slug_field)
171-
172-    if request.method == 'POST':
173-        form = form_class(request.POST, request.FILES, instance=obj)
174-        if form.is_valid():
175-            obj = form.save()
176-            msg = ugettext("The %(verbose_name)s was updated successfully.") %\
177-                                    {"verbose_name": model._meta.verbose_name}
178-            messages.success(request, msg, fail_silently=True)
179-            return redirect(post_save_redirect, obj)
180-    else:
181-        form = form_class(instance=obj)
182-
183-    if not template_name:
184-        template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
185-    t = template_loader.get_template(template_name)
186-    c = RequestContext(request, {
187-        'form': form,
188-        template_object_name: obj,
189-    }, context_processors)
190-    apply_extra_context(extra_context, c)
191-    response = HttpResponse(t.render(c))
192-    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname))
193-    return response
194-
195-def delete_object(request, model, post_delete_redirect, object_id=None,
196-        slug=None, slug_field='slug', template_name=None,
197-        template_loader=loader, extra_context=None, login_required=False,
198-        context_processors=None, template_object_name='object'):
199-    """
200-    Generic object-delete function.
201-
202-    The given template will be used to confirm deletetion if this view is
203-    fetched using GET; for safty, deletion will only be performed if this
204-    view is POSTed.
205-
206-    Templates: ``<app_label>/<model_name>_confirm_delete.html``
207-    Context:
208-        object
209-            the original object being deleted
210-    """
211-    if extra_context is None: extra_context = {}
212-    if login_required and not request.user.is_authenticated():
213-        return redirect_to_login(request.path)
214-
215-    obj = lookup_object(model, object_id, slug, slug_field)
216-
217-    if request.method == 'POST':
218-        obj.delete()
219-        msg = ugettext("The %(verbose_name)s was deleted.") %\
220-                                    {"verbose_name": model._meta.verbose_name}
221-        messages.success(request, msg, fail_silently=True)
222-        return HttpResponseRedirect(post_delete_redirect)
223-    else:
224-        if not template_name:
225-            template_name = "%s/%s_confirm_delete.html" % (model._meta.app_label, model._meta.object_name.lower())
226-        t = template_loader.get_template(template_name)
227-        c = RequestContext(request, {
228-            template_object_name: obj,
229-        }, context_processors)
230-        apply_extra_context(extra_context, c)
231-        response = HttpResponse(t.render(c))
232-        populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname))
233-        return response
234diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py
235deleted file mode 100644
236index 75094aa..0000000
237--- a/django/views/generic/date_based.py
238+++ /dev/null
239@@ -1,376 +0,0 @@
240-import datetime
241-import time
242-
243-from django.template import loader, RequestContext
244-from django.core.exceptions import ObjectDoesNotExist
245-from django.core.xheaders import populate_xheaders
246-from django.db.models.fields import DateTimeField
247-from django.http import Http404, HttpResponse
248-from django.utils import timezone
249-
250-import warnings
251-warnings.warn(
252-    'Function-based generic views have been deprecated; use class-based views instead.',
253-    DeprecationWarning
254-)
255-
256-
257-def archive_index(request, queryset, date_field, num_latest=15,
258-        template_name=None, template_loader=loader,
259-        extra_context=None, allow_empty=True, context_processors=None,
260-        mimetype=None, allow_future=False, template_object_name='latest'):
261-    """
262-    Generic top-level archive of date-based objects.
263-
264-    Templates: ``<app_label>/<model_name>_archive.html``
265-    Context:
266-        date_list
267-            List of years
268-        latest
269-            Latest N (defaults to 15) objects by date
270-    """
271-    if extra_context is None: extra_context = {}
272-    model = queryset.model
273-    if not allow_future:
274-        queryset = queryset.filter(**{'%s__lte' % date_field: timezone.now()})
275-    date_list = queryset.dates(date_field, 'year')[::-1]
276-    if not date_list and not allow_empty:
277-        raise Http404("No %s available" % model._meta.verbose_name)
278-
279-    if date_list and num_latest:
280-        latest = queryset.order_by('-'+date_field)[:num_latest]
281-    else:
282-        latest = None
283-
284-    if not template_name:
285-        template_name = "%s/%s_archive.html" % (model._meta.app_label, model._meta.object_name.lower())
286-    t = template_loader.get_template(template_name)
287-    c = RequestContext(request, {
288-        'date_list' : date_list,
289-        template_object_name : latest,
290-    }, context_processors)
291-    for key, value in extra_context.items():
292-        if callable(value):
293-            c[key] = value()
294-        else:
295-            c[key] = value
296-    return HttpResponse(t.render(c), mimetype=mimetype)
297-
298-def archive_year(request, year, queryset, date_field, template_name=None,
299-        template_loader=loader, extra_context=None, allow_empty=False,
300-        context_processors=None, template_object_name='object', mimetype=None,
301-        make_object_list=False, allow_future=False):
302-    """
303-    Generic yearly archive view.
304-
305-    Templates: ``<app_label>/<model_name>_archive_year.html``
306-    Context:
307-        date_list
308-            List of months in this year with objects
309-        year
310-            This year
311-        object_list
312-            List of objects published in the given month
313-            (Only available if make_object_list argument is True)
314-    """
315-    if extra_context is None: extra_context = {}
316-    model = queryset.model
317-    now = timezone.now()
318-
319-    lookup_kwargs = {'%s__year' % date_field: year}
320-
321-    # Only bother to check current date if the year isn't in the past and future objects aren't requested.
322-    if int(year) >= now.year and not allow_future:
323-        lookup_kwargs['%s__lte' % date_field] = now
324-    date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month')
325-    if not date_list and not allow_empty:
326-        raise Http404
327-    if make_object_list:
328-        object_list = queryset.filter(**lookup_kwargs)
329-    else:
330-        object_list = []
331-    if not template_name:
332-        template_name = "%s/%s_archive_year.html" % (model._meta.app_label, model._meta.object_name.lower())
333-    t = template_loader.get_template(template_name)
334-    c = RequestContext(request, {
335-        'date_list': date_list,
336-        'year': year,
337-        '%s_list' % template_object_name: object_list,
338-    }, context_processors)
339-    for key, value in extra_context.items():
340-        if callable(value):
341-            c[key] = value()
342-        else:
343-            c[key] = value
344-    return HttpResponse(t.render(c), mimetype=mimetype)
345-
346-def archive_month(request, year, month, queryset, date_field,
347-        month_format='%b', template_name=None, template_loader=loader,
348-        extra_context=None, allow_empty=False, context_processors=None,
349-        template_object_name='object', mimetype=None, allow_future=False):
350-    """
351-    Generic monthly archive view.
352-
353-    Templates: ``<app_label>/<model_name>_archive_month.html``
354-    Context:
355-        date_list:
356-            List of days in this month with objects
357-        month:
358-            (date) this month
359-        next_month:
360-            (date) the first day of the next month, or None if the next month is in the future
361-        previous_month:
362-            (date) the first day of the previous month
363-        object_list:
364-            list of objects published in the given month
365-    """
366-    if extra_context is None: extra_context = {}
367-    try:
368-        tt = time.strptime("%s-%s" % (year, month), '%s-%s' % ('%Y', month_format))
369-        date = datetime.date(*tt[:3])
370-    except ValueError:
371-        raise Http404
372-
373-    model = queryset.model
374-    now = timezone.now()
375-
376-    # Calculate first and last day of month, for use in a date-range lookup.
377-    first_day = date.replace(day=1)
378-    if first_day.month == 12:
379-        last_day = first_day.replace(year=first_day.year + 1, month=1)
380-    else:
381-        last_day = first_day.replace(month=first_day.month + 1)
382-    lookup_kwargs = {
383-        '%s__gte' % date_field: first_day,
384-        '%s__lt' % date_field: last_day,
385-    }
386-
387-    # Only bother to check current date if the month isn't in the past and future objects are requested.
388-    if last_day >= now.date() and not allow_future:
389-        lookup_kwargs['%s__lte' % date_field] = now
390-    object_list = queryset.filter(**lookup_kwargs)
391-    date_list = object_list.dates(date_field, 'day')
392-    if not object_list and not allow_empty:
393-        raise Http404
394-
395-    # Calculate the next month, if applicable.
396-    if allow_future:
397-        next_month = last_day
398-    elif last_day <= datetime.date.today():
399-        next_month = last_day
400-    else:
401-        next_month = None
402-
403-    # Calculate the previous month
404-    if first_day.month == 1:
405-        previous_month = first_day.replace(year=first_day.year-1,month=12)
406-    else:
407-        previous_month = first_day.replace(month=first_day.month-1)
408-
409-    if not template_name:
410-        template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower())
411-    t = template_loader.get_template(template_name)
412-    c = RequestContext(request, {
413-        'date_list': date_list,
414-        '%s_list' % template_object_name: object_list,
415-        'month': date,
416-        'next_month': next_month,
417-        'previous_month': previous_month,
418-    }, context_processors)
419-    for key, value in extra_context.items():
420-        if callable(value):
421-            c[key] = value()
422-        else:
423-            c[key] = value
424-    return HttpResponse(t.render(c), mimetype=mimetype)
425-
426-def archive_week(request, year, week, queryset, date_field,
427-        template_name=None, template_loader=loader,
428-        extra_context=None, allow_empty=True, context_processors=None,
429-        template_object_name='object', mimetype=None, allow_future=False):
430-    """
431-    Generic weekly archive view.
432-
433-    Templates: ``<app_label>/<model_name>_archive_week.html``
434-    Context:
435-        week:
436-            (date) this week
437-        object_list:
438-            list of objects published in the given week
439-    """
440-    if extra_context is None: extra_context = {}
441-    try:
442-        tt = time.strptime(year+'-0-'+week, '%Y-%w-%U')
443-        date = datetime.date(*tt[:3])
444-    except ValueError:
445-        raise Http404
446-
447-    model = queryset.model
448-    now = timezone.now()
449-
450-    # Calculate first and last day of week, for use in a date-range lookup.
451-    first_day = date
452-    last_day = date + datetime.timedelta(days=7)
453-    lookup_kwargs = {
454-        '%s__gte' % date_field: first_day,
455-        '%s__lt' % date_field: last_day,
456-    }
457-
458-    # Only bother to check current date if the week isn't in the past and future objects aren't requested.
459-    if last_day >= now.date() and not allow_future:
460-        lookup_kwargs['%s__lte' % date_field] = now
461-    object_list = queryset.filter(**lookup_kwargs)
462-    if not object_list and not allow_empty:
463-        raise Http404
464-    if not template_name:
465-        template_name = "%s/%s_archive_week.html" % (model._meta.app_label, model._meta.object_name.lower())
466-    t = template_loader.get_template(template_name)
467-    c = RequestContext(request, {
468-        '%s_list' % template_object_name: object_list,
469-        'week': date,
470-    })
471-    for key, value in extra_context.items():
472-        if callable(value):
473-            c[key] = value()
474-        else:
475-            c[key] = value
476-    return HttpResponse(t.render(c), mimetype=mimetype)
477-
478-def archive_day(request, year, month, day, queryset, date_field,
479-        month_format='%b', day_format='%d', template_name=None,
480-        template_loader=loader, extra_context=None, allow_empty=False,
481-        context_processors=None, template_object_name='object',
482-        mimetype=None, allow_future=False):
483-    """
484-    Generic daily archive view.
485-
486-    Templates: ``<app_label>/<model_name>_archive_day.html``
487-    Context:
488-        object_list:
489-            list of objects published that day
490-        day:
491-            (datetime) the day
492-        previous_day
493-            (datetime) the previous day
494-        next_day
495-            (datetime) the next day, or None if the current day is today
496-    """
497-    if extra_context is None: extra_context = {}
498-    try:
499-        tt = time.strptime('%s-%s-%s' % (year, month, day),
500-                           '%s-%s-%s' % ('%Y', month_format, day_format))
501-        date = datetime.date(*tt[:3])
502-    except ValueError:
503-        raise Http404
504-
505-    model = queryset.model
506-    now = timezone.now()
507-
508-    if isinstance(model._meta.get_field(date_field), DateTimeField):
509-        lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
510-    else:
511-        lookup_kwargs = {date_field: date}
512-
513-    # Only bother to check current date if the date isn't in the past and future objects aren't requested.
514-    if date >= now.date() and not allow_future:
515-        lookup_kwargs['%s__lte' % date_field] = now
516-    object_list = queryset.filter(**lookup_kwargs)
517-    if not allow_empty and not object_list:
518-        raise Http404
519-
520-    # Calculate the next day, if applicable.
521-    if allow_future:
522-        next_day = date + datetime.timedelta(days=1)
523-    elif date < datetime.date.today():
524-        next_day = date + datetime.timedelta(days=1)
525-    else:
526-        next_day = None
527-
528-    if not template_name:
529-        template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower())
530-    t = template_loader.get_template(template_name)
531-    c = RequestContext(request, {
532-        '%s_list' % template_object_name: object_list,
533-        'day': date,
534-        'previous_day': date - datetime.timedelta(days=1),
535-        'next_day': next_day,
536-    }, context_processors)
537-    for key, value in extra_context.items():
538-        if callable(value):
539-            c[key] = value()
540-        else:
541-            c[key] = value
542-    return HttpResponse(t.render(c), mimetype=mimetype)
543-
544-def archive_today(request, **kwargs):
545-    """
546-    Generic daily archive view for today. Same as archive_day view.
547-    """
548-    today = datetime.date.today()
549-    kwargs.update({
550-        'year': str(today.year),
551-        'month': today.strftime('%b').lower(),
552-        'day': str(today.day),
553-    })
554-    return archive_day(request, **kwargs)
555-
556-def object_detail(request, year, month, day, queryset, date_field,
557-        month_format='%b', day_format='%d', object_id=None, slug=None,
558-        slug_field='slug', template_name=None, template_name_field=None,
559-        template_loader=loader, extra_context=None, context_processors=None,
560-        template_object_name='object', mimetype=None, allow_future=False):
561-    """
562-    Generic detail view from year/month/day/slug or year/month/day/id structure.
563-
564-    Templates: ``<app_label>/<model_name>_detail.html``
565-    Context:
566-        object:
567-            the object to be detailed
568-    """
569-    if extra_context is None: extra_context = {}
570-    try:
571-        tt = time.strptime('%s-%s-%s' % (year, month, day),
572-                           '%s-%s-%s' % ('%Y', month_format, day_format))
573-        date = datetime.date(*tt[:3])
574-    except ValueError:
575-        raise Http404
576-
577-    model = queryset.model
578-    now = timezone.now()
579-
580-    if isinstance(model._meta.get_field(date_field), DateTimeField):
581-        lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}
582-    else:
583-        lookup_kwargs = {date_field: date}
584-
585-    # Only bother to check current date if the date isn't in the past and future objects aren't requested.
586-    if date >= now.date() and not allow_future:
587-        lookup_kwargs['%s__lte' % date_field] = now
588-    if object_id:
589-        lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id
590-    elif slug and slug_field:
591-        lookup_kwargs['%s__exact' % slug_field] = slug
592-    else:
593-        raise AttributeError("Generic detail view must be called with either an object_id or a slug/slugfield")
594-    try:
595-        obj = queryset.get(**lookup_kwargs)
596-    except ObjectDoesNotExist:
597-        raise Http404("No %s found for" % model._meta.verbose_name)
598-    if not template_name:
599-        template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
600-    if template_name_field:
601-        template_name_list = [getattr(obj, template_name_field), template_name]
602-        t = template_loader.select_template(template_name_list)
603-    else:
604-        t = template_loader.get_template(template_name)
605-    c = RequestContext(request, {
606-        template_object_name: obj,
607-    }, context_processors)
608-    for key, value in extra_context.items():
609-        if callable(value):
610-            c[key] = value()
611-        else:
612-            c[key] = value
613-    response = HttpResponse(t.render(c), mimetype=mimetype)
614-    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
615-    return response
616diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
617deleted file mode 100644
618index 22414ae..0000000
619--- a/django/views/generic/list_detail.py
620+++ /dev/null
621@@ -1,152 +0,0 @@
622-from django.template import loader, RequestContext
623-from django.http import Http404, HttpResponse
624-from django.core.xheaders import populate_xheaders
625-from django.core.paginator import Paginator, InvalidPage
626-from django.core.exceptions import ObjectDoesNotExist
627-
628-import warnings
629-warnings.warn(
630-    'Function-based generic views have been deprecated; use class-based views instead.',
631-    DeprecationWarning
632-)
633-
634-
635-def object_list(request, queryset, paginate_by=None, page=None,
636-        allow_empty=True, template_name=None, template_loader=loader,
637-        extra_context=None, context_processors=None, template_object_name='object',
638-        mimetype=None):
639-    """
640-    Generic list of objects.
641-
642-    Templates: ``<app_label>/<model_name>_list.html``
643-    Context:
644-        object_list
645-            list of objects
646-        is_paginated
647-            are the results paginated?
648-        results_per_page
649-            number of objects per page (if paginated)
650-        has_next
651-            is there a next page?
652-        has_previous
653-            is there a prev page?
654-        page
655-            the current page
656-        next
657-            the next page
658-        previous
659-            the previous page
660-        pages
661-            number of pages, total
662-        hits
663-            number of objects, total
664-        last_on_page
665-            the result number of the last of object in the
666-            object_list (1-indexed)
667-        first_on_page
668-            the result number of the first object in the
669-            object_list (1-indexed)
670-        page_range:
671-            A list of the page numbers (1-indexed).
672-    """
673-    if extra_context is None: extra_context = {}
674-    queryset = queryset._clone()
675-    if paginate_by:
676-        paginator = Paginator(queryset, paginate_by, allow_empty_first_page=allow_empty)
677-        if not page:
678-            page = request.GET.get('page', 1)
679-        try:
680-            page_number = int(page)
681-        except ValueError:
682-            if page == 'last':
683-                page_number = paginator.num_pages
684-            else:
685-                # Page is not 'last', nor can it be converted to an int.
686-                raise Http404
687-        try:
688-            page_obj = paginator.page(page_number)
689-        except InvalidPage:
690-            raise Http404
691-        c = RequestContext(request, {
692-            '%s_list' % template_object_name: page_obj.object_list,
693-            'paginator': paginator,
694-            'page_obj': page_obj,
695-            'is_paginated': page_obj.has_other_pages(),
696-
697-            # Legacy template context stuff. New templates should use page_obj
698-            # to access this instead.
699-            'results_per_page': paginator.per_page,
700-            'has_next': page_obj.has_next(),
701-            'has_previous': page_obj.has_previous(),
702-            'page': page_obj.number,
703-            'next': page_obj.next_page_number(),
704-            'previous': page_obj.previous_page_number(),
705-            'first_on_page': page_obj.start_index(),
706-            'last_on_page': page_obj.end_index(),
707-            'pages': paginator.num_pages,
708-            'hits': paginator.count,
709-            'page_range': paginator.page_range,
710-        }, context_processors)
711-    else:
712-        c = RequestContext(request, {
713-            '%s_list' % template_object_name: queryset,
714-            'paginator': None,
715-            'page_obj': None,
716-            'is_paginated': False,
717-        }, context_processors)
718-        if not allow_empty and len(queryset) == 0:
719-            raise Http404
720-    for key, value in extra_context.items():
721-        if callable(value):
722-            c[key] = value()
723-        else:
724-            c[key] = value
725-    if not template_name:
726-        model = queryset.model
727-        template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
728-    t = template_loader.get_template(template_name)
729-    return HttpResponse(t.render(c), mimetype=mimetype)
730-
731-def object_detail(request, queryset, object_id=None, slug=None,
732-        slug_field='slug', template_name=None, template_name_field=None,
733-        template_loader=loader, extra_context=None,
734-        context_processors=None, template_object_name='object',
735-        mimetype=None):
736-    """
737-    Generic detail of an object.
738-
739-    Templates: ``<app_label>/<model_name>_detail.html``
740-    Context:
741-        object
742-            the object
743-    """
744-    if extra_context is None: extra_context = {}
745-    model = queryset.model
746-    if object_id:
747-        queryset = queryset.filter(pk=object_id)
748-    elif slug and slug_field:
749-        queryset = queryset.filter(**{slug_field: slug})
750-    else:
751-        raise AttributeError("Generic detail view must be called with either an object_id or a slug/slug_field.")
752-    try:
753-        obj = queryset.get()
754-    except ObjectDoesNotExist:
755-        raise Http404("No %s found matching the query" % (model._meta.verbose_name))
756-    if not template_name:
757-        template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
758-    if template_name_field:
759-        template_name_list = [getattr(obj, template_name_field), template_name]
760-        t = template_loader.select_template(template_name_list)
761-    else:
762-        t = template_loader.get_template(template_name)
763-    c = RequestContext(request, {
764-        template_object_name: obj,
765-    }, context_processors)
766-    for key, value in extra_context.items():
767-        if callable(value):
768-            c[key] = value()
769-        else:
770-            c[key] = value
771-    response = HttpResponse(t.render(c), mimetype=mimetype)
772-    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
773-    return response
774diff --git a/django/views/generic/simple.py b/django/views/generic/simple.py
775deleted file mode 100644
776index f63860a..0000000
777--- a/django/views/generic/simple.py
778+++ /dev/null
779@@ -1,68 +0,0 @@
780-from django.template import loader, RequestContext
781-from django.http import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, HttpResponseGone
782-from django.utils.log import getLogger
783-
784-import warnings
785-warnings.warn(
786-    'Function-based generic views have been deprecated; use class-based views instead.',
787-    DeprecationWarning
788-)
789-
790-logger = getLogger('django.request')
791-
792-
793-def direct_to_template(request, template, extra_context=None, mimetype=None, **kwargs):
794-    """
795-    Render a given template with any extra URL parameters in the context as
796-    ``{{ params }}``.
797-    """
798-    if extra_context is None: extra_context = {}
799-    dictionary = {'params': kwargs}
800-    for key, value in extra_context.items():
801-        if callable(value):
802-            dictionary[key] = value()
803-        else:
804-            dictionary[key] = value
805-    c = RequestContext(request, dictionary)
806-    t = loader.get_template(template)
807-    return HttpResponse(t.render(c), content_type=mimetype)
808-
809-def redirect_to(request, url, permanent=True, query_string=False, **kwargs):
810-    """
811-    Redirect to a given URL.
812-
813-    The given url may contain dict-style string formatting, which will be
814-    interpolated against the params in the URL.  For example, to redirect from
815-    ``/foo/<id>/`` to ``/bar/<id>/``, you could use the following URLconf::
816-
817-        urlpatterns = patterns('',
818-            ('^foo/(?P<id>\d+)/$', 'django.views.generic.simple.redirect_to', {'url' : '/bar/%(id)s/'}),
819-        )
820-
821-    If the given url is ``None``, a HttpResponseGone (410) will be issued.
822-
823-    If the ``permanent`` argument is False, then the response will have a 302
824-    HTTP status code. Otherwise, the status code will be 301.
825-
826-    If the ``query_string`` argument is True, then the GET query string
827-    from the request is appended to the URL.
828-
829-    """
830-    args = request.META.get('QUERY_STRING', '')
831-
832-    if url is not None:
833-        if kwargs:
834-            url = url % kwargs
835-
836-        if args and query_string:
837-            url = "%s?%s" % (url, args)
838-
839-        klass = permanent and HttpResponsePermanentRedirect or HttpResponseRedirect
840-        return klass(url)
841-    else:
842-        logger.warning('Gone: %s', request.path,
843-                    extra={
844-                        'status_code': 410,
845-                        'request': request
846-                    })
847-        return HttpResponseGone()
848diff --git a/docs/glossary.txt b/docs/glossary.txt
849index 15776ce..4d0f8b9 100644
850--- a/docs/glossary.txt
851+++ b/docs/glossary.txt
852@@ -16,7 +16,7 @@ Glossary
853         A higher-order :term:`view` function that provides an abstract/generic
854         implementation of a common idiom or pattern found in view development.
855 
856-        See :doc:`/ref/generic-views`.
857+        See :doc:`/ref/class-based-views`.
858 
859     model
860         Models store your application's data.
861diff --git a/docs/index.txt b/docs/index.txt
862index 66c8e73..d596511 100644
863--- a/docs/index.txt
864+++ b/docs/index.txt
865@@ -195,7 +195,6 @@ Other batteries included
866 * :doc:`Unicode in Django <ref/unicode>`
867 * :doc:`Web design helpers <ref/contrib/webdesign>`
868 * :doc:`Validators <ref/validators>`
869-* Function-based generic views (Deprecated) :doc:`Overview<topics/generic-views>` | :doc:`Built-in generic views<ref/generic-views>` | :doc:`Migration guide<topics/generic-views-migration>`
870 
871 The Django open-source project
872 ==============================
873diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt
874index 5223aee..aa3f8f7 100644
875--- a/docs/ref/class-based-views.txt
876+++ b/docs/ref/class-based-views.txt
877@@ -6,13 +6,9 @@ Class-based generic views
878 
879 .. note::
880     Prior to Django 1.3, generic views were implemented as functions. The
881-    function-based implementation has been deprecated in favor of the
882+    function-based implementation has been removed in favor of the
883     class-based approach described here.
884 
885-    For details on the previous generic views implementation,
886-    see the :doc:`topic guide </topics/generic-views>` and
887-    :doc:`detailed reference </ref/generic-views>`.
888-
889 Writing Web applications can be monotonous, because we repeat certain patterns
890 again and again. Django tries to take away some of that monotony at the model
891 and template layers, but Web developers also experience this boredom at the view
892diff --git a/docs/ref/generic-views.txt b/docs/ref/generic-views.txt
893deleted file mode 100644
894index eb65107..0000000
895--- a/docs/ref/generic-views.txt
896+++ /dev/null
897@@ -1,1112 +0,0 @@
898-=============
899-Generic views
900-=============
901-
902-
903-.. versionchanged:: 1.3
904-
905-.. note::
906-
907-    From Django 1.3, function-based generic views have been deprecated in favor
908-    of a class-based approach, described in the class-based views :doc:`topic
909-    guide </topics/class-based-views>` and :doc:`detailed reference
910-    </ref/class-based-views>`.
911-
912-Writing Web applications can be monotonous, because we repeat certain patterns
913-again and again. In Django, the most common of these patterns have been
914-abstracted into "generic views" that let you quickly provide common views of
915-an object without actually needing to write any Python code.
916-
917-A general introduction to generic views can be found in the :doc:`topic guide
918-</topics/generic-views>`.
919-
920-This reference contains details of Django's built-in generic views, along with
921-a list of all keyword arguments that a generic view expects. Remember that
922-arguments may either come from the URL pattern or from the ``extra_context``
923-additional-information dictionary.
924-
925-Most generic views require the ``queryset`` key, which is a ``QuerySet``
926-instance; see :doc:`/topics/db/queries` for more information about ``QuerySet``
927-objects.
928-
929-.. module:: django.views.generic.simple
930-
931-"Simple" generic views
932-======================
933-
934-The ``django.views.generic.simple`` module contains simple views to handle a
935-couple of common cases: rendering a template when no view logic is needed,
936-and issuing a redirect.
937-
938-``django.views.generic.simple.direct_to_template``
939---------------------------------------------------
940-
941-**Description:**
942-
943-Renders a given template, passing it a ``{{ params }}`` template variable,
944-which is a dictionary of the parameters captured in the URL.
945-
946-**Required arguments:**
947-
948-* ``template``: The full name of a template to use.
949-
950-**Optional arguments:**
951-
952-* ``extra_context``: A dictionary of values to add to the template
953-  context. By default, this is an empty dictionary. If a value in the
954-  dictionary is callable, the generic view will call it
955-  just before rendering the template.
956-
957-* ``mimetype``: The MIME type to use for the resulting document. Defaults
958-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
959-
960-**Example:**
961-
962-Given the following URL patterns::
963-
964-    from django.views.generic.simple import direct_to_template
965-
966-    urlpatterns = patterns('',
967-        (r'^foo/$',             direct_to_template, {'template': 'foo_index.html'}),
968-        (r'^foo/(?P<id>\d+)/$', direct_to_template, {'template': 'foo_detail.html'}),
969-    )
970-
971-... a request to ``/foo/`` would render the template ``foo_index.html``, and a
972-request to ``/foo/15/`` would render the ``foo_detail.html`` with a context
973-variable ``{{ params.id }}`` that is set to ``15``.
974-
975-``django.views.generic.simple.redirect_to``
976--------------------------------------------
977-
978-**Description:**
979-
980-Redirects to a given URL.
981-
982-The given URL may contain dictionary-style string formatting, which will be
983-interpolated against the parameters captured in the URL. Because keyword
984-interpolation is *always* done (even if no arguments are passed in), any ``"%"``
985-characters in the URL must be written as ``"%%"`` so that Python will convert
986-them to a single percent sign on output.
987-
988-If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410).
989-
990-**Required arguments:**
991-
992-* ``url``: The URL to redirect to, as a string. Or ``None`` to raise a 410
993-  (Gone) HTTP error.
994-
995-**Optional arguments:**
996-
997-* ``permanent``: Whether the redirect should be permanent. The only
998-  difference here is the HTTP status code returned. If ``True``, then the
999-  redirect will use status code 301. If ``False``, then the redirect will
1000-  use status code 302. By default, ``permanent`` is ``True``.
1001-
1002-* ``query_string``: Whether to pass along the GET query string to
1003-  the new location. If ``True``, then the query string is appended
1004-  to the URL. If ``False``, then the query string is discarded. By
1005-  default, ``query_string`` is ``False``.
1006-
1007-.. versionadded:: 1.3
1008-    The ``query_string`` keyword argument is new in Django 1.3.
1009-
1010-**Example:**
1011-
1012-This example issues a permanent redirect (HTTP status code 301) from
1013-``/foo/<id>/`` to ``/bar/<id>/``::
1014-
1015-    from django.views.generic.simple import redirect_to
1016-
1017-    urlpatterns = patterns('',
1018-        ('^foo/(?P<id>\d+)/$', redirect_to, {'url': '/bar/%(id)s/'}),
1019-    )
1020-
1021-This example issues a non-permanent redirect (HTTP status code 302) from
1022-``/foo/<id>/`` to ``/bar/<id>/``::
1023-
1024-    from django.views.generic.simple import redirect_to
1025-
1026-    urlpatterns = patterns('',
1027-        ('^foo/(?P<id>\d+)/$', redirect_to, {'url': '/bar/%(id)s/', 'permanent': False}),
1028-    )
1029-
1030-This example returns a 410 HTTP error for requests to ``/bar/``::
1031-
1032-    from django.views.generic.simple import redirect_to
1033-
1034-    urlpatterns = patterns('',
1035-        ('^bar/$', redirect_to, {'url': None}),
1036-    )
1037-
1038-This example shows how ``"%"`` characters must be written in the URL in order
1039-to avoid confusion with Python's string formatting markers. If the redirect
1040-string is written as ``"%7Ejacob/"`` (with only a single ``%``), an exception would be raised::
1041-
1042-    from django.views.generic.simple import redirect_to
1043-
1044-    urlpatterns = patterns('',
1045-        ('^bar/$', redirect_to, {'url': '%%7Ejacob.'}),
1046-    )
1047-
1048-.. module:: django.views.generic.date_based
1049-
1050-Date-based generic views
1051-========================
1052-
1053-Date-based generic views (in the module ``django.views.generic.date_based``)
1054-are views for displaying drilldown pages for date-based data.
1055-
1056-``django.views.generic.date_based.archive_index``
1057--------------------------------------------------
1058-
1059-**Description:**
1060-
1061-A top-level index page showing the "latest" objects, by date. Objects with
1062-a date in the *future* are not included unless you set ``allow_future`` to
1063-``True``.
1064-
1065-**Required arguments:**
1066-
1067-* ``queryset``: A ``QuerySet`` of objects for which the archive serves.
1068-
1069-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1070-  the ``QuerySet``'s model that the date-based archive should use to
1071-  determine the objects on the page.
1072-
1073-**Optional arguments:**
1074-
1075-* ``num_latest``: The number of latest objects to send to the template
1076-  context. By default, it's 15.
1077-
1078-* ``template_name``: The full name of a template to use in rendering the
1079-  page. This lets you override the default template name (see below).
1080-
1081-* ``template_loader``: The template loader to use when loading the
1082-  template. By default, it's ``django.template.loader``.
1083-
1084-* ``extra_context``: A dictionary of values to add to the template
1085-  context. By default, this is an empty dictionary. If a value in the
1086-  dictionary is callable, the generic view will call it
1087-  just before rendering the template.
1088-
1089-* ``allow_empty``: A boolean specifying whether to display the page if no
1090-  objects are available. If this is ``False`` and no objects are available,
1091-  the view will raise a 404 instead of displaying an empty page. By
1092-  default, this is ``True``.
1093-
1094-* ``context_processors``: A list of template-context processors to apply to
1095-  the view's template.
1096-
1097-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1098-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1099-
1100-* ``allow_future``: A boolean specifying whether to include "future"
1101-  objects on this page, where "future" means objects in which the field
1102-  specified in ``date_field`` is greater than the current date/time. By
1103-  default, this is ``False``.
1104-
1105-* ``template_object_name``: Designates the name of the template variable
1106-  to use in the template context. By default, this is ``'latest'``.
1107-
1108-**Template name:**
1109-
1110-If ``template_name`` isn't specified, this view will use the template
1111-``<app_label>/<model_name>_archive.html`` by default, where:
1112-
1113-* ``<model_name>`` is your model's name in all lowercase. For a model
1114-  ``StaffMember``, that'd be ``staffmember``.
1115-
1116-* ``<app_label>`` is the right-most part of the full Python path to
1117-  your model's app. For example, if your model lives in
1118-  ``apps/blog/models.py``, that'd be ``blog``.
1119-
1120-**Template context:**
1121-
1122-In addition to ``extra_context``, the template's context will be:
1123-
1124-* ``date_list``: A ``DateQuerySet`` object containing all years that have
1125-  have objects available according to ``queryset``, represented as
1126-  ``datetime.datetime`` objects. These are ordered in reverse. This is
1127-  equivalent to ``queryset.dates(date_field, 'year')[::-1]``.
1128-
1129-* ``latest``: The ``num_latest`` objects in the system, ordered descending
1130-  by ``date_field``. For example, if ``num_latest`` is ``10``, then
1131-  ``latest`` will be a list of the latest 10 objects in ``queryset``.
1132-
1133-  This variable's name depends on the ``template_object_name`` parameter,
1134-  which is ``'latest'`` by default. If ``template_object_name`` is
1135-  ``'foo'``, this variable's name will be ``foo``.
1136-
1137-``django.views.generic.date_based.archive_year``
1138-------------------------------------------------
1139-
1140-**Description:**
1141-
1142-A yearly archive page showing all available months in a given year. Objects
1143-with a date in the *future* are not displayed unless you set ``allow_future``
1144-to ``True``.
1145-
1146-**Required arguments:**
1147-
1148-* ``year``: The four-digit year for which the archive serves.
1149-
1150-* ``queryset``: A ``QuerySet`` of objects for which the archive serves.
1151-
1152-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1153-  the ``QuerySet``'s model that the date-based archive should use to
1154-  determine the objects on the page.
1155-
1156-**Optional arguments:**
1157-
1158-* ``template_name``: The full name of a template to use in rendering the
1159-  page. This lets you override the default template name (see below).
1160-
1161-* ``template_loader``: The template loader to use when loading the
1162-  template. By default, it's ``django.template.loader``.
1163-
1164-* ``extra_context``: A dictionary of values to add to the template
1165-  context. By default, this is an empty dictionary. If a value in the
1166-  dictionary is callable, the generic view will call it
1167-  just before rendering the template.
1168-
1169-* ``allow_empty``: A boolean specifying whether to display the page if no
1170-  objects are available. If this is ``False`` and no objects are available,
1171-  the view will raise a 404 instead of displaying an empty page. By
1172-  default, this is ``False``.
1173-
1174-* ``context_processors``: A list of template-context processors to apply to
1175-  the view's template.
1176-
1177-* ``template_object_name``:  Designates the name of the template variable
1178-  to use in the template context. By default, this is ``'object'``. The
1179-  view will append ``'_list'`` to the value of this parameter in
1180-  determining the variable's name.
1181-
1182-* ``make_object_list``: A boolean specifying whether to retrieve the full
1183-  list of objects for this year and pass those to the template. If ``True``,
1184-  this list of objects will be made available to the template as
1185-  ``object_list``. (The name ``object_list`` may be different; see the docs
1186-  for ``object_list`` in the "Template context" section below.) By default,
1187-  this is ``False``.
1188-
1189-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1190-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1191-
1192-* ``allow_future``: A boolean specifying whether to include "future"
1193-  objects on this page, where "future" means objects in which the field
1194-  specified in ``date_field`` is greater than the current date/time. By
1195-  default, this is ``False``.
1196-
1197-**Template name:**
1198-
1199-If ``template_name`` isn't specified, this view will use the template
1200-``<app_label>/<model_name>_archive_year.html`` by default.
1201-
1202-**Template context:**
1203-
1204-In addition to ``extra_context``, the template's context will be:
1205-
1206-* ``date_list``: A ``DateQuerySet`` object containing all months that have
1207-  have objects available according to ``queryset``, represented as
1208-  ``datetime.datetime`` objects, in ascending order.
1209-
1210-* ``year``: The given year, as a four-character string.
1211-
1212-* ``object_list``: If the ``make_object_list`` parameter is ``True``, this
1213-  will be set to a list of objects available for the given year, ordered by
1214-  the date field. This variable's name depends on the
1215-  ``template_object_name`` parameter, which is ``'object'`` by default. If
1216-  ``template_object_name`` is ``'foo'``, this variable's name will be
1217-  ``foo_list``.
1218-
1219-  If ``make_object_list`` is ``False``, ``object_list`` will be passed to
1220-  the template as an empty list.
1221-
1222-``django.views.generic.date_based.archive_month``
1223--------------------------------------------------
1224-
1225-**Description:**
1226-
1227-A monthly archive page showing all objects in a given month. Objects with a
1228-date in the *future* are not displayed unless you set ``allow_future`` to
1229-``True``.
1230-
1231-**Required arguments:**
1232-
1233-* ``year``: The four-digit year for which the archive serves (a string).
1234-
1235-* ``month``: The month for which the archive serves, formatted according to
1236-  the ``month_format`` argument.
1237-
1238-* ``queryset``: A ``QuerySet`` of objects for which the archive serves.
1239-
1240-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1241-  the ``QuerySet``'s model that the date-based archive should use to
1242-  determine the objects on the page.
1243-
1244-**Optional arguments:**
1245-
1246-* ``month_format``: A format string that regulates what format the ``month``
1247-  parameter uses. This should be in the syntax accepted by Python's
1248-  :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a
1249-  three-letter month abbreviation. To change it to use numbers, use
1250-  ``"%m"``.
1251-
1252-* ``template_name``: The full name of a template to use in rendering the
1253-  page. This lets you override the default template name (see below).
1254-
1255-* ``template_loader``: The template loader to use when loading the
1256-  template. By default, it's ``django.template.loader``.
1257-
1258-* ``extra_context``: A dictionary of values to add to the template
1259-  context. By default, this is an empty dictionary. If a value in the
1260-  dictionary is callable, the generic view will call it
1261-  just before rendering the template.
1262-
1263-* ``allow_empty``: A boolean specifying whether to display the page if no
1264-  objects are available. If this is ``False`` and no objects are available,
1265-  the view will raise a 404 instead of displaying an empty page. By
1266-  default, this is ``False``.
1267-
1268-* ``context_processors``: A list of template-context processors to apply to
1269-  the view's template.
1270-
1271-* ``template_object_name``:  Designates the name of the template variable
1272-  to use in the template context. By default, this is ``'object'``. The
1273-  view will append ``'_list'`` to the value of this parameter in
1274-  determining the variable's name.
1275-
1276-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1277-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1278-
1279-* ``allow_future``: A boolean specifying whether to include "future"
1280-  objects on this page, where "future" means objects in which the field
1281-  specified in ``date_field`` is greater than the current date/time. By
1282-  default, this is ``False``.
1283-
1284-**Template name:**
1285-
1286-If ``template_name`` isn't specified, this view will use the template
1287-``<app_label>/<model_name>_archive_month.html`` by default.
1288-
1289-**Template context:**
1290-
1291-.. versionadded:: 1.2
1292-   The inclusion of ``date_list`` in the template's context is new.
1293-
1294-In addition to ``extra_context``, the template's context will be:
1295-
1296-* ``date_list``: A ``DateQuerySet`` object containing all days that have
1297-  have objects available in the given month, according to ``queryset``,
1298-  represented as ``datetime.datetime`` objects, in ascending order.
1299-
1300-* ``month``: A ``datetime.date`` object representing the given month.
1301-
1302-* ``next_month``: A ``datetime.date`` object representing the first day of
1303-  the next month. If the next month is in the future, this will be
1304-  ``None``.
1305-
1306-* ``previous_month``: A ``datetime.date`` object representing the first day
1307-  of the previous month. Unlike ``next_month``, this will never be
1308-  ``None``.
1309-
1310-* ``object_list``: A list of objects available for the given month. This
1311-  variable's name depends on the ``template_object_name`` parameter, which
1312-  is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
1313-  this variable's name will be ``foo_list``.
1314-
1315-``django.views.generic.date_based.archive_week``
1316-------------------------------------------------
1317-
1318-**Description:**
1319-
1320-A weekly archive page showing all objects in a given week. Objects with a date
1321-in the *future* are not displayed unless you set ``allow_future`` to ``True``.
1322-
1323-**Required arguments:**
1324-
1325-* ``year``: The four-digit year for which the archive serves (a string).
1326-
1327-* ``week``: The week of the year for which the archive serves (a string).
1328-  Weeks start with Sunday.
1329-
1330-* ``queryset``: A ``QuerySet`` of objects for which the archive serves.
1331-
1332-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1333-  the ``QuerySet``'s model that the date-based archive should use to
1334-  determine the objects on the page.
1335-
1336-**Optional arguments:**
1337-
1338-* ``template_name``: The full name of a template to use in rendering the
1339-  page. This lets you override the default template name (see below).
1340-
1341-* ``template_loader``: The template loader to use when loading the
1342-  template. By default, it's ``django.template.loader``.
1343-
1344-* ``extra_context``: A dictionary of values to add to the template
1345-  context. By default, this is an empty dictionary. If a value in the
1346-  dictionary is callable, the generic view will call it
1347-  just before rendering the template.
1348-
1349-* ``allow_empty``: A boolean specifying whether to display the page if no
1350-  objects are available. If this is ``False`` and no objects are available,
1351-  the view will raise a 404 instead of displaying an empty page. By
1352-  default, this is ``True``.
1353-
1354-* ``context_processors``: A list of template-context processors to apply to
1355-  the view's template.
1356-
1357-* ``template_object_name``:  Designates the name of the template variable
1358-  to use in the template context. By default, this is ``'object'``. The
1359-  view will append ``'_list'`` to the value of this parameter in
1360-  determining the variable's name.
1361-
1362-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1363-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1364-
1365-* ``allow_future``: A boolean specifying whether to include "future"
1366-  objects on this page, where "future" means objects in which the field
1367-  specified in ``date_field`` is greater than the current date/time. By
1368-  default, this is ``False``.
1369-
1370-**Template name:**
1371-
1372-If ``template_name`` isn't specified, this view will use the template
1373-``<app_label>/<model_name>_archive_week.html`` by default.
1374-
1375-**Template context:**
1376-
1377-In addition to ``extra_context``, the template's context will be:
1378-
1379-* ``week``: A ``datetime.date`` object representing the first day of the
1380-  given week.
1381-
1382-* ``object_list``: A list of objects available for the given week. This
1383-  variable's name depends on the ``template_object_name`` parameter, which
1384-  is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
1385-  this variable's name will be ``foo_list``.
1386-
1387-``django.views.generic.date_based.archive_day``
1388------------------------------------------------
1389-
1390-**Description:**
1391-
1392-A day archive page showing all objects in a given day. Days in the future throw
1393-a 404 error, regardless of whether any objects exist for future days, unless
1394-you set ``allow_future`` to ``True``.
1395-
1396-**Required arguments:**
1397-
1398-* ``year``: The four-digit year for which the archive serves (a string).
1399-
1400-* ``month``: The month for which the archive serves, formatted according to
1401-  the ``month_format`` argument.
1402-
1403-* ``day``: The day for which the archive serves, formatted according to the
1404-  ``day_format`` argument.
1405-
1406-* ``queryset``: A ``QuerySet`` of objects for which the archive serves.
1407-
1408-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1409-  the ``QuerySet``'s model that the date-based archive should use to
1410-  determine the objects on the page.
1411-
1412-**Optional arguments:**
1413-
1414-* ``month_format``: A format string that regulates what format the ``month``
1415-  parameter uses. This should be in the syntax accepted by Python's
1416-  :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a
1417-  three-letter month abbreviation. To change it to use numbers, use
1418-  ``"%m"``.
1419-
1420-* ``day_format``: Like ``month_format``, but for the ``day`` parameter.
1421-  It defaults to ``"%d"`` (day of the month as a decimal number, 01-31).
1422-
1423-* ``template_name``: The full name of a template to use in rendering the
1424-  page. This lets you override the default template name (see below).
1425-
1426-* ``template_loader``: The template loader to use when loading the
1427-  template. By default, it's ``django.template.loader``.
1428-
1429-* ``extra_context``: A dictionary of values to add to the template
1430-  context. By default, this is an empty dictionary. If a value in the
1431-  dictionary is callable, the generic view will call it
1432-  just before rendering the template.
1433-
1434-* ``allow_empty``: A boolean specifying whether to display the page if no
1435-  objects are available. If this is ``False`` and no objects are available,
1436-  the view will raise a 404 instead of displaying an empty page. By
1437-  default, this is ``False``.
1438-
1439-* ``context_processors``: A list of template-context processors to apply to
1440-  the view's template.
1441-
1442-* ``template_object_name``:  Designates the name of the template variable
1443-  to use in the template context. By default, this is ``'object'``. The
1444-  view will append ``'_list'`` to the value of this parameter in
1445-  determining the variable's name.
1446-
1447-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1448-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1449-
1450-* ``allow_future``: A boolean specifying whether to include "future"
1451-  objects on this page, where "future" means objects in which the field
1452-  specified in ``date_field`` is greater than the current date/time. By
1453-  default, this is ``False``.
1454-
1455-**Template name:**
1456-
1457-If ``template_name`` isn't specified, this view will use the template
1458-``<app_label>/<model_name>_archive_day.html`` by default.
1459-
1460-**Template context:**
1461-
1462-In addition to ``extra_context``, the template's context will be:
1463-
1464-* ``day``: A ``datetime.date`` object representing the given day.
1465-
1466-* ``next_day``: A ``datetime.date`` object representing the next day. If
1467-  the next day is in the future, this will be ``None``.
1468-
1469-* ``previous_day``: A ``datetime.date`` object representing the previous day.
1470-  Unlike ``next_day``, this will never be ``None``.
1471-
1472-* ``object_list``: A list of objects available for the given day. This
1473-  variable's name depends on the ``template_object_name`` parameter, which
1474-  is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
1475-  this variable's name will be ``foo_list``.
1476-
1477-``django.views.generic.date_based.archive_today``
1478--------------------------------------------------
1479-
1480-**Description:**
1481-
1482-A day archive page showing all objects for *today*. This is exactly the same as
1483-``archive_day``, except the ``year``/``month``/``day`` arguments are not used,
1484-and today's date is used instead.
1485-
1486-``django.views.generic.date_based.object_detail``
1487--------------------------------------------------
1488-
1489-**Description:**
1490-
1491-A page representing an individual object. If the object has a date value in the
1492-future, the view will throw a 404 error by default, unless you set
1493-``allow_future`` to ``True``.
1494-
1495-**Required arguments:**
1496-
1497-* ``year``: The object's four-digit year (a string).
1498-
1499-* ``month``: The object's month , formatted according to the
1500-  ``month_format`` argument.
1501-
1502-* ``day``: The object's day , formatted according to the ``day_format``
1503-  argument.
1504-
1505-* ``queryset``: A ``QuerySet`` that contains the object.
1506-
1507-* ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in
1508-  the ``QuerySet``'s model that the generic view should use to look up the
1509-  object according to ``year``, ``month`` and ``day``.
1510-
1511-* Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.
1512-
1513-  If you provide ``object_id``, it should be the value of the primary-key
1514-  field for the object being displayed on this page.
1515-
1516-  Otherwise, ``slug`` should be the slug of the given object, and
1517-  ``slug_field`` should be the name of the slug field in the ``QuerySet``'s
1518-  model. By default, ``slug_field`` is ``'slug'``.
1519-
1520-**Optional arguments:**
1521-
1522-* ``month_format``: A format string that regulates what format the ``month``
1523-  parameter uses. This should be in the syntax accepted by Python's
1524-  :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a
1525-  three-letter month abbreviation. To change it to use numbers, use
1526-  ``"%m"``.
1527-
1528-* ``day_format``: Like ``month_format``, but for the ``day`` parameter.
1529-  It defaults to ``"%d"`` (day of the month as a decimal number, 01-31).
1530-
1531-* ``template_name``: The full name of a template to use in rendering the
1532-  page. This lets you override the default template name (see below).
1533-
1534-* ``template_name_field``: The name of a field on the object whose value is
1535-  the template name to use. This lets you store template names in the data.
1536-  In other words, if your object has a field ``'the_template'`` that
1537-  contains a string ``'foo.html'``, and you set ``template_name_field`` to
1538-  ``'the_template'``, then the generic view for this object will use the
1539-  template ``'foo.html'``.
1540-
1541-  It's a bit of a brain-bender, but it's useful in some cases.
1542-
1543-* ``template_loader``: The template loader to use when loading the
1544-  template. By default, it's ``django.template.loader``.
1545-
1546-* ``extra_context``: A dictionary of values to add to the template
1547-  context. By default, this is an empty dictionary. If a value in the
1548-  dictionary is callable, the generic view will call it
1549-  just before rendering the template.
1550-
1551-* ``context_processors``: A list of template-context processors to apply to
1552-  the view's template.
1553-
1554-* ``template_object_name``:  Designates the name of the template variable
1555-  to use in the template context. By default, this is ``'object'``.
1556-
1557-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1558-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1559-
1560-* ``allow_future``: A boolean specifying whether to include "future"
1561-  objects on this page, where "future" means objects in which the field
1562-  specified in ``date_field`` is greater than the current date/time. By
1563-  default, this is ``False``.
1564-
1565-**Template name:**
1566-
1567-If ``template_name`` isn't specified, this view will use the template
1568-``<app_label>/<model_name>_detail.html`` by default.
1569-
1570-**Template context:**
1571-
1572-In addition to ``extra_context``, the template's context will be:
1573-
1574-* ``object``: The object. This variable's name depends on the
1575-  ``template_object_name`` parameter, which is ``'object'`` by default. If
1576-  ``template_object_name`` is ``'foo'``, this variable's name will be
1577-  ``foo``.
1578-
1579-.. module:: django.views.generic.list_detail
1580-
1581-List/detail generic views
1582-=========================
1583-
1584-The list-detail generic-view framework (in the
1585-``django.views.generic.list_detail`` module) is similar to the date-based one,
1586-except the former simply has two views: a list of objects and an individual
1587-object page.
1588-
1589-``django.views.generic.list_detail.object_list``
1590-------------------------------------------------
1591-
1592-**Description:**
1593-
1594-A page representing a list of objects.
1595-
1596-**Required arguments:**
1597-
1598-* ``queryset``: A ``QuerySet`` that represents the objects.
1599-
1600-**Optional arguments:**
1601-
1602-* ``paginate_by``: An integer specifying how many objects should be
1603-  displayed per page. If this is given, the view will paginate objects with
1604-  ``paginate_by`` objects per page. The view will expect either a ``page``
1605-  query string parameter (via ``GET``) or a ``page`` variable specified in
1606-  the URLconf. See `Notes on pagination`_ below.
1607-
1608-* ``page``: The current page number, as an integer, or the string
1609-  ``'last'``. This is 1-based. See `Notes on pagination`_ below.
1610-
1611-* ``template_name``: The full name of a template to use in rendering the
1612-  page. This lets you override the default template name (see below).
1613-
1614-* ``template_loader``: The template loader to use when loading the
1615-  template. By default, it's ``django.template.loader``.
1616-
1617-* ``extra_context``: A dictionary of values to add to the template
1618-  context. By default, this is an empty dictionary. If a value in the
1619-  dictionary is callable, the generic view will call it
1620-  just before rendering the template.
1621-
1622-* ``allow_empty``: A boolean specifying whether to display the page if no
1623-  objects are available. If this is ``False`` and no objects are available,
1624-  the view will raise a 404 instead of displaying an empty page. By
1625-  default, this is ``True``.
1626-
1627-* ``context_processors``: A list of template-context processors to apply to
1628-  the view's template.
1629-
1630-* ``template_object_name``:  Designates the name of the template variable
1631-  to use in the template context. By default, this is ``'object'``. The
1632-  view will append ``'_list'`` to the value of this parameter in
1633-  determining the variable's name.
1634-
1635-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1636-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1637-
1638-**Template name:**
1639-
1640-If ``template_name`` isn't specified, this view will use the template
1641-``<app_label>/<model_name>_list.html`` by default.
1642-
1643-**Template context:**
1644-
1645-In addition to ``extra_context``, the template's context will be:
1646-
1647-* ``object_list``: The list of objects. This variable's name depends on the
1648-  ``template_object_name`` parameter, which is ``'object'`` by default. If
1649-  ``template_object_name`` is ``'foo'``, this variable's name will be
1650-  ``foo_list``.
1651-
1652-* ``is_paginated``: A boolean representing whether the results are
1653-  paginated. Specifically, this is set to ``False`` if the number of
1654-  available objects is less than or equal to ``paginate_by``.
1655-
1656-If the results are paginated, the context will contain these extra variables:
1657-
1658-* ``paginator``: An instance of ``django.core.paginator.Paginator``.
1659-
1660-* ``page_obj``: An instance of ``django.core.paginator.Page``.
1661-
1662-Notes on pagination
1663-~~~~~~~~~~~~~~~~~~~
1664-
1665-If ``paginate_by`` is specified, Django will paginate the results. You can
1666-specify the page number in the URL in one of two ways:
1667-
1668-* Use the ``page`` parameter in the URLconf. For example, this is what
1669-  your URLconf might look like::
1670-
1671-    (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
1672-
1673-* Pass the page number via the ``page`` query-string parameter. For
1674-  example, a URL would look like this::
1675-
1676-    /objects/?page=3
1677-
1678-* To loop over all the available page numbers, use the ``page_range``
1679-  variable. You can iterate over the list provided by ``page_range``
1680-  to create a link to every page of results.
1681-
1682-These values and lists are 1-based, not 0-based, so the first page would be
1683-represented as page ``1``.
1684-
1685-For more on pagination, read the :doc:`pagination documentation
1686-</topics/pagination>`.
1687-
1688-As a special case, you are also permitted to use ``last`` as a value for
1689-``page``::
1690-
1691-    /objects/?page=last
1692-
1693-This allows you to access the final page of results without first having to
1694-determine how many pages there are.
1695-
1696-Note that ``page`` *must* be either a valid page number or the value ``last``;
1697-any other value for ``page`` will result in a 404 error.
1698-
1699-``django.views.generic.list_detail.object_detail``
1700---------------------------------------------------
1701-
1702-A page representing an individual object.
1703-
1704-**Description:**
1705-
1706-A page representing an individual object.
1707-
1708-**Required arguments:**
1709-
1710-* ``queryset``: A ``QuerySet`` that contains the object.
1711-
1712-* Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.
1713-
1714-  If you provide ``object_id``, it should be the value of the primary-key
1715-  field for the object being displayed on this page.
1716-
1717-  Otherwise, ``slug`` should be the slug of the given object, and
1718-  ``slug_field`` should be the name of the slug field in the ``QuerySet``'s
1719-  model. By default, ``slug_field`` is ``'slug'``.
1720-
1721-**Optional arguments:**
1722-
1723-* ``template_name``: The full name of a template to use in rendering the
1724-  page. This lets you override the default template name (see below).
1725-
1726-* ``template_name_field``: The name of a field on the object whose value is
1727-  the template name to use. This lets you store template names in the data.
1728-  In other words, if your object has a field ``'the_template'`` that
1729-  contains a string ``'foo.html'``, and you set ``template_name_field`` to
1730-  ``'the_template'``, then the generic view for this object will use the
1731-  template ``'foo.html'``.
1732-
1733-  It's a bit of a brain-bender, but it's useful in some cases.
1734-
1735-* ``template_loader``: The template loader to use when loading the
1736-  template. By default, it's ``django.template.loader``.
1737-
1738-* ``extra_context``: A dictionary of values to add to the template
1739-  context. By default, this is an empty dictionary. If a value in the
1740-  dictionary is callable, the generic view will call it
1741-  just before rendering the template.
1742-
1743-* ``context_processors``: A list of template-context processors to apply to
1744-  the view's template.
1745-
1746-* ``template_object_name``:  Designates the name of the template variable
1747-  to use in the template context. By default, this is ``'object'``.
1748-
1749-* ``mimetype``: The MIME type to use for the resulting document. Defaults
1750-  to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.
1751-
1752-**Template name:**
1753-
1754-If ``template_name`` isn't specified, this view will use the template
1755-``<app_label>/<model_name>_detail.html`` by default.
1756-
1757-**Template context:**
1758-
1759-In addition to ``extra_context``, the template's context will be:
1760-
1761-* ``object``: The object. This variable's name depends on the
1762-  ``template_object_name`` parameter, which is ``'object'`` by default. If
1763-  ``template_object_name`` is ``'foo'``, this variable's name will be
1764-  ``foo``.
1765-
1766-.. module:: django.views.generic.create_update
1767-
1768-Create/update/delete generic views
1769-==================================
1770-
1771-The ``django.views.generic.create_update`` module contains a set of functions
1772-for creating, editing and deleting objects.
1773-
1774-``django.views.generic.create_update.create_object``
1775-----------------------------------------------------
1776-
1777-**Description:**
1778-
1779-A page that displays a form for creating an object, redisplaying the form with
1780-validation errors (if there are any) and saving the object.
1781-
1782-**Required arguments:**
1783-
1784-* Either ``form_class`` or ``model`` is required.
1785-
1786-  If you provide ``form_class``, it should be a ``django.forms.ModelForm``
1787-  subclass. Use this argument when you need to customize the model's form.
1788-  See the :doc:`ModelForm docs </topics/forms/modelforms>` for more
1789-  information.
1790-
1791-  Otherwise, ``model`` should be a Django model class and the form used
1792-  will be a standard ``ModelForm`` for ``model``.
1793-
1794-**Optional arguments:**
1795-
1796-* ``post_save_redirect``: A URL to which the view will redirect after
1797-  saving the object. By default, it's ``object.get_absolute_url()``.
1798-
1799-  ``post_save_redirect`` may contain dictionary string formatting, which
1800-  will be interpolated against the object's field attributes. For example,
1801-  you could use ``post_save_redirect="/polls/%(slug)s/"``.
1802-
1803-* ``login_required``: A boolean that designates whether a user must be
1804-  logged in, in order to see the page and save changes. This hooks into the
1805-  Django :doc:`authentication system </topics/auth>`. By default, this is
1806-  ``False``.
1807-
1808-  If this is ``True``, and a non-logged-in user attempts to visit this page
1809-  or save the form, Django will redirect the request to ``/accounts/login/``.
1810-
1811-* ``template_name``: The full name of a template to use in rendering the
1812-  page. This lets you override the default template name (see below).
1813-
1814-* ``template_loader``: The template loader to use when loading the
1815-  template. By default, it's ``django.template.loader``.
1816-
1817-* ``extra_context``: A dictionary of values to add to the template
1818-  context. By default, this is an empty dictionary. If a value in the
1819-  dictionary is callable, the generic view will call it
1820-  just before rendering the template.
1821-
1822-* ``context_processors``: A list of template-context processors to apply to
1823-  the view's template.
1824-
1825-**Template name:**
1826-
1827-If ``template_name`` isn't specified, this view will use the template
1828-``<app_label>/<model_name>_form.html`` by default.
1829-
1830-**Template context:**
1831-
1832-In addition to ``extra_context``, the template's context will be:
1833-
1834-* ``form``: A ``django.forms.ModelForm`` instance representing the form
1835-  for creating the object. This lets you refer to form fields easily in the
1836-  template system.
1837-
1838-  For example, if the model has two fields, ``name`` and ``address``::
1839-
1840-      <form action="" method="post">
1841-      <p>{{ form.name.label_tag }} {{ form.name }}</p>
1842-      <p>{{ form.address.label_tag }} {{ form.address }}</p>
1843-      </form>
1844-
1845-  See the :doc:`forms documentation </topics/forms/index>` for more
1846-  information about using ``Form`` objects in templates.
1847-
1848-``django.views.generic.create_update.update_object``
1849-----------------------------------------------------
1850-
1851-**Description:**
1852-
1853-A page that displays a form for editing an existing object, redisplaying the
1854-form with validation errors (if there are any) and saving changes to the
1855-object. This uses a form automatically generated from the object's
1856-model class.
1857-
1858-**Required arguments:**
1859-
1860-* Either ``form_class`` or ``model`` is required.
1861-
1862-  If you provide ``form_class``, it should be a ``django.forms.ModelForm``
1863-  subclass. Use this argument when you need to customize the model's form.
1864-  See the :doc:`ModelForm docs </topics/forms/modelforms>` for more
1865-  information.
1866-
1867-  Otherwise, ``model`` should be a Django model class and the form used
1868-  will be a standard ``ModelForm`` for ``model``.
1869-
1870-* Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.
1871-
1872-  If you provide ``object_id``, it should be the value of the primary-key
1873-  field for the object being displayed on this page.
1874-
1875-  Otherwise, ``slug`` should be the slug of the given object, and
1876-  ``slug_field`` should be the name of the slug field in the ``QuerySet``'s
1877-  model. By default, ``slug_field`` is ``'slug'``.
1878-
1879-**Optional arguments:**
1880-
1881-* ``post_save_redirect``: A URL to which the view will redirect after
1882-  saving the object. By default, it's ``object.get_absolute_url()``.
1883-
1884-  ``post_save_redirect`` may contain dictionary string formatting, which
1885-  will be interpolated against the object's field attributes. For example,
1886-  you could use ``post_save_redirect="/polls/%(slug)s/"``.
1887-
1888-* ``login_required``: A boolean that designates whether a user must be
1889-  logged in, in order to see the page and save changes. This hooks into the
1890-  Django :doc:`authentication system </topics/auth>`. By default, this is
1891-  ``False``.
1892-
1893-  If this is ``True``, and a non-logged-in user attempts to visit this page
1894-  or save the form, Django will redirect to :setting:`LOGIN_URL` (which
1895-  defaults to ``/accounts/login/``).
1896-
1897-* ``template_name``: The full name of a template to use in rendering the
1898-  page. This lets you override the default template name (see below).
1899-
1900-* ``template_loader``: The template loader to use when loading the
1901-  template. By default, it's ``django.template.loader``.
1902-
1903-* ``extra_context``: A dictionary of values to add to the template
1904-  context. By default, this is an empty dictionary. If a value in the
1905-  dictionary is callable, the generic view will call it
1906-  just before rendering the template.
1907-
1908-* ``context_processors``: A list of template-context processors to apply to
1909-  the view's template.
1910-
1911-* ``template_object_name``:  Designates the name of the template variable
1912-  to use in the template context. By default, this is ``'object'``.
1913-
1914-**Template name:**
1915-
1916-If ``template_name`` isn't specified, this view will use the template
1917-``<app_label>/<model_name>_form.html`` by default.
1918-
1919-**Template context:**
1920-
1921-In addition to ``extra_context``, the template's context will be:
1922-
1923-* ``form``: A ``django.forms.ModelForm`` instance representing the form
1924-  for editing the object. This lets you refer to form fields easily in the
1925-  template system.
1926-
1927-  For example, if the model has two fields, ``name`` and ``address``::
1928-
1929-      <form action="" method="post">
1930-      <p>{{ form.name.label_tag }} {{ form.name }}</p>
1931-      <p>{{ form.address.label_tag }} {{ form.address }}</p>
1932-      </form>
1933-
1934-  See the :doc:`forms documentation </topics/forms/index>` for more
1935-  information about using ``Form`` objects in templates.
1936-
1937-* ``object``: The original object being edited. This variable's name
1938-  depends on the ``template_object_name`` parameter, which is ``'object'``
1939-  by default. If ``template_object_name`` is ``'foo'``, this variable's
1940-  name will be ``foo``.
1941-
1942-``django.views.generic.create_update.delete_object``
1943-----------------------------------------------------
1944-
1945-**Description:**
1946-
1947-A view that displays a confirmation page and deletes an existing object. The
1948-given object will only be deleted if the request method is ``POST``. If this
1949-view is fetched via ``GET``, it will display a confirmation page that should
1950-contain a form that POSTs to the same URL.
1951-
1952-**Required arguments:**
1953-
1954-* ``model``: The Django model class of the object that the form will
1955-  delete.
1956-
1957-* Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.
1958-
1959-  If you provide ``object_id``, it should be the value of the primary-key
1960-  field for the object being displayed on this page.
1961-
1962-  Otherwise, ``slug`` should be the slug of the given object, and
1963-  ``slug_field`` should be the name of the slug field in the ``QuerySet``'s
1964-  model. By default, ``slug_field`` is ``'slug'``.
1965-
1966-* ``post_delete_redirect``: A URL to which the view will redirect after
1967-  deleting the object.
1968-
1969-**Optional arguments:**
1970-
1971-* ``login_required``: A boolean that designates whether a user must be
1972-  logged in, in order to see the page and save changes. This hooks into the
1973-  Django :doc:`authentication system </topics/auth>`. By default, this is
1974-  ``False``.
1975-
1976-  If this is ``True``, and a non-logged-in user attempts to visit this page
1977-  or save the form, Django will redirect to :setting:`LOGIN_URL` (which
1978-  defaults to ``/accounts/login/``).
1979-
1980-* ``template_name``: The full name of a template to use in rendering the
1981-  page. This lets you override the default template name (see below).
1982-
1983-* ``template_loader``: The template loader to use when loading the
1984-  template. By default, it's ``django.template.loader``.
1985-
1986-* ``extra_context``: A dictionary of values to add to the template
1987-  context. By default, this is an empty dictionary. If a value in the
1988-  dictionary is callable, the generic view will call it
1989-  just before rendering the template.
1990-
1991-* ``context_processors``: A list of template-context processors to apply to
1992-  the view's template.
1993-
1994-* ``template_object_name``:  Designates the name of the template variable
1995-  to use in the template context. By default, this is ``'object'``.
1996-
1997-**Template name:**
1998-
1999-If ``template_name`` isn't specified, this view will use the template
2000-``<app_label>/<model_name>_confirm_delete.html`` by default.
2001-
2002-**Template context:**
2003-
2004-In addition to ``extra_context``, the template's context will be:
2005-
2006-* ``object``: The original object that's about to be deleted. This
2007-  variable's name depends on the ``template_object_name`` parameter, which
2008-  is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,
2009-  this variable's name will be ``foo``.
2010diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
2011index 69e3b7d..805a3af 100644
2012--- a/docs/topics/auth.txt
2013+++ b/docs/topics/auth.txt
2014@@ -1466,19 +1466,6 @@ To limit access to a :doc:`class-based generic view </ref/class-based-views>`,
2015 decorate the :meth:`View.dispatch <django.views.generic.base.View.dispatch>`
2016 method on the class. See :ref:`decorating-class-based-views` for details.
2017 
2018-Function-based generic views
2019-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020-
2021-To limit access to a :doc:`function-based generic view </ref/generic-views>`,
2022-write a thin wrapper around the view, and point your URLconf to your wrapper
2023-instead of the generic view itself. For example::
2024-
2025-    from django.views.generic.date_based import object_detail
2026-
2027-    @login_required
2028-    def limited_object_detail(*args, **kwargs):
2029-        return object_detail(*args, **kwargs)
2030-
2031 .. _permissions:
2032 
2033 Permissions
2034diff --git a/docs/topics/class-based-views.txt b/docs/topics/class-based-views.txt
2035index 8059ed1..c283d03 100644
2036--- a/docs/topics/class-based-views.txt
2037+++ b/docs/topics/class-based-views.txt
2038@@ -6,13 +6,9 @@ Class-based generic views
2039 
2040 .. note::
2041     Prior to Django 1.3, generic views were implemented as functions. The
2042-    function-based implementation has been deprecated in favor of the
2043+    function-based implementation has been removed in favor of the
2044     class-based approach described here.
2045 
2046-    For details on the previous generic views implementation,
2047-    see the :doc:`topic guide </topics/generic-views>` and
2048-    :doc:`detailed reference </ref/generic-views>`.
2049-
2050 Writing Web applications can be monotonous, because we repeat certain patterns
2051 again and again. Django tries to take away some of that monotony at the model
2052 and template layers, but Web developers also experience this boredom at the view
2053diff --git a/docs/topics/generic-views-migration.txt b/docs/topics/generic-views-migration.txt
2054deleted file mode 100644
2055index 0647336..0000000
2056--- a/docs/topics/generic-views-migration.txt
2057+++ /dev/null
2058@@ -1,159 +0,0 @@
2059-======================================
2060-Migrating function-based generic views
2061-======================================
2062-
2063-All the :doc:`function-based generic views</ref/generic-views>`
2064-that existed in Django 1.2 have analogs as :doc:`class-based generic
2065-views</ref/class-based-views>` in Django 1.3. The feature set
2066-exposed in those function-based views can be replicated in a
2067-class-based way.
2068-
2069-How to migrate
2070-==============
2071-
2072-Replace generic views with generic classes
2073-------------------------------------------
2074-
2075-Existing usage of function-based generic views should be replaced with
2076-their class-based analogs:
2077-
2078-====================================================  ====================================================
2079-Old function-based generic view                       New class-based generic view
2080-====================================================  ====================================================
2081-``django.views.generic.simple.direct_to_template``    :class:`django.views.generic.base.TemplateView`
2082-``django.views.generic.simple.redirect_to``           :class:`django.views.generic.base.RedirectView`
2083-``django.views.generic.list_detail.object_list``      :class:`django.views.generic.list.ListView`
2084-``django.views.generic.list_detail.object_detail``    :class:`django.views.generic.detail.DetailView`
2085-``django.views.generic.create_update.create_object``  :class:`django.views.generic.edit.CreateView`
2086-``django.views.generic.create_update.update_object``  :class:`django.views.generic.edit.UpdateView`
2087-``django.views.generic.create_update.delete_object``  :class:`django.views.generic.edit.DeleteView`
2088-``django.views.generic.date_based.archive_index``     :class:`django.views.generic.dates.ArchiveIndexView`
2089-``django.views.generic.date_based.archive_year``      :class:`django.views.generic.dates.YearArchiveView`
2090-``django.views.generic.date_based.archive_month``     :class:`django.views.generic.dates.MonthArchiveView`
2091-``django.views.generic.date_based.archive_week``      :class:`django.views.generic.dates.WeekArchiveView`
2092-``django.views.generic.date_based.archive_day``       :class:`django.views.generic.dates.DayArchiveView`
2093-``django.views.generic.date_based.archive_today``     :class:`django.views.generic.dates.TodayArchiveView`
2094-``django.views.generic.date_based.object_detail``     :class:`django.views.generic.dates.DateDetailView`
2095-====================================================  ====================================================
2096-
2097-To do this, replace the reference to the generic view function with
2098-a ``as_view()`` instantiation of the class-based view. For example,
2099-the old-style ``direct_to_template`` pattern::
2100-
2101-    ('^about/$', direct_to_template, {'template': 'about.html'})
2102-
2103-can be replaced with an instance of
2104-:class:`~django.views.generic.base.TemplateView`::
2105-
2106-    ('^about/$', TemplateView.as_view(template_name='about.html'))
2107-
2108-``template`` argument to ``direct_to_template`` views
2109------------------------------------------------------
2110-
2111-The ``template`` argument to the ``direct_to_template`` view has been renamed
2112-``template_name``. This has been done to maintain consistency with other views.
2113-
2114-``object_id`` argument to detail views
2115---------------------------------------
2116-
2117-The object_id argument to the ``object_detail`` view has been renamed
2118-``pk`` on the :class:`~django.views.generic.detail.DetailView`.
2119-
2120-``template_object_name``
2121-------------------------
2122-
2123-``template_object_name`` has been renamed ``context_object_name``,
2124-reflecting the fact that the context data can be used for purposes
2125-other than template rendering (e.g., to populate JSON output).
2126-
2127-The ``_list`` suffix on list views
2128-----------------------------------
2129-
2130-In a function-based :class:`ListView`, the ``template_object_name``
2131-was appended with the suffix ``'_list'`` to yield the final context
2132-variable name. In a class-based ``ListView``, the
2133-``context_object_name`` is used verbatim. The ``'_list'`` suffix
2134-is only applied when generating a default context object name.
2135-
2136-The context data for ``object_list`` views
2137-------------------------------------------
2138-
2139-The context provided by :class:`~django.views.generic.list.MultipleObjectMixin`
2140-is quite different from that provided by ``object_list``, with most pagination
2141-related variables replaced by a single ``page_obj`` object. The following are no
2142-longer provided:
2143-
2144-* ``first_on_page``
2145-* ``has_next``
2146-* ``has_previous``
2147-* ``hits``
2148-* ``last_on_page``
2149-* ``next``
2150-* ``page_range``
2151-* ``page``
2152-* ``pages``
2153-* ``previous``
2154-* ``results_per_page``
2155-
2156-``extra_context``
2157------------------
2158-
2159-Function-based generic views provided an ``extra_context`` argument
2160-as way to insert extra items into the context at time of rendering.
2161-
2162-Class-based views don't provide an ``extra_context`` argument.
2163-Instead, you subclass the view, overriding :meth:`get_context_data()`.
2164-For example::
2165-
2166-    class MyListView(ListView):
2167-        def get_context_data(self, **kwargs):
2168-            context = super(MyListView, self).get_context_data(**kwargs)
2169-            context.update({
2170-                'foo': 42,
2171-                'bar': 37
2172-            })
2173-            return context
2174-
2175-``post_save_redirect`` argument to create and update views
2176-----------------------------------------------------------
2177-
2178-The ``post_save_redirect`` argument to the create and update views
2179-has been renamed ``success_url`` on the
2180-:class:`~django.views.generic.edit.ModelFormMixin`.
2181-
2182-``mimetype``
2183-------------
2184-
2185-Some function-based generic views provided a ``mimetype`` argument
2186-as way to control the mimetype of the response.
2187-
2188-Class-based views don't provide a ``mimetype`` argument. Instead, you
2189-subclass the view, overriding
2190-:meth:`TemplateResponseMixin.render_to_response()` and pass in arguments for
2191-the TemplateResponse constructor. For example::
2192-
2193-    class MyListView(ListView):
2194-        def render_to_response(self, context, **kwargs):
2195-            return super(MyListView, self).render_to_response(context,
2196-                            content_type='application/json', **kwargs)
2197-
2198-``context_processors``
2199-----------------------
2200-
2201-Some function-based generic views provided a ``context_processors``
2202-argument that could be used to force the use of specialized context
2203-processors when rendering template content.
2204-
2205-Class-based views don't provide a ``context_processors`` argument.
2206-Instead, you subclass the view, overriding
2207-:meth:`TemplateResponseMixin.render_to_response()`, and passing in
2208-a context instance that has been instantiated with the processors
2209-you want to use. For example::
2210-
2211-    class MyListView(ListView):
2212-        def render_to_response(self, context, **kwargs):
2213-            return super(MyListView, self).render_to_response(
2214-                    RequestContext(self.request,
2215-                                   context,
2216-                                   processors=[custom_processor]),
2217-                    **kwargs)
2218diff --git a/docs/topics/generic-views.txt b/docs/topics/generic-views.txt
2219deleted file mode 100644
2220index 77232bc..0000000
2221--- a/docs/topics/generic-views.txt
2222+++ /dev/null
2223@@ -1,511 +0,0 @@
2224-=============
2225-Generic views
2226-=============
2227-
2228-
2229-.. versionchanged:: 1.3
2230-
2231-.. note::
2232-
2233-    From Django 1.3, function-based generic views have been deprecated in favor
2234-    of a class-based approach, described in the class-based views :doc:`topic
2235-    guide </topics/class-based-views>` and :doc:`detailed reference
2236-    </ref/class-based-views>`.
2237-
2238-Writing Web applications can be monotonous, because we repeat certain patterns
2239-again and again. Django tries to take away some of that monotony at the model
2240-and template layers, but Web developers also experience this boredom at the view
2241-level.
2242-
2243-Django's *generic views* were developed to ease that pain. They take certain
2244-common idioms and patterns found in view development and abstract them so that
2245-you can quickly write common views of data without having to write too much
2246-code.
2247-
2248-We can recognize certain common tasks, like displaying a list of objects, and
2249-write code that displays a list of *any* object. Then the model in question can
2250-be passed as an extra argument to the URLconf.
2251-
2252-Django ships with generic views to do the following:
2253-
2254-* Perform common "simple" tasks: redirect to a different page and
2255-  render a given template.
2256-
2257-* Display list and detail pages for a single object. If we were creating an
2258-  application to manage conferences then a ``talk_list`` view and a
2259-  ``registered_user_list`` view would be examples of list views. A single
2260-  talk page is an example of what we call a "detail" view.
2261-
2262-* Present date-based objects in year/month/day archive pages,
2263-  associated detail, and "latest" pages. The Django Weblog's
2264-  (https://www.djangoproject.com/weblog/) year, month, and
2265-  day archives are built with these, as would be a typical
2266-  newspaper's archives.
2267-
2268-* Allow users to create, update, and delete objects -- with or
2269-  without authorization.
2270-
2271-Taken together, these views provide easy interfaces to perform the most common
2272-tasks developers encounter.
2273-
2274-Using generic views
2275-===================
2276-
2277-All of these views are used by creating configuration dictionaries in
2278-your URLconf files and passing those dictionaries as the third member of the
2279-URLconf tuple for a given pattern.
2280-
2281-For example, here's a simple URLconf you could use to present a static "about"
2282-page::
2283-
2284-    from django.conf.urls import patterns, url, include
2285-    from django.views.generic.simple import direct_to_template
2286-
2287-    urlpatterns = patterns('',
2288-        ('^about/$', direct_to_template, {
2289-            'template': 'about.html'
2290-        })
2291-    )
2292-
2293-Though this might seem a bit "magical" at first glance  -- look, a view with no
2294-code! --, actually the ``direct_to_template`` view simply grabs information from
2295-the extra-parameters dictionary and uses that information when rendering the
2296-view.
2297-
2298-Because this generic view -- and all the others -- is a regular view function
2299-like any other, we can reuse it inside our own views. As an example, let's
2300-extend our "about" example to map URLs of the form ``/about/<whatever>/`` to
2301-statically rendered ``about/<whatever>.html``. We'll do this by first modifying
2302-the URLconf to point to a view function:
2303-
2304-.. parsed-literal::
2305-
2306-    from django.conf.urls import patterns, url, include
2307-    from django.views.generic.simple import direct_to_template
2308-    **from books.views import about_pages**
2309-
2310-    urlpatterns = patterns('',
2311-        ('^about/$', direct_to_template, {
2312-            'template': 'about.html'
2313-        }),
2314-        **('^about/(\\w+)/$', about_pages),**
2315-    )
2316-
2317-Next, we'll write the ``about_pages`` view::
2318-
2319-    from django.http import Http404
2320-    from django.template import TemplateDoesNotExist
2321-    from django.views.generic.simple import direct_to_template
2322-
2323-    def about_pages(request, page):
2324-        try:
2325-            return direct_to_template(request, template="about/%s.html" % page)
2326-        except TemplateDoesNotExist:
2327-            raise Http404()
2328-
2329-Here we're treating ``direct_to_template`` like any other function. Since it
2330-returns an ``HttpResponse``, we can simply return it as-is. The only slightly
2331-tricky business here is dealing with missing templates. We don't want a
2332-nonexistent template to cause a server error, so we catch
2333-``TemplateDoesNotExist`` exceptions and return 404 errors instead.
2334-
2335-.. admonition:: Is there a security vulnerability here?
2336-
2337-    Sharp-eyed readers may have noticed a possible security hole: we're
2338-    constructing the template name using interpolated content from the browser
2339-    (``template="about/%s.html" % page``). At first glance, this looks like a
2340-    classic *directory traversal* vulnerability. But is it really?
2341-
2342-    Not exactly. Yes, a maliciously crafted value of ``page`` could cause
2343-    directory traversal, but although ``page`` *is* taken from the request URL,
2344-    not every value will be accepted. The key is in the URLconf: we're using
2345-    the regular expression ``\w+`` to match the ``page`` part of the URL, and
2346-    ``\w`` only accepts letters and numbers. Thus, any malicious characters
2347-    (dots and slashes, here) will be rejected by the URL resolver before they
2348-    reach the view itself.
2349-
2350-Generic views of objects
2351-========================
2352-
2353-The ``direct_to_template`` certainly is useful, but Django's generic views
2354-really shine when it comes to presenting views on your database content. Because
2355-it's such a common task, Django comes with a handful of built-in generic views
2356-that make generating list and detail views of objects incredibly easy.
2357-
2358-Let's take a look at one of these generic views: the "object list" view. We'll
2359-be using these models::
2360-
2361-    # models.py
2362-    from django.db import models
2363-
2364-    class Publisher(models.Model):
2365-        name = models.CharField(max_length=30)
2366-        address = models.CharField(max_length=50)
2367-        city = models.CharField(max_length=60)
2368-        state_province = models.CharField(max_length=30)
2369-        country = models.CharField(max_length=50)
2370-        website = models.URLField()
2371-
2372-        def __unicode__(self):
2373-            return self.name
2374-
2375-        class Meta:
2376-            ordering = ["-name"]
2377-
2378-    class Book(models.Model):
2379-        title = models.CharField(max_length=100)
2380-        authors = models.ManyToManyField('Author')
2381-        publisher = models.ForeignKey(Publisher)
2382-        publication_date = models.DateField()
2383-
2384-To build a list page of all publishers, we'd use a URLconf along these lines::
2385-
2386-    from django.conf.urls import patterns, url, include
2387-    from django.views.generic import list_detail
2388-    from books.models import Publisher
2389-
2390-    publisher_info = {
2391-        "queryset" : Publisher.objects.all(),
2392-    }
2393-
2394-    urlpatterns = patterns('',
2395-        (r'^publishers/$', list_detail.object_list, publisher_info)
2396-    )
2397-
2398-That's all the Python code we need to write. We still need to write a template,
2399-however. We could explicitly tell the ``object_list`` view which template to use
2400-by including a ``template_name`` key in the extra arguments dictionary, but in
2401-the absence of an explicit template Django will infer one from the object's
2402-name. In this case, the inferred template will be
2403-``"books/publisher_list.html"`` -- the "books" part comes from the name of the
2404-app that defines the model, while the "publisher" bit is just the lowercased
2405-version of the model's name.
2406-
2407-.. highlightlang:: html+django
2408-
2409-This template will be rendered against a context containing a variable called
2410-``object_list`` that contains all the publisher objects. A very simple template
2411-might look like the following::
2412-
2413-    {% extends "base.html" %}
2414-
2415-    {% block content %}
2416-        <h2>Publishers</h2>
2417-        <ul>
2418-            {% for publisher in object_list %}
2419-                <li>{{ publisher.name }}</li>
2420-            {% endfor %}
2421-        </ul>
2422-    {% endblock %}
2423-
2424-That's really all there is to it. All the cool features of generic views come
2425-from changing the "info" dictionary passed to the generic view. The
2426-:doc:`generic views reference</ref/generic-views>` documents all the generic
2427-views and all their options in detail; the rest of this document will consider
2428-some of the common ways you might customize and extend generic views.
2429-
2430-Extending generic views
2431-=======================
2432-
2433-.. highlightlang:: python
2434-
2435-There's no question that using generic views can speed up development
2436-substantially. In most projects, however, there comes a moment when the
2437-generic views no longer suffice. Indeed, the most common question asked by new
2438-Django developers is how to make generic views handle a wider array of
2439-situations.
2440-
2441-Luckily, in nearly every one of these cases, there are ways to simply extend
2442-generic views to handle a larger array of use cases. These situations usually
2443-fall into a handful of patterns dealt with in the sections that follow.
2444-
2445-Making "friendly" template contexts
2446------------------------------------
2447-
2448-You might have noticed that our sample publisher list template stores all the
2449-books in a variable named ``object_list``. While this works just fine, it isn't
2450-all that "friendly" to template authors: they have to "just know" that they're
2451-dealing with publishers here. A better name for that variable would be
2452-``publisher_list``; that variable's content is pretty obvious.
2453-
2454-We can change the name of that variable easily with the ``template_object_name``
2455-argument:
2456-
2457-.. parsed-literal::
2458-
2459-    publisher_info = {
2460-        "queryset" : Publisher.objects.all(),
2461-        **"template_object_name" : "publisher",**
2462-    }
2463-
2464-    urlpatterns = patterns('',
2465-        (r'^publishers/$', list_detail.object_list, publisher_info)
2466-    )
2467-
2468-Providing a useful ``template_object_name`` is always a good idea. Your
2469-coworkers who design templates will thank you.
2470-
2471-Adding extra context
2472---------------------
2473-
2474-Often you simply need to present some extra information beyond that provided by
2475-the generic view. For example, think of showing a list of all the books on each
2476-publisher detail page. The ``object_detail`` generic view provides the
2477-publisher to the context, but it seems there's no way to get additional
2478-information in that template.
2479-
2480-But there is: all generic views take an extra optional parameter,
2481-``extra_context``. This is a dictionary of extra objects that will be added to
2482-the template's context. So, to provide the list of all books on the detail
2483-detail view, we'd use an info dict like this:
2484-
2485-.. parsed-literal::
2486-
2487-    from books.models import Publisher, **Book**
2488-
2489-    publisher_info = {
2490-        "queryset" : Publisher.objects.all(),
2491-        "template_object_name" : "publisher",
2492-        **"extra_context" : {"book_list" : Book.objects.all()}**
2493-    }
2494-
2495-This would populate a ``{{ book_list }}`` variable in the template context.
2496-This pattern can be used to pass any information down into the template for the
2497-generic view. It's very handy.
2498-
2499-However, there's actually a subtle bug here -- can you spot it?
2500-
2501-The problem has to do with when the queries in ``extra_context`` are evaluated.
2502-Because this example puts ``Book.objects.all()`` in the URLconf, it will
2503-be evaluated only once (when the URLconf is first loaded). Once you add or
2504-remove books, you'll notice that the generic view doesn't reflect those
2505-changes until you reload the Web server (see :ref:`caching-and-querysets`
2506-for more information about when QuerySets are cached and evaluated).
2507-
2508-.. note::
2509-
2510-    This problem doesn't apply to the ``queryset`` generic view argument. Since
2511-    Django knows that particular QuerySet should *never* be cached, the generic
2512-    view takes care of clearing the cache when each view is rendered.
2513-
2514-The solution is to use a callback in ``extra_context`` instead of a value. Any
2515-callable (i.e., a function) that's passed to ``extra_context`` will be evaluated
2516-when the view is rendered (instead of only once). You could do this with an
2517-explicitly defined function:
2518-
2519-.. parsed-literal::
2520-
2521-    def get_books():
2522-        return Book.objects.all()
2523-
2524-    publisher_info = {
2525-        "queryset" : Publisher.objects.all(),
2526-        "template_object_name" : "publisher",
2527-        "extra_context" : **{"book_list" : get_books}**
2528-    }
2529-
2530-or you could use a less obvious but shorter version that relies on the fact that
2531-``Book.objects.all`` is itself a callable:
2532-
2533-.. parsed-literal::
2534-
2535-    publisher_info = {
2536-        "queryset" : Publisher.objects.all(),
2537-        "template_object_name" : "publisher",
2538-        "extra_context" : **{"book_list" : Book.objects.all}**
2539-    }
2540-
2541-Notice the lack of parentheses after ``Book.objects.all``; this references
2542-the function without actually calling it (which the generic view will do later).
2543-
2544-Viewing subsets of objects
2545---------------------------
2546-
2547-Now let's take a closer look at this ``queryset`` key we've been using all
2548-along. Most generic views take one of these ``queryset`` arguments -- it's how
2549-the view knows which set of objects to display (see :doc:`/topics/db/queries` for
2550-more information about ``QuerySet`` objects, and see the
2551-:doc:`generic views reference</ref/generic-views>` for the complete details).
2552-
2553-To pick a simple example, we might want to order a list of books by
2554-publication date, with the most recent first:
2555-
2556-.. parsed-literal::
2557-
2558-    book_info = {
2559-        "queryset" : Book.objects.all().order_by("-publication_date"),
2560-    }
2561-
2562-    urlpatterns = patterns('',
2563-        (r'^publishers/$', list_detail.object_list, publisher_info),
2564-        **(r'^books/$', list_detail.object_list, book_info),**
2565-    )
2566-
2567-
2568-That's a pretty simple example, but it illustrates the idea nicely. Of course,
2569-you'll usually want to do more than just reorder objects. If you want to
2570-present a list of books by a particular publisher, you can use the same
2571-technique:
2572-
2573-.. parsed-literal::
2574-
2575-    **acme_books = {**
2576-        **"queryset": Book.objects.filter(publisher__name="Acme Publishing"),**
2577-        **"template_name" : "books/acme_list.html"**
2578-    **}**
2579-
2580-    urlpatterns = patterns('',
2581-        (r'^publishers/$', list_detail.object_list, publisher_info),
2582-        **(r'^books/acme/$', list_detail.object_list, acme_books),**
2583-    )
2584-
2585-Notice that along with a filtered ``queryset``, we're also using a custom
2586-template name. If we didn't, the generic view would use the same template as the
2587-"vanilla" object list, which might not be what we want.
2588-
2589-Also notice that this isn't a very elegant way of doing publisher-specific
2590-books. If we want to add another publisher page, we'd need another handful of
2591-lines in the URLconf, and more than a few publishers would get unreasonable.
2592-We'll deal with this problem in the next section.
2593-
2594-.. note::
2595-
2596-    If you get a 404 when requesting ``/books/acme/``, check to ensure you
2597-    actually have a Publisher with the name 'ACME Publishing'.  Generic
2598-    views have an ``allow_empty`` parameter for this case.  See the
2599-    :doc:`generic views reference</ref/generic-views>` for more details.
2600-
2601-Complex filtering with wrapper functions
2602-----------------------------------------
2603-
2604-Another common need is to filter down the objects given in a list page by some
2605-key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but
2606-what if we wanted to write a view that displayed all the books by some arbitrary
2607-publisher? We can "wrap" the ``object_list`` generic view to avoid writing a lot
2608-of code by hand. As usual, we'll start by writing a URLconf:
2609-
2610-.. parsed-literal::
2611-
2612-    from books.views import books_by_publisher
2613-
2614-    urlpatterns = patterns('',
2615-        (r'^publishers/$', list_detail.object_list, publisher_info),
2616-        **(r'^books/(\\w+)/$', books_by_publisher),**
2617-    )
2618-
2619-Next, we'll write the ``books_by_publisher`` view itself::
2620-
2621-    from django.http import Http404
2622-    from django.views.generic import list_detail
2623-    from books.models import Book, Publisher
2624-
2625-    def books_by_publisher(request, name):
2626-
2627-        # Look up the publisher (and raise a 404 if it can't be found).
2628-        try:
2629-            publisher = Publisher.objects.get(name__iexact=name)
2630-        except Publisher.DoesNotExist:
2631-            raise Http404
2632-
2633-        # Use the object_list view for the heavy lifting.
2634-        return list_detail.object_list(
2635-            request,
2636-            queryset = Book.objects.filter(publisher=publisher),
2637-            template_name = "books/books_by_publisher.html",
2638-            template_object_name = "books",
2639-            extra_context = {"publisher" : publisher}
2640-        )
2641-
2642-This works because there's really nothing special about generic views -- they're
2643-just Python functions. Like any view function, generic views expect a certain
2644-set of arguments and return ``HttpResponse`` objects. Thus, it's incredibly easy
2645-to wrap a small function around a generic view that does additional work before
2646-(or after; see the next section) handing things off to the generic view.
2647-
2648-.. note::
2649-
2650-    Notice that in the preceding example we passed the current publisher being
2651-    displayed in the ``extra_context``. This is usually a good idea in wrappers
2652-    of this nature; it lets the template know which "parent" object is currently
2653-    being browsed.
2654-
2655-Performing extra work
2656----------------------
2657-
2658-The last common pattern we'll look at involves doing some extra work before
2659-or after calling the generic view.
2660-
2661-Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
2662-using to keep track of the last time anybody looked at that author::
2663-
2664-    # models.py
2665-
2666-    class Author(models.Model):
2667-        salutation = models.CharField(max_length=10)
2668-        first_name = models.CharField(max_length=30)
2669-        last_name = models.CharField(max_length=40)
2670-        email = models.EmailField()
2671-        headshot = models.ImageField(upload_to='/tmp')
2672-        last_accessed = models.DateTimeField()
2673-
2674-The generic ``object_detail`` view, of course, wouldn't know anything about this
2675-field, but once again we could easily write a custom view to keep that field
2676-updated.
2677-
2678-First, we'd need to add an author detail bit in the URLconf to point to a
2679-custom view:
2680-
2681-.. parsed-literal::
2682-
2683-    from books.views import author_detail
2684-
2685-    urlpatterns = patterns('',
2686-        #...
2687-        **(r'^authors/(?P<author_id>\\d+)/$', author_detail),**
2688-    )
2689-
2690-Then we'd write our wrapper function::
2691-
2692-    import datetime
2693-    from books.models import Author
2694-    from django.views.generic import list_detail
2695-    from django.shortcuts import get_object_or_404
2696-
2697-    def author_detail(request, author_id):
2698-        # Look up the Author (and raise a 404 if she's not found)
2699-        author = get_object_or_404(Author, pk=author_id)
2700-
2701-        # Record the last accessed date
2702-        author.last_accessed = datetime.datetime.now()
2703-        author.save()
2704-
2705-        # Show the detail page
2706-        return list_detail.object_detail(
2707-            request,
2708-            queryset = Author.objects.all(),
2709-            object_id = author_id,
2710-        )
2711-
2712-.. note::
2713-
2714-    This code won't actually work unless you create a
2715-    ``books/author_detail.html`` template.
2716-
2717-We can use a similar idiom to alter the response returned by the generic view.
2718-If we wanted to provide a downloadable plain-text version of the list of
2719-authors, we could use a view like this::
2720-
2721-    def author_list_plaintext(request):
2722-        response = list_detail.object_list(
2723-            request,
2724-            queryset = Author.objects.all(),
2725-            mimetype = "text/plain",
2726-            template_name = "books/author_list.txt"
2727-        )
2728-        response["Content-Disposition"] = "attachment; filename=authors.txt"
2729-        return response
2730-
2731-This works because the generic views return simple ``HttpResponse`` objects
2732-that can be treated like dictionaries to set HTTP headers. This
2733-``Content-Disposition`` business, by the way, instructs the browser to
2734-download and save the page instead of displaying it in the browser.
2735diff --git a/docs/topics/http/generic-views.txt b/docs/topics/http/generic-views.txt
2736index 15f895e..fdaa27d 100644
2737--- a/docs/topics/http/generic-views.txt
2738+++ b/docs/topics/http/generic-views.txt
2739@@ -2,4 +2,4 @@
2740 Generic views
2741 =============
2742 
2743-See :doc:`/ref/generic-views`.
2744+See :doc:`/ref/class-based-views`.
2745diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
2746index 73c06ca..ee1d4e8 100644
2747--- a/docs/topics/http/urls.txt
2748+++ b/docs/topics/http/urls.txt
2749@@ -416,8 +416,8 @@ Old::
2750     from django.conf.urls import patterns, url, include
2751 
2752     urlpatterns = patterns('',
2753-        (r'^$', 'django.views.generic.date_based.archive_index'),
2754-        (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'django.views.generic.date_based.archive_month'),
2755+        (r'^$', 'myapp.views.app_index'),
2756+        (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'myapp.views.month_display'),
2757         (r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'),
2758     )
2759 
2760@@ -425,9 +425,9 @@ New::
2761 
2762     from django.conf.urls import patterns, url, include
2763 
2764-    urlpatterns = patterns('django.views.generic.date_based',
2765-        (r'^$', 'archive_index'),
2766-        (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'),
2767+    urlpatterns = patterns('myapp.views',
2768+        (r'^$', 'app_index'),
2769+        (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','month_display'),
2770     )
2771 
2772     urlpatterns += patterns('weblog.views',
2773@@ -579,7 +579,7 @@ In this example, for a request to ``/blog/2005/``, Django will call the
2774 
2775     year='2005', foo='bar'
2776 
2777-This technique is used in :doc:`generic views </ref/generic-views>` and in the
2778+This technique is used in the
2779 :doc:`syndication framework </ref/contrib/syndication>` to pass metadata and
2780 options to views.
2781 
2782diff --git a/tests/regressiontests/special_headers/tests.py b/tests/regressiontests/special_headers/tests.py
2783index 4de518c..087bfe9 100644
2784--- a/tests/regressiontests/special_headers/tests.py
2785+++ b/tests/regressiontests/special_headers/tests.py
2786@@ -1,5 +1,3 @@
2787-import warnings
2788-
2789 from django.contrib.auth.models import User
2790 from django.test import TestCase
2791 
2792@@ -8,14 +6,6 @@ class SpecialHeadersTest(TestCase):
2793     fixtures = ['data.xml']
2794     urls = 'regressiontests.special_headers.urls'
2795 
2796-    def setUp(self):
2797-        self.save_warnings_state()
2798-        warnings.filterwarnings('ignore', category=DeprecationWarning,
2799-                                module='django.views.generic.list_detail')
2800-
2801-    def tearDown(self):
2802-        self.restore_warnings_state()
2803-
2804     def test_xheaders(self):
2805         user = User.objects.get(username='super')
2806         response = self.client.get('/special_headers/article/1/')
2807diff --git a/tests/regressiontests/special_headers/urls.py b/tests/regressiontests/special_headers/urls.py
2808index 2e6a305..f7ba141 100644
2809--- a/tests/regressiontests/special_headers/urls.py
2810+++ b/tests/regressiontests/special_headers/urls.py
2811@@ -2,13 +2,12 @@
2812 from __future__ import absolute_import
2813 
2814 from django.conf.urls import patterns
2815-from django.views.generic.list_detail import object_detail
2816 
2817 from . import views
2818 from .models import Article
2819 
2820 urlpatterns = patterns('',
2821-    (r'^special_headers/article/(?P<object_id>\d+)/$', object_detail, {'queryset': Article.objects.all()}),
2822+    (r'^special_headers/article/(?P<object_id>\d+)/$', views.xview_xheaders),
2823     (r'^special_headers/xview/func/$', views.xview_dec(views.xview)),
2824     (r'^special_headers/xview/class/$', views.xview_dec(views.XViewClass.as_view())),
2825 )
2826diff --git a/tests/regressiontests/special_headers/views.py b/tests/regressiontests/special_headers/views.py
2827index ce94036..a8bbd65 100644
2828--- a/tests/regressiontests/special_headers/views.py
2829+++ b/tests/regressiontests/special_headers/views.py
2830@@ -1,14 +1,21 @@
2831-# -*- coding:utf-8 -*-
2832+from django.core.xheaders import populate_xheaders
2833 from django.http import HttpResponse
2834 from django.utils.decorators import decorator_from_middleware
2835 from django.views.generic import View
2836 from django.middleware.doc import XViewMiddleware
2837 
2838+from .models import Article
2839+
2840 xview_dec = decorator_from_middleware(XViewMiddleware)
2841 
2842 def xview(request):
2843     return HttpResponse()
2844 
2845+def xview_xheaders(request, object_id):
2846+    response = HttpResponse()
2847+    populate_xheaders(request, response, Article, 1)
2848+    return response
2849+
2850 class XViewClass(View):
2851     def get(self, request):
2852         return HttpResponse()
2853diff --git a/tests/regressiontests/views/generic_urls.py b/tests/regressiontests/views/generic_urls.py
2854index 40a6c01..5bf929e 100644
2855--- a/tests/regressiontests/views/generic_urls.py
2856+++ b/tests/regressiontests/views/generic_urls.py
2857@@ -2,6 +2,7 @@
2858 from __future__ import absolute_import
2859 
2860 from django.conf.urls import patterns, url
2861+from django.views.generic import RedirectView
2862 
2863 from . import views
2864 from .models import Article, DateArticle, UrlArticle
2865@@ -35,65 +36,12 @@ urlpatterns = patterns('',
2866     url(u'^中文/target/$', 'regressiontests.views.views.index_page'),
2867 )
2868 
2869-# Date-based generic views.
2870-urlpatterns += patterns('django.views.generic.date_based',
2871-    (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$',
2872-        'object_detail',
2873-        dict(slug_field='slug', **date_based_info_dict)),
2874-    (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/allow_future/$',
2875-        'object_detail',
2876-        dict(allow_future=True, slug_field='slug', **date_based_info_dict)),
2877-    (r'^date_based/archive_day/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$',
2878-        'archive_day',
2879-        numeric_days_info_dict),
2880-    (r'^date_based/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',
2881-        'archive_month',
2882-        date_based_info_dict),
2883-    (r'^date_based/datefield/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',
2884-        'archive_month',
2885-        date_based_datefield_info_dict),
2886-)
2887-
2888-# crud generic views.
2889-urlpatterns += patterns('django.views.generic.create_update',
2890-    (r'^create_update/member/create/article/$', 'create_object',
2891-        dict(login_required=True, model=Article)),
2892-    (r'^create_update/create/article/$', 'create_object',
2893-        dict(post_save_redirect='/create_update/view/article/%(slug)s/',
2894-             model=Article)),
2895-    (r'^create_update/update/article/(?P<slug>[-\w]+)/$', 'update_object',
2896-        dict(post_save_redirect='/create_update/view/article/%(slug)s/',
2897-             slug_field='slug', model=Article)),
2898-    (r'^create_update/create_custom/article/$', views.custom_create),
2899-    (r'^create_update/delete/article/(?P<slug>[-\w]+)/$', 'delete_object',
2900-        dict(post_delete_redirect='/create_update/', slug_field='slug',
2901-             model=Article)),
2902-
2903-    # No post_save_redirect and no get_absolute_url on model.
2904-    (r'^create_update/no_redirect/create/article/$', 'create_object',
2905-        dict(model=Article)),
2906-    (r'^create_update/no_redirect/update/article/(?P<slug>[-\w]+)/$',
2907-        'update_object', dict(slug_field='slug', model=Article)),
2908-
2909-    # get_absolute_url on model, but no passed post_save_redirect.
2910-    (r'^create_update/no_url/create/article/$', 'create_object',
2911-        dict(model=UrlArticle)),
2912-    (r'^create_update/no_url/update/article/(?P<slug>[-\w]+)/$',
2913-        'update_object', dict(slug_field='slug', model=UrlArticle)),
2914-)
2915-
2916-urlpatterns += patterns('django.views.generic.list_detail',
2917-    (r'^object_list/page(?P<page>[\w]*)/$', 'object_list', object_list_dict),
2918-    (r'^object_list_no_paginate_by/page(?P<page>[0-9]+)/$', 'object_list',
2919-     object_list_no_paginate_by),
2920-)
2921-
2922 # rediriects, both temporary and permanent, with non-ASCII targets
2923-urlpatterns += patterns('django.views.generic.simple',
2924-    ('^nonascii_redirect/$', 'redirect_to',
2925-        {'url': u'/中文/target/', 'permanent': False}),
2926-    ('^permanent_nonascii_redirect/$', 'redirect_to',
2927-        {'url': u'/中文/target/', 'permanent': True}),
2928+urlpatterns += patterns('',
2929+    ('^nonascii_redirect/$', RedirectView.as_view(
2930+        url=u'/中文/target/', permanent=False)),
2931+    ('^permanent_nonascii_redirect/$', RedirectView.as_view(
2932+        url=u'/中文/target/', permanent=True)),
2933 )
2934 
2935 urlpatterns += patterns('regressiontests.views.views',
2936@@ -107,13 +55,3 @@ urlpatterns += patterns('regressiontests.views.views',
2937     (r'^shortcuts/render/current_app/$', 'render_view_with_current_app'),
2938     (r'^shortcuts/render/current_app_conflict/$', 'render_view_with_current_app_conflict'),
2939 )
2940-
2941-# simple generic views.
2942-urlpatterns += patterns('django.views.generic.simple',
2943-    (r'^simple/redirect_to/$', 'redirect_to', dict(url='/simple/target/')),
2944-    (r'^simple/redirect_to_temp/$', 'redirect_to', dict(url='/simple/target/', permanent=False)),
2945-    (r'^simple/redirect_to_none/$', 'redirect_to', dict(url=None)),
2946-    (r'^simple/redirect_to_arg/(?P<id>\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/')),
2947-    (r'^simple/redirect_to_query/$', 'redirect_to', dict(url='/simple/target/', query_string=True)),
2948-    (r'^simple/redirect_to_arg_and_query/(?P<id>\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/', query_string=True)),
2949-)
2950diff --git a/tests/regressiontests/views/tests/__init__.py b/tests/regressiontests/views/tests/__init__.py
2951index 04537a2..63db5da 100644
2952--- a/tests/regressiontests/views/tests/__init__.py
2953+++ b/tests/regressiontests/views/tests/__init__.py
2954@@ -4,11 +4,6 @@ from .debug import (DebugViewTests, ExceptionReporterTests,
2955     ExceptionReporterTests, PlainTextReportTests, ExceptionReporterFilterTests,
2956     AjaxResponseExceptionReporterFilter)
2957 from .defaults import DefaultsTests
2958-from .generic.create_update import (UpdateDeleteObjectTest, CreateObjectTest,
2959-    PostSaveRedirectTests, NoPostSaveNoAbsoluteUrl, AbsoluteUrlNoPostSave)
2960-from .generic.date_based import MonthArchiveTest, ObjectDetailTest, DayArchiveTests
2961-from .generic.object_list import ObjectListTest
2962-from .generic.simple import RedirectToTest
2963 from .i18n import JsI18NTests, I18NTests, JsI18NTestsMultiPackage
2964 from .shortcuts import ShortcutTests
2965 from .specials import URLHandling
2966diff --git a/tests/regressiontests/views/tests/generic/__init__.py b/tests/regressiontests/views/tests/generic/__init__.py
2967deleted file mode 100644
2968index e69de29..0000000
2969diff --git a/tests/regressiontests/views/tests/generic/create_update.py b/tests/regressiontests/views/tests/generic/create_update.py
2970deleted file mode 100644
2971index 2abcfb4..0000000
2972--- a/tests/regressiontests/views/tests/generic/create_update.py
2973+++ /dev/null
2974@@ -1,255 +0,0 @@
2975-import datetime
2976-import warnings
2977-
2978-from django.test import TestCase
2979-from django.core.exceptions import ImproperlyConfigured
2980-from regressiontests.views.models import Article, UrlArticle
2981-
2982-class CreateObjectTest(TestCase):
2983-    fixtures = ['testdata.json']
2984-    urls = 'regressiontests.views.generic_urls'
2985-
2986-    def setUp(self):
2987-        self.save_warnings_state()
2988-        warnings.filterwarnings('ignore', category=DeprecationWarning,
2989-                                module='django.views.generic.create_update')
2990-
2991-    def tearDown(self):
2992-        self.restore_warnings_state()
2993-
2994-    def test_login_required_view(self):
2995-        """
2996-        Verifies that an unauthenticated user attempting to access a
2997-        login_required view gets redirected to the login page and that
2998-        an authenticated user is let through.
2999-        """
3000-        view_url = '/create_update/member/create/article/'
3001-        response = self.client.get(view_url)
3002-        self.assertRedirects(response, '/accounts/login/?next=%s' % view_url)
3003-        # Now login and try again.
3004-        login = self.client.login(username='testclient', password='password')
3005-        self.assertTrue(login, 'Could not log in')
3006-        response = self.client.get(view_url)
3007-        self.assertEqual(response.status_code, 200)
3008-        self.assertTemplateUsed(response, 'views/article_form.html')
3009-
3010-    def test_create_article_display_page(self):
3011-        """
3012-        Ensures the generic view returned the page and contains a form.
3013-        """
3014-        view_url = '/create_update/create/article/'
3015-        response = self.client.get(view_url)
3016-        self.assertEqual(response.status_code, 200)
3017-        self.assertTemplateUsed(response, 'views/article_form.html')
3018-        if not response.context.get('form'):
3019-            self.fail('No form found in the response.')
3020-
3021-    def test_create_article_with_errors(self):
3022-        """
3023-        POSTs a form that contains validation errors.
3024-        """
3025-        view_url = '/create_update/create/article/'
3026-        num_articles = Article.objects.count()
3027-        response = self.client.post(view_url, {
3028-            'title': 'My First Article',
3029-        })
3030-        self.assertFormError(response, 'form', 'slug', [u'This field is required.'])
3031-        self.assertTemplateUsed(response, 'views/article_form.html')
3032-        self.assertEqual(num_articles, Article.objects.count(),
3033-                         "Number of Articles should not have changed.")
3034-
3035-    def test_create_custom_save_article(self):
3036-        """
3037-        Creates a new article using a custom form class with a save method
3038-        that alters the slug entered.
3039-        """
3040-        view_url = '/create_update/create_custom/article/'
3041-        response = self.client.post(view_url, {
3042-            'title': 'Test Article',
3043-            'slug': 'this-should-get-replaced',
3044-            'author': 1,
3045-            'date_created': datetime.datetime(2007, 6, 25),
3046-        })
3047-        self.assertRedirects(response,
3048-            '/create_update/view/article/some-other-slug/',
3049-            target_status_code=404)
3050-
3051-class UpdateDeleteObjectTest(TestCase):
3052-    fixtures = ['testdata.json']
3053-    urls = 'regressiontests.views.generic_urls'
3054-
3055-    def setUp(self):
3056-        self.save_warnings_state()
3057-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3058-                                module='django.views.generic.create_update')
3059-
3060-    def tearDown(self):
3061-        self.restore_warnings_state()
3062-
3063-    def test_update_object_form_display(self):
3064-        """
3065-        Verifies that the form was created properly and with initial values.
3066-        """
3067-        response = self.client.get('/create_update/update/article/old_article/')
3068-        self.assertTemplateUsed(response, 'views/article_form.html')
3069-        self.assertHTMLEqual(unicode(response.context['form']['title']),
3070-            u'<input id="id_title" type="text" name="title" value="Old Article" maxlength="100" />')
3071-
3072-    def test_update_object(self):
3073-        """
3074-        Verifies the updating of an Article.
3075-        """
3076-        response = self.client.post('/create_update/update/article/old_article/', {
3077-            'title': 'Another Article',
3078-            'slug': 'another-article-slug',
3079-            'author': 1,
3080-            'date_created': datetime.datetime(2007, 6, 25),
3081-        })
3082-        article = Article.objects.get(pk=1)
3083-        self.assertEqual(article.title, "Another Article")
3084-
3085-    def test_delete_object_confirm(self):
3086-        """
3087-        Verifies the confirm deletion page is displayed using a GET.
3088-        """
3089-        response = self.client.get('/create_update/delete/article/old_article/')
3090-        self.assertTemplateUsed(response, 'views/article_confirm_delete.html')
3091-
3092-    def test_delete_object(self):
3093-        """
3094-        Verifies the object actually gets deleted on a POST.
3095-        """
3096-        view_url = '/create_update/delete/article/old_article/'
3097-        response = self.client.post(view_url)
3098-        try:
3099-            Article.objects.get(slug='old_article')
3100-        except Article.DoesNotExist:
3101-            pass
3102-        else:
3103-            self.fail('Object was not deleted.')
3104-
3105-class PostSaveRedirectTests(TestCase):
3106-    """
3107-    Verifies that the views redirect to the correct locations depending on
3108-    if a post_save_redirect was passed and a get_absolute_url method exists
3109-    on the Model.
3110-    """
3111-
3112-    fixtures = ['testdata.json']
3113-    article_model = Article
3114-    urls = 'regressiontests.views.generic_urls'
3115-
3116-    create_url = '/create_update/create/article/'
3117-    update_url = '/create_update/update/article/old_article/'
3118-    delete_url = '/create_update/delete/article/old_article/'
3119-
3120-    create_redirect = '/create_update/view/article/my-first-article/'
3121-    update_redirect = '/create_update/view/article/another-article-slug/'
3122-    delete_redirect = '/create_update/'
3123-
3124-    def setUp(self):
3125-        self.save_warnings_state()
3126-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3127-                                module='django.views.generic.create_update')
3128-
3129-    def tearDown(self):
3130-        self.restore_warnings_state()
3131-
3132-    def test_create_article(self):
3133-        num_articles = self.article_model.objects.count()
3134-        response = self.client.post(self.create_url, {
3135-            'title': 'My First Article',
3136-            'slug': 'my-first-article',
3137-            'author': '1',
3138-            'date_created': datetime.datetime(2007, 6, 25),
3139-        })
3140-        self.assertRedirects(response, self.create_redirect,
3141-                             target_status_code=404)
3142-        self.assertEqual(num_articles + 1, self.article_model.objects.count(),
3143-                         "A new Article should have been created.")
3144-
3145-    def test_update_article(self):
3146-        num_articles = self.article_model.objects.count()
3147-        response = self.client.post(self.update_url, {
3148-            'title': 'Another Article',
3149-            'slug': 'another-article-slug',
3150-            'author': 1,
3151-            'date_created': datetime.datetime(2007, 6, 25),
3152-        })
3153-        self.assertRedirects(response, self.update_redirect,
3154-                             target_status_code=404)
3155-        self.assertEqual(num_articles, self.article_model.objects.count(),
3156-                         "A new Article should not have been created.")
3157-
3158-    def test_delete_article(self):
3159-        num_articles = self.article_model.objects.count()
3160-        response = self.client.post(self.delete_url)
3161-        self.assertRedirects(response, self.delete_redirect,
3162-                             target_status_code=404)
3163-        self.assertEqual(num_articles - 1, self.article_model.objects.count(),
3164-                         "An Article should have been deleted.")
3165-
3166-class NoPostSaveNoAbsoluteUrl(PostSaveRedirectTests):
3167-    """
3168-    Tests that when no post_save_redirect is passed and no get_absolute_url
3169-    method exists on the Model that the view raises an ImproperlyConfigured
3170-    error.
3171-    """
3172-    urls = 'regressiontests.views.generic_urls'
3173-
3174-    create_url = '/create_update/no_redirect/create/article/'
3175-    update_url = '/create_update/no_redirect/update/article/old_article/'
3176-
3177-    def setUp(self):
3178-        self.save_warnings_state()
3179-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3180-                                module='django.views.generic.create_update')
3181-
3182-    def tearDown(self):
3183-        self.restore_warnings_state()
3184-
3185-    def test_create_article(self):
3186-        self.assertRaises(ImproperlyConfigured,
3187-            super(NoPostSaveNoAbsoluteUrl, self).test_create_article)
3188-
3189-    def test_update_article(self):
3190-        self.assertRaises(ImproperlyConfigured,
3191-            super(NoPostSaveNoAbsoluteUrl, self).test_update_article)
3192-
3193-    def test_delete_article(self):
3194-        """
3195-        The delete_object view requires a post_delete_redirect, so skip testing
3196-        here.
3197-        """
3198-        pass
3199-
3200-class AbsoluteUrlNoPostSave(PostSaveRedirectTests):
3201-    """
3202-    Tests that the views redirect to the Model's get_absolute_url when no
3203-    post_save_redirect is passed.
3204-    """
3205-    urls = 'regressiontests.views.generic_urls'
3206-
3207-    # Article model with get_absolute_url method.
3208-    article_model = UrlArticle
3209-
3210-    create_url = '/create_update/no_url/create/article/'
3211-    update_url = '/create_update/no_url/update/article/old_article/'
3212-
3213-    create_redirect = '/urlarticles/my-first-article/'
3214-    update_redirect = '/urlarticles/another-article-slug/'
3215-
3216-    def setUp(self):
3217-        self.save_warnings_state()
3218-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3219-                                module='django.views.generic.create_update')
3220-
3221-    def tearDown(self):
3222-        self.restore_warnings_state()
3223-
3224-    def test_delete_article(self):
3225-        """
3226-        The delete_object view requires a post_delete_redirect, so skip testing
3227-        here.
3228-        """
3229-        pass
3230diff --git a/tests/regressiontests/views/tests/generic/date_based.py b/tests/regressiontests/views/tests/generic/date_based.py
3231deleted file mode 100644
3232index 96555e5..0000000
3233--- a/tests/regressiontests/views/tests/generic/date_based.py
3234+++ /dev/null
3235@@ -1,171 +0,0 @@
3236-# coding: utf-8
3237-import warnings
3238-
3239-from django.test import TestCase
3240-from datetime import datetime, date
3241-from datetime import timedelta
3242-from regressiontests.views.models import Article, Author, DateArticle
3243-
3244-class ObjectDetailTest(TestCase):
3245-    fixtures = ['testdata.json']
3246-    urls = 'regressiontests.views.generic_urls'
3247-
3248-    def setUp(self):
3249-        self.save_warnings_state()
3250-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3251-                                module='django.views.generic.date_based')
3252-        # Correct the date for the current article
3253-        current_article = Article.objects.get(title="Current Article")
3254-        current_article.date_created = datetime.now()
3255-        current_article.save()
3256-
3257-    def tearDown(self):
3258-        self.restore_warnings_state()
3259-
3260-    def test_finds_past(self):
3261-        "date_based.object_detail can view a page in the past"
3262-        response = self.client.get('/date_based/object_detail/2001/01/01/old_article/')
3263-        self.assertEqual(response.status_code, 200)
3264-        self.assertEqual(response.context['object'].title, "Old Article")
3265-
3266-    def test_object_detail_finds_today(self):
3267-        "date_based.object_detail can view a page from today"
3268-        today_url = datetime.now().strftime('%Y/%m/%d')
3269-        response = self.client.get('/date_based/object_detail/%s/current_article/' % today_url)
3270-        self.assertEqual(response.status_code, 200)
3271-        self.assertEqual(response.context['object'].title, "Current Article")
3272-
3273-    def test_object_detail_ignores_future(self):
3274-        "date_based.object_detail can view a page from the future, but only if allowed."
3275-        response = self.client.get('/date_based/object_detail/3000/01/01/future_article/')
3276-        self.assertEqual(response.status_code, 404)
3277-
3278-    def test_object_detail_allowed_future_if_enabled(self):
3279-        "date_based.object_detail can view a page from the future if explicitly allowed."
3280-        response = self.client.get('/date_based/object_detail/3000/01/01/future_article/allow_future/')
3281-        self.assertEqual(response.status_code, 200)
3282-        self.assertEqual(response.context['object'].title, "Future Article")
3283-
3284-class MonthArchiveTest(TestCase):
3285-    urls = 'regressiontests.views.generic_urls'
3286-
3287-    def setUp(self):
3288-        self.save_warnings_state()
3289-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3290-                                module='django.views.generic.date_based')
3291-
3292-    def tearDown(self):
3293-        self.restore_warnings_state()
3294-
3295-    def test_archive_month_includes_only_month(self):
3296-        "Regression for #3031: Archives around Feburary include only one month"
3297-        author = Author(name="John Smith")
3298-        author.save()
3299-
3300-        # 2004 was a leap year, so it should be weird enough to not cheat
3301-        first_second_of_feb = datetime(2004, 2, 1, 0, 0, 1)
3302-        first_second_of_mar = datetime(2004, 3, 1, 0, 0, 1)
3303-        two_seconds = timedelta(0, 2, 0)
3304-        article = Article(title="example", author=author)
3305-
3306-        article.date_created = first_second_of_feb
3307-        article.save()
3308-        response = self.client.get('/date_based/archive_month/2004/02/')
3309-        self.assertEqual(response.status_code, 200)
3310-        self.assertEqual(response.context['next_month'], date(2004, 3, 1))
3311-        self.assertEqual(response.context['previous_month'], date(2004, 1, 1))
3312-
3313-        article.date_created = first_second_of_feb-two_seconds
3314-        article.save()
3315-        response = self.client.get('/date_based/archive_month/2004/02/')
3316-        self.assertEqual(response.status_code, 404)
3317-
3318-        article.date_created = first_second_of_mar-two_seconds
3319-        article.save()
3320-        response = self.client.get('/date_based/archive_month/2004/02/')
3321-        self.assertEqual(response.status_code, 200)
3322-        self.assertEqual(response.context['next_month'], date(2004, 3, 1))
3323-        self.assertEqual(response.context['previous_month'], date(2004, 1, 1))
3324-
3325-        article.date_created = first_second_of_mar
3326-        article.save()
3327-        response = self.client.get('/date_based/archive_month/2004/02/')
3328-        self.assertEqual(response.status_code, 404)
3329-
3330-        article2 = DateArticle(title="example", author=author)
3331-
3332-        article2.date_created = first_second_of_feb.date()
3333-        article2.save()
3334-        response = self.client.get('/date_based/datefield/archive_month/2004/02/')
3335-        self.assertEqual(response.status_code, 200)
3336-        self.assertEqual(response.context['next_month'], date(2004, 3, 1))
3337-        self.assertEqual(response.context['previous_month'], date(2004, 1, 1))
3338-
3339-        article2.date_created = (first_second_of_feb-two_seconds).date()
3340-        article2.save()
3341-        response = self.client.get('/date_based/datefield/archive_month/2004/02/')
3342-        self.assertEqual(response.status_code, 404)
3343-
3344-        article2.date_created = (first_second_of_mar-two_seconds).date()
3345-        article2.save()
3346-        response = self.client.get('/date_based/datefield/archive_month/2004/02/')
3347-        self.assertEqual(response.status_code, 200)
3348-        self.assertEqual(response.context['next_month'], date(2004, 3, 1))
3349-        self.assertEqual(response.context['previous_month'], date(2004, 1, 1))
3350-
3351-        article2.date_created = first_second_of_mar.date()
3352-        article2.save()
3353-        response = self.client.get('/date_based/datefield/archive_month/2004/02/')
3354-        self.assertEqual(response.status_code, 404)
3355-
3356-        now = datetime.now()
3357-        prev_month = now.date().replace(day=1)
3358-        if prev_month.month == 1:
3359-            prev_month = prev_month.replace(year=prev_month.year-1, month=12)
3360-        else:
3361-            prev_month = prev_month.replace(month=prev_month.month-1)
3362-        article2.date_created = now
3363-        article2.save()
3364-        response = self.client.get('/date_based/datefield/archive_month/%s/' % now.strftime('%Y/%m'))
3365-        self.assertEqual(response.status_code, 200)
3366-        self.assertEqual(response.context['next_month'], None)
3367-        self.assertEqual(response.context['previous_month'], prev_month)
3368-       
3369-    def test_archive_month_date_list(self):
3370-        author = Author(name="John Smith")
3371-        author.save()
3372-        date1 = datetime(2010, 1, 1, 0, 0, 0)
3373-        date2 = datetime(2010, 1, 2, 0, 0, 0)
3374-        Article.objects.create(title='example1', author=author, date_created=date1)
3375-        Article.objects.create(title='example2', author=author, date_created=date2)
3376-        response = self.client.get('/date_based/archive_month/2010/1/')
3377-        self.assertEqual(response.status_code, 200)
3378-        self.assertEqual(len(response.context['date_list']), 2)
3379-        self.assertEqual(response.context['date_list'][0], date1)
3380-        # Checks that the same date is not included more than once in the list
3381-        Article.objects.create(title='example2', author=author, date_created=date2)
3382-        response = self.client.get('/date_based/archive_month/2010/1/')
3383-        self.assertEqual(len(response.context['date_list']), 2)
3384-
3385-class DayArchiveTests(TestCase):
3386-    urls = 'regressiontests.views.generic_urls'
3387-
3388-    def setUp(self):
3389-        self.save_warnings_state()
3390-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3391-                                module='django.views.generic.date_based')
3392-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3393-                                module='django.views.generic.create_update')
3394-
3395-    def tearDown(self):
3396-        self.restore_warnings_state()
3397-
3398-    def test_year_month_day_format(self):
3399-        """
3400-        Make sure day views don't get confused with numeric month formats (#7944)
3401-        """
3402-        author = Author.objects.create(name="John Smith")
3403-        article = Article.objects.create(title="example", author=author, date_created=datetime(2004, 1, 21, 0, 0, 1))
3404-        response = self.client.get('/date_based/archive_day/2004/1/21/')
3405-        self.assertEqual(response.status_code, 200)
3406-        self.assertEqual(response.context['object_list'][0], article)
3407diff --git a/tests/regressiontests/views/tests/generic/object_list.py b/tests/regressiontests/views/tests/generic/object_list.py
3408deleted file mode 100644
3409index 3fa871a..0000000
3410--- a/tests/regressiontests/views/tests/generic/object_list.py
3411+++ /dev/null
3412@@ -1,47 +0,0 @@
3413-import warnings
3414-
3415-from django.test import TestCase
3416-
3417-
3418-class ObjectListTest(TestCase):
3419-    fixtures = ['testdata.json']
3420-    urls = 'regressiontests.views.generic_urls'
3421-
3422-    def setUp(self):
3423-        self.save_warnings_state()
3424-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3425-                                module='django.views.generic.list_detail')
3426-
3427-    def tearDown(self):
3428-        self.restore_warnings_state()
3429-
3430-    def check_pagination(self, url, expected_status_code, object_count=None):
3431-        response = self.client.get(url)
3432-        self.assertEqual(response.status_code, expected_status_code)
3433-
3434-        if object_count:
3435-            self.assertEqual(response.context['is_paginated'], True)
3436-            self.assertEqual(len(response.context['page_obj'].object_list),
3437-                             object_count)
3438-
3439-        return response
3440-
3441-    def test_finds_pages(self):
3442-        # Check page count doesn't start at 0.
3443-        self.check_pagination('/object_list/page0/', 404)
3444-
3445-        # Check basic pages.
3446-        self.check_pagination('/object_list/page/', 200, 2)
3447-        self.check_pagination('/object_list/page1/', 200, 2)
3448-        self.check_pagination('/object_list/page2/', 200, 1)
3449-        self.check_pagination('/object_list/page3/', 404)
3450-
3451-        # Check the special "last" page.
3452-        self.check_pagination('/object_list/pagelast/', 200, 1)
3453-        self.check_pagination('/object_list/pagenotlast/', 404)
3454-
3455-    def test_no_paginate_by(self):
3456-        # Ensure that the view isn't paginated by default.
3457-        url = '/object_list_no_paginate_by/page1/'
3458-        response = self.check_pagination(url, 200)
3459-        self.assertEqual(response.context['is_paginated'], False)
3460diff --git a/tests/regressiontests/views/tests/generic/simple.py b/tests/regressiontests/views/tests/generic/simple.py
3461deleted file mode 100644
3462index 7dcf08a..0000000
3463--- a/tests/regressiontests/views/tests/generic/simple.py
3464+++ /dev/null
3465@@ -1,64 +0,0 @@
3466-# coding: utf-8
3467-import warnings
3468-
3469-from django.test import TestCase
3470-
3471-class RedirectToTest(TestCase):
3472-    urls = 'regressiontests.views.generic_urls'
3473-
3474-    def setUp(self):
3475-        self.save_warnings_state()
3476-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3477-                                module='django.views.generic.simple')
3478-
3479-    def tearDown(self):
3480-        self.restore_warnings_state()
3481-
3482-    def test_redirect_to_returns_permanent_redirect(self):
3483-        "simple.redirect_to returns a permanent redirect (301) by default"
3484-        response = self.client.get('/simple/redirect_to/')
3485-        self.assertEqual(response.status_code, 301)
3486-        self.assertEqual('http://testserver/simple/target/', response['Location'])
3487-
3488-    def test_redirect_to_can_return_a_temporary_redirect(self):
3489-        "simple.redirect_to returns a temporary redirect (302) when explicitely asked to"
3490-        response = self.client.get('/simple/redirect_to_temp/')
3491-        self.assertEqual(response.status_code, 302)
3492-        self.assertEqual('http://testserver/simple/target/', response['Location'])
3493-
3494-    def test_redirect_to_on_empty_url_returns_gone(self):
3495-        "simple.redirect_to returns resource gone (410) when given a None url"
3496-        response = self.client.get('/simple/redirect_to_none/')
3497-        self.assertEqual(response.status_code, 410)
3498-
3499-    def test_redirect_to_allows_formatted_url_string(self):
3500-        "simple.redirect_to uses string interpolation on target url for keyword args"
3501-        response = self.client.get('/simple/redirect_to_arg/42/')
3502-        self.assertEqual(response.status_code, 301)
3503-        self.assertEqual('http://testserver/simple/target_arg/42/', response['Location'])
3504-
3505-    def test_redirect_to_allows_query_string_to_be_passed(self):
3506-        "simple.redirect_to configured with query_string=True passes on any query string"
3507-        # the default is to not forward the query string
3508-        response = self.client.get('/simple/redirect_to/?param1=foo&param2=bar')
3509-        self.assertEqual(response.status_code, 301)
3510-        self.assertEqual('http://testserver/simple/target/', response['Location'])
3511-        # views configured with query_string=True however passes the query string along
3512-        response = self.client.get('/simple/redirect_to_query/?param1=foo&param2=bar')
3513-        self.assertEqual(response.status_code, 301)
3514-        self.assertEqual('http://testserver/simple/target/?param1=foo&param2=bar', response['Location'])
3515-
3516-        # Confirm that the contents of the query string are not subject to
3517-        # string interpolation (Refs #17111):
3518-        response = self.client.get('/simple/redirect_to_query/?param1=foo&param2=hist%C3%B3ria')
3519-        self.assertEqual(response.status_code, 301)
3520-        self.assertEqual('http://testserver/simple/target/?param1=foo&param2=hist%C3%B3ria', response['Location'])
3521-        response = self.client.get('/simple/redirect_to_arg_and_query/99/?param1=foo&param2=hist%C3%B3ria')
3522-        self.assertEqual(response.status_code, 301)
3523-        self.assertEqual('http://testserver/simple/target_arg/99/?param1=foo&param2=hist%C3%B3ria', response['Location'])
3524-
3525-    def test_redirect_to_when_meta_contains_no_query_string(self):
3526-        "regression for #16705"
3527-        # we can't use self.client.get because it always sets QUERY_STRING
3528-        response = self.client.request(PATH_INFO='/simple/redirect_to/')
3529-        self.assertEqual(response.status_code, 301)
3530diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py
3531index 24bf6bb..d74ae9d 100644
3532--- a/tests/regressiontests/views/tests/shortcuts.py
3533+++ b/tests/regressiontests/views/tests/shortcuts.py
3534@@ -1,5 +1,3 @@
3535-import warnings
3536-
3537 from django.conf import settings
3538 from django.test import TestCase
3539 
3540@@ -7,10 +5,6 @@ class ShortcutTests(TestCase):
3541     urls = 'regressiontests.views.generic_urls'
3542 
3543     def setUp(self):
3544-        self.save_warnings_state()
3545-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3546-                                module='django.views.generic.simple')
3547-
3548         self.old_STATIC_URL = settings.STATIC_URL
3549         self.old_TEMPLATE_CONTEXT_PROCESSORS = settings.TEMPLATE_CONTEXT_PROCESSORS
3550 
3551@@ -20,9 +14,6 @@ class ShortcutTests(TestCase):
3552         )
3553 
3554     def tearDown(self):
3555-        self.restore_warnings_state()
3556-
3557-    def tearDown(self):
3558         settings.STATIC_URL = self.old_STATIC_URL
3559         settings.TEMPLATE_CONTEXT_PROCESSORS = self.old_TEMPLATE_CONTEXT_PROCESSORS
3560 
3561diff --git a/tests/regressiontests/views/tests/specials.py b/tests/regressiontests/views/tests/specials.py
3562index 7855704..cd8ac5b 100644
3563--- a/tests/regressiontests/views/tests/specials.py
3564+++ b/tests/regressiontests/views/tests/specials.py
3565@@ -1,6 +1,4 @@
3566 # coding: utf-8
3567-import warnings
3568-
3569 from django.test import TestCase
3570 
3571 
3572@@ -11,14 +9,6 @@ class URLHandling(TestCase):
3573     urls = 'regressiontests.views.generic_urls'
3574     redirect_target = "/%E4%B8%AD%E6%96%87/target/"
3575 
3576-    def setUp(self):
3577-        self.save_warnings_state()
3578-        warnings.filterwarnings('ignore', category=DeprecationWarning,
3579-                                module='django.views.generic.simple')
3580-
3581-    def tearDown(self):
3582-        self.restore_warnings_state()
3583-
3584     def test_combining_redirect(self):
3585         """
3586         Tests that redirecting to an IRI, requiring encoding before we use it
3587diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py
3588index 1d17e6e..8e530cd 100644
3589--- a/tests/regressiontests/views/views.py
3590+++ b/tests/regressiontests/views/views.py
3591@@ -21,25 +21,6 @@ def index_page(request):
3592     """Dummy index page"""
3593     return HttpResponse('<html><body>Dummy page</body></html>')
3594 
3595-def custom_create(request):
3596-    """
3597-    Calls create_object generic view with a custom form class.
3598-    """
3599-    class SlugChangingArticleForm(forms.ModelForm):
3600-        """Custom form class to overwrite the slug."""
3601-
3602-        class Meta:
3603-            model = Article
3604-
3605-        def save(self, *args, **kwargs):
3606-            self.instance.slug = 'some-other-slug'
3607-            return super(SlugChangingArticleForm, self).save(*args, **kwargs)
3608-
3609-    from django.views.generic.create_update import create_object
3610-    return create_object(request,
3611-        post_save_redirect='/create_update/view/article/%(slug)s/',
3612-        form_class=SlugChangingArticleForm)
3613-
3614 def raises(request):
3615     # Make sure that a callable that raises an exception in the stack frame's
3616     # local vars won't hijack the technical 500 response. See: