Ticket #18033: 18033-3.diff
File 18033-3.diff, 152.9 KB (added by , 13 years ago) |
---|
-
deleted file django/views/generic/create_update.py
From d6f598b2f93e98573656e29c2df3747633d2ade0 Mon Sep 17 00:00:00 2001 From: Claude Paroz <claude@2xlibre.net> Date: Sat, 31 Mar 2012 21:26:00 +0200 Subject: [PATCH 3/3] Remove function-based generic views --- django/views/generic/create_update.py | 221 ---- django/views/generic/date_based.py | 376 ------- django/views/generic/list_detail.py | 152 --- django/views/generic/simple.py | 68 -- docs/glossary.txt | 2 +- docs/index.txt | 1 - docs/internals/deprecation.txt | 2 +- docs/intro/tutorial04.txt | 2 +- docs/misc/api-stability.txt | 2 +- docs/ref/class-based-views.txt | 6 +- docs/ref/contrib/messages.txt | 4 - docs/ref/contrib/sitemaps.txt | 20 +- docs/ref/generic-views.txt | 1112 -------------------- docs/ref/index.txt | 8 - docs/releases/1.1-alpha-1.txt | 4 +- docs/releases/1.1.txt | 4 +- docs/releases/1.3-alpha-1.txt | 2 +- docs/releases/1.3.txt | 4 +- docs/topics/auth.txt | 13 - docs/topics/class-based-views.txt | 6 +- docs/topics/generic-views-migration.txt | 159 --- docs/topics/generic-views.txt | 511 --------- docs/topics/http/generic-views.txt | 2 +- docs/topics/http/urls.txt | 12 +- docs/topics/index.txt | 9 - tests/regressiontests/special_headers/tests.py | 10 - tests/regressiontests/special_headers/urls.py | 3 +- tests/regressiontests/special_headers/views.py | 9 +- tests/regressiontests/views/generic_urls.py | 74 +-- tests/regressiontests/views/tests/__init__.py | 5 - .../views/tests/generic/create_update.py | 255 ----- .../views/tests/generic/date_based.py | 171 --- .../views/tests/generic/object_list.py | 47 - .../regressiontests/views/tests/generic/simple.py | 64 -- tests/regressiontests/views/tests/shortcuts.py | 10 - tests/regressiontests/views/tests/specials.py | 10 - tests/regressiontests/views/views.py | 19 - 37 files changed, 45 insertions(+), 3334 deletions(-) delete mode 100644 django/views/generic/create_update.py delete mode 100644 django/views/generic/date_based.py delete mode 100644 django/views/generic/list_detail.py delete mode 100644 django/views/generic/simple.py delete mode 100644 docs/ref/generic-views.txt delete mode 100644 docs/topics/generic-views-migration.txt delete mode 100644 docs/topics/generic-views.txt delete mode 100644 tests/regressiontests/views/tests/generic/__init__.py delete mode 100644 tests/regressiontests/views/tests/generic/create_update.py delete mode 100644 tests/regressiontests/views/tests/generic/date_based.py delete mode 100644 tests/regressiontests/views/tests/generic/object_list.py delete mode 100644 tests/regressiontests/views/tests/generic/simple.py diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py deleted file mode 100644 index 59760b4..0000000
+ - 1 from django.forms.models import ModelFormMetaclass, ModelForm2 from django.template import RequestContext, loader3 from django.http import Http404, HttpResponse, HttpResponseRedirect4 from django.core.xheaders import populate_xheaders5 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured6 from django.utils.translation import ugettext7 from django.contrib.auth.views import redirect_to_login8 from django.views.generic import GenericViewError9 from django.contrib import messages10 11 import warnings12 warnings.warn(13 'Function-based generic views have been deprecated; use class-based views instead.',14 DeprecationWarning15 )16 17 18 def apply_extra_context(extra_context, context):19 """20 Adds items from extra_context dict to context. If a value in extra_context21 is callable, then it is called and the result is added to context.22 """23 for key, value in extra_context.iteritems():24 if callable(value):25 context[key] = value()26 else:27 context[key] = value28 29 def get_model_and_form_class(model, form_class):30 """31 Returns a model and form class based on the model and form_class32 parameters that were passed to the generic view.33 34 If ``form_class`` is given then its associated model will be returned along35 with ``form_class`` itself. Otherwise, if ``model`` is given, ``model``36 itself will be returned along with a ``ModelForm`` class created from37 ``model``.38 """39 if form_class:40 return form_class._meta.model, form_class41 if model:42 # The inner Meta class fails if model = model is used for some reason.43 tmp_model = model44 # TODO: we should be able to construct a ModelForm without creating45 # and passing in a temporary inner class.46 class Meta:47 model = tmp_model48 class_name = model.__name__ + 'Form'49 form_class = ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta})50 return model, form_class51 raise GenericViewError("Generic view must be called with either a model or"52 " form_class argument.")53 54 def redirect(post_save_redirect, obj):55 """56 Returns a HttpResponseRedirect to ``post_save_redirect``.57 58 ``post_save_redirect`` should be a string, and can contain named string-59 substitution place holders of ``obj`` field names.60 61 If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned62 by ``get_absolute_url()``. If ``obj`` has no ``get_absolute_url`` method,63 then raise ImproperlyConfigured.64 65 This function is meant to handle the post_save_redirect parameter to the66 ``create_object`` and ``update_object`` views.67 """68 if post_save_redirect:69 return HttpResponseRedirect(post_save_redirect % obj.__dict__)70 elif hasattr(obj, 'get_absolute_url'):71 return HttpResponseRedirect(obj.get_absolute_url())72 else:73 raise ImproperlyConfigured(74 "No URL to redirect to. Either pass a post_save_redirect"75 " parameter to the generic view or define a get_absolute_url"76 " method on the Model.")77 78 def lookup_object(model, object_id, slug, slug_field):79 """80 Return the ``model`` object with the passed ``object_id``. If81 ``object_id`` is None, then return the object whose ``slug_field``82 equals the passed ``slug``. If ``slug`` and ``slug_field`` are not passed,83 then raise Http404 exception.84 """85 lookup_kwargs = {}86 if object_id:87 lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id88 elif slug and slug_field:89 lookup_kwargs['%s__exact' % slug_field] = slug90 else:91 raise GenericViewError(92 "Generic view must be called with either an object_id or a"93 " slug/slug_field.")94 try:95 return model.objects.get(**lookup_kwargs)96 except ObjectDoesNotExist:97 raise Http404("No %s found for %s"98 % (model._meta.verbose_name, lookup_kwargs))99 100 def create_object(request, model=None, template_name=None,101 template_loader=loader, extra_context=None, post_save_redirect=None,102 login_required=False, context_processors=None, form_class=None):103 """104 Generic object-creation function.105 106 Templates: ``<app_label>/<model_name>_form.html``107 Context:108 form109 the form for the object110 """111 if extra_context is None: extra_context = {}112 if login_required and not request.user.is_authenticated():113 return redirect_to_login(request.path)114 115 model, form_class = get_model_and_form_class(model, form_class)116 if request.method == 'POST':117 form = form_class(request.POST, request.FILES)118 if form.is_valid():119 new_object = form.save()120 121 msg = ugettext("The %(verbose_name)s was created successfully.") %\122 {"verbose_name": model._meta.verbose_name}123 messages.success(request, msg, fail_silently=True)124 return redirect(post_save_redirect, new_object)125 else:126 form = form_class()127 128 # Create the template, context, response129 if not template_name:130 template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())131 t = template_loader.get_template(template_name)132 c = RequestContext(request, {133 'form': form,134 }, context_processors)135 apply_extra_context(extra_context, c)136 return HttpResponse(t.render(c))137 138 def update_object(request, model=None, object_id=None, slug=None,139 slug_field='slug', template_name=None, template_loader=loader,140 extra_context=None, post_save_redirect=None, login_required=False,141 context_processors=None, template_object_name='object',142 form_class=None):143 """144 Generic object-update function.145 146 Templates: ``<app_label>/<model_name>_form.html``147 Context:148 form149 the form for the object150 object151 the original object being edited152 """153 if extra_context is None: extra_context = {}154 if login_required and not request.user.is_authenticated():155 return redirect_to_login(request.path)156 157 model, form_class = get_model_and_form_class(model, form_class)158 obj = lookup_object(model, object_id, slug, slug_field)159 160 if request.method == 'POST':161 form = form_class(request.POST, request.FILES, instance=obj)162 if form.is_valid():163 obj = form.save()164 msg = ugettext("The %(verbose_name)s was updated successfully.") %\165 {"verbose_name": model._meta.verbose_name}166 messages.success(request, msg, fail_silently=True)167 return redirect(post_save_redirect, obj)168 else:169 form = form_class(instance=obj)170 171 if not template_name:172 template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())173 t = template_loader.get_template(template_name)174 c = RequestContext(request, {175 'form': form,176 template_object_name: obj,177 }, context_processors)178 apply_extra_context(extra_context, c)179 response = HttpResponse(t.render(c))180 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname))181 return response182 183 def delete_object(request, model, post_delete_redirect, object_id=None,184 slug=None, slug_field='slug', template_name=None,185 template_loader=loader, extra_context=None, login_required=False,186 context_processors=None, template_object_name='object'):187 """188 Generic object-delete function.189 190 The given template will be used to confirm deletetion if this view is191 fetched using GET; for safty, deletion will only be performed if this192 view is POSTed.193 194 Templates: ``<app_label>/<model_name>_confirm_delete.html``195 Context:196 object197 the original object being deleted198 """199 if extra_context is None: extra_context = {}200 if login_required and not request.user.is_authenticated():201 return redirect_to_login(request.path)202 203 obj = lookup_object(model, object_id, slug, slug_field)204 205 if request.method == 'POST':206 obj.delete()207 msg = ugettext("The %(verbose_name)s was deleted.") %\208 {"verbose_name": model._meta.verbose_name}209 messages.success(request, msg, fail_silently=True)210 return HttpResponseRedirect(post_delete_redirect)211 else:212 if not template_name:213 template_name = "%s/%s_confirm_delete.html" % (model._meta.app_label, model._meta.object_name.lower())214 t = template_loader.get_template(template_name)215 c = RequestContext(request, {216 template_object_name: obj,217 }, context_processors)218 apply_extra_context(extra_context, c)219 response = HttpResponse(t.render(c))220 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname))221 return response -
deleted file django/views/generic/date_based.py
diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py deleted file mode 100644 index 75094aa..0000000
+ - 1 import datetime2 import time3 4 from django.template import loader, RequestContext5 from django.core.exceptions import ObjectDoesNotExist6 from django.core.xheaders import populate_xheaders7 from django.db.models.fields import DateTimeField8 from django.http import Http404, HttpResponse9 from django.utils import timezone10 11 import warnings12 warnings.warn(13 'Function-based generic views have been deprecated; use class-based views instead.',14 DeprecationWarning15 )16 17 18 def archive_index(request, queryset, date_field, num_latest=15,19 template_name=None, template_loader=loader,20 extra_context=None, allow_empty=True, context_processors=None,21 mimetype=None, allow_future=False, template_object_name='latest'):22 """23 Generic top-level archive of date-based objects.24 25 Templates: ``<app_label>/<model_name>_archive.html``26 Context:27 date_list28 List of years29 latest30 Latest N (defaults to 15) objects by date31 """32 if extra_context is None: extra_context = {}33 model = queryset.model34 if not allow_future:35 queryset = queryset.filter(**{'%s__lte' % date_field: timezone.now()})36 date_list = queryset.dates(date_field, 'year')[::-1]37 if not date_list and not allow_empty:38 raise Http404("No %s available" % model._meta.verbose_name)39 40 if date_list and num_latest:41 latest = queryset.order_by('-'+date_field)[:num_latest]42 else:43 latest = None44 45 if not template_name:46 template_name = "%s/%s_archive.html" % (model._meta.app_label, model._meta.object_name.lower())47 t = template_loader.get_template(template_name)48 c = RequestContext(request, {49 'date_list' : date_list,50 template_object_name : latest,51 }, context_processors)52 for key, value in extra_context.items():53 if callable(value):54 c[key] = value()55 else:56 c[key] = value57 return HttpResponse(t.render(c), mimetype=mimetype)58 59 def archive_year(request, year, queryset, date_field, template_name=None,60 template_loader=loader, extra_context=None, allow_empty=False,61 context_processors=None, template_object_name='object', mimetype=None,62 make_object_list=False, allow_future=False):63 """64 Generic yearly archive view.65 66 Templates: ``<app_label>/<model_name>_archive_year.html``67 Context:68 date_list69 List of months in this year with objects70 year71 This year72 object_list73 List of objects published in the given month74 (Only available if make_object_list argument is True)75 """76 if extra_context is None: extra_context = {}77 model = queryset.model78 now = timezone.now()79 80 lookup_kwargs = {'%s__year' % date_field: year}81 82 # Only bother to check current date if the year isn't in the past and future objects aren't requested.83 if int(year) >= now.year and not allow_future:84 lookup_kwargs['%s__lte' % date_field] = now85 date_list = queryset.filter(**lookup_kwargs).dates(date_field, 'month')86 if not date_list and not allow_empty:87 raise Http40488 if make_object_list:89 object_list = queryset.filter(**lookup_kwargs)90 else:91 object_list = []92 if not template_name:93 template_name = "%s/%s_archive_year.html" % (model._meta.app_label, model._meta.object_name.lower())94 t = template_loader.get_template(template_name)95 c = RequestContext(request, {96 'date_list': date_list,97 'year': year,98 '%s_list' % template_object_name: object_list,99 }, context_processors)100 for key, value in extra_context.items():101 if callable(value):102 c[key] = value()103 else:104 c[key] = value105 return HttpResponse(t.render(c), mimetype=mimetype)106 107 def archive_month(request, year, month, queryset, date_field,108 month_format='%b', template_name=None, template_loader=loader,109 extra_context=None, allow_empty=False, context_processors=None,110 template_object_name='object', mimetype=None, allow_future=False):111 """112 Generic monthly archive view.113 114 Templates: ``<app_label>/<model_name>_archive_month.html``115 Context:116 date_list:117 List of days in this month with objects118 month:119 (date) this month120 next_month:121 (date) the first day of the next month, or None if the next month is in the future122 previous_month:123 (date) the first day of the previous month124 object_list:125 list of objects published in the given month126 """127 if extra_context is None: extra_context = {}128 try:129 tt = time.strptime("%s-%s" % (year, month), '%s-%s' % ('%Y', month_format))130 date = datetime.date(*tt[:3])131 except ValueError:132 raise Http404133 134 model = queryset.model135 now = timezone.now()136 137 # Calculate first and last day of month, for use in a date-range lookup.138 first_day = date.replace(day=1)139 if first_day.month == 12:140 last_day = first_day.replace(year=first_day.year + 1, month=1)141 else:142 last_day = first_day.replace(month=first_day.month + 1)143 lookup_kwargs = {144 '%s__gte' % date_field: first_day,145 '%s__lt' % date_field: last_day,146 }147 148 # Only bother to check current date if the month isn't in the past and future objects are requested.149 if last_day >= now.date() and not allow_future:150 lookup_kwargs['%s__lte' % date_field] = now151 object_list = queryset.filter(**lookup_kwargs)152 date_list = object_list.dates(date_field, 'day')153 if not object_list and not allow_empty:154 raise Http404155 156 # Calculate the next month, if applicable.157 if allow_future:158 next_month = last_day159 elif last_day <= datetime.date.today():160 next_month = last_day161 else:162 next_month = None163 164 # Calculate the previous month165 if first_day.month == 1:166 previous_month = first_day.replace(year=first_day.year-1,month=12)167 else:168 previous_month = first_day.replace(month=first_day.month-1)169 170 if not template_name:171 template_name = "%s/%s_archive_month.html" % (model._meta.app_label, model._meta.object_name.lower())172 t = template_loader.get_template(template_name)173 c = RequestContext(request, {174 'date_list': date_list,175 '%s_list' % template_object_name: object_list,176 'month': date,177 'next_month': next_month,178 'previous_month': previous_month,179 }, context_processors)180 for key, value in extra_context.items():181 if callable(value):182 c[key] = value()183 else:184 c[key] = value185 return HttpResponse(t.render(c), mimetype=mimetype)186 187 def archive_week(request, year, week, queryset, date_field,188 template_name=None, template_loader=loader,189 extra_context=None, allow_empty=True, context_processors=None,190 template_object_name='object', mimetype=None, allow_future=False):191 """192 Generic weekly archive view.193 194 Templates: ``<app_label>/<model_name>_archive_week.html``195 Context:196 week:197 (date) this week198 object_list:199 list of objects published in the given week200 """201 if extra_context is None: extra_context = {}202 try:203 tt = time.strptime(year+'-0-'+week, '%Y-%w-%U')204 date = datetime.date(*tt[:3])205 except ValueError:206 raise Http404207 208 model = queryset.model209 now = timezone.now()210 211 # Calculate first and last day of week, for use in a date-range lookup.212 first_day = date213 last_day = date + datetime.timedelta(days=7)214 lookup_kwargs = {215 '%s__gte' % date_field: first_day,216 '%s__lt' % date_field: last_day,217 }218 219 # Only bother to check current date if the week isn't in the past and future objects aren't requested.220 if last_day >= now.date() and not allow_future:221 lookup_kwargs['%s__lte' % date_field] = now222 object_list = queryset.filter(**lookup_kwargs)223 if not object_list and not allow_empty:224 raise Http404225 if not template_name:226 template_name = "%s/%s_archive_week.html" % (model._meta.app_label, model._meta.object_name.lower())227 t = template_loader.get_template(template_name)228 c = RequestContext(request, {229 '%s_list' % template_object_name: object_list,230 'week': date,231 })232 for key, value in extra_context.items():233 if callable(value):234 c[key] = value()235 else:236 c[key] = value237 return HttpResponse(t.render(c), mimetype=mimetype)238 239 def archive_day(request, year, month, day, queryset, date_field,240 month_format='%b', day_format='%d', template_name=None,241 template_loader=loader, extra_context=None, allow_empty=False,242 context_processors=None, template_object_name='object',243 mimetype=None, allow_future=False):244 """245 Generic daily archive view.246 247 Templates: ``<app_label>/<model_name>_archive_day.html``248 Context:249 object_list:250 list of objects published that day251 day:252 (datetime) the day253 previous_day254 (datetime) the previous day255 next_day256 (datetime) the next day, or None if the current day is today257 """258 if extra_context is None: extra_context = {}259 try:260 tt = time.strptime('%s-%s-%s' % (year, month, day),261 '%s-%s-%s' % ('%Y', month_format, day_format))262 date = datetime.date(*tt[:3])263 except ValueError:264 raise Http404265 266 model = queryset.model267 now = timezone.now()268 269 if isinstance(model._meta.get_field(date_field), DateTimeField):270 lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}271 else:272 lookup_kwargs = {date_field: date}273 274 # Only bother to check current date if the date isn't in the past and future objects aren't requested.275 if date >= now.date() and not allow_future:276 lookup_kwargs['%s__lte' % date_field] = now277 object_list = queryset.filter(**lookup_kwargs)278 if not allow_empty and not object_list:279 raise Http404280 281 # Calculate the next day, if applicable.282 if allow_future:283 next_day = date + datetime.timedelta(days=1)284 elif date < datetime.date.today():285 next_day = date + datetime.timedelta(days=1)286 else:287 next_day = None288 289 if not template_name:290 template_name = "%s/%s_archive_day.html" % (model._meta.app_label, model._meta.object_name.lower())291 t = template_loader.get_template(template_name)292 c = RequestContext(request, {293 '%s_list' % template_object_name: object_list,294 'day': date,295 'previous_day': date - datetime.timedelta(days=1),296 'next_day': next_day,297 }, context_processors)298 for key, value in extra_context.items():299 if callable(value):300 c[key] = value()301 else:302 c[key] = value303 return HttpResponse(t.render(c), mimetype=mimetype)304 305 def archive_today(request, **kwargs):306 """307 Generic daily archive view for today. Same as archive_day view.308 """309 today = datetime.date.today()310 kwargs.update({311 'year': str(today.year),312 'month': today.strftime('%b').lower(),313 'day': str(today.day),314 })315 return archive_day(request, **kwargs)316 317 def object_detail(request, year, month, day, queryset, date_field,318 month_format='%b', day_format='%d', object_id=None, slug=None,319 slug_field='slug', template_name=None, template_name_field=None,320 template_loader=loader, extra_context=None, context_processors=None,321 template_object_name='object', mimetype=None, allow_future=False):322 """323 Generic detail view from year/month/day/slug or year/month/day/id structure.324 325 Templates: ``<app_label>/<model_name>_detail.html``326 Context:327 object:328 the object to be detailed329 """330 if extra_context is None: extra_context = {}331 try:332 tt = time.strptime('%s-%s-%s' % (year, month, day),333 '%s-%s-%s' % ('%Y', month_format, day_format))334 date = datetime.date(*tt[:3])335 except ValueError:336 raise Http404337 338 model = queryset.model339 now = timezone.now()340 341 if isinstance(model._meta.get_field(date_field), DateTimeField):342 lookup_kwargs = {'%s__range' % date_field: (datetime.datetime.combine(date, datetime.time.min), datetime.datetime.combine(date, datetime.time.max))}343 else:344 lookup_kwargs = {date_field: date}345 346 # Only bother to check current date if the date isn't in the past and future objects aren't requested.347 if date >= now.date() and not allow_future:348 lookup_kwargs['%s__lte' % date_field] = now349 if object_id:350 lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id351 elif slug and slug_field:352 lookup_kwargs['%s__exact' % slug_field] = slug353 else:354 raise AttributeError("Generic detail view must be called with either an object_id or a slug/slugfield")355 try:356 obj = queryset.get(**lookup_kwargs)357 except ObjectDoesNotExist:358 raise Http404("No %s found for" % model._meta.verbose_name)359 if not template_name:360 template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())361 if template_name_field:362 template_name_list = [getattr(obj, template_name_field), template_name]363 t = template_loader.select_template(template_name_list)364 else:365 t = template_loader.get_template(template_name)366 c = RequestContext(request, {367 template_object_name: obj,368 }, context_processors)369 for key, value in extra_context.items():370 if callable(value):371 c[key] = value()372 else:373 c[key] = value374 response = HttpResponse(t.render(c), mimetype=mimetype)375 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))376 return response -
deleted file django/views/generic/list_detail.py
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py deleted file mode 100644 index 22414ae..0000000
+ - 1 from django.template import loader, RequestContext2 from django.http import Http404, HttpResponse3 from django.core.xheaders import populate_xheaders4 from django.core.paginator import Paginator, InvalidPage5 from django.core.exceptions import ObjectDoesNotExist6 7 import warnings8 warnings.warn(9 'Function-based generic views have been deprecated; use class-based views instead.',10 DeprecationWarning11 )12 13 14 def object_list(request, queryset, paginate_by=None, page=None,15 allow_empty=True, template_name=None, template_loader=loader,16 extra_context=None, context_processors=None, template_object_name='object',17 mimetype=None):18 """19 Generic list of objects.20 21 Templates: ``<app_label>/<model_name>_list.html``22 Context:23 object_list24 list of objects25 is_paginated26 are the results paginated?27 results_per_page28 number of objects per page (if paginated)29 has_next30 is there a next page?31 has_previous32 is there a prev page?33 page34 the current page35 next36 the next page37 previous38 the previous page39 pages40 number of pages, total41 hits42 number of objects, total43 last_on_page44 the result number of the last of object in the45 object_list (1-indexed)46 first_on_page47 the result number of the first object in the48 object_list (1-indexed)49 page_range:50 A list of the page numbers (1-indexed).51 """52 if extra_context is None: extra_context = {}53 queryset = queryset._clone()54 if paginate_by:55 paginator = Paginator(queryset, paginate_by, allow_empty_first_page=allow_empty)56 if not page:57 page = request.GET.get('page', 1)58 try:59 page_number = int(page)60 except ValueError:61 if page == 'last':62 page_number = paginator.num_pages63 else:64 # Page is not 'last', nor can it be converted to an int.65 raise Http40466 try:67 page_obj = paginator.page(page_number)68 except InvalidPage:69 raise Http40470 c = RequestContext(request, {71 '%s_list' % template_object_name: page_obj.object_list,72 'paginator': paginator,73 'page_obj': page_obj,74 'is_paginated': page_obj.has_other_pages(),75 76 # Legacy template context stuff. New templates should use page_obj77 # to access this instead.78 'results_per_page': paginator.per_page,79 'has_next': page_obj.has_next(),80 'has_previous': page_obj.has_previous(),81 'page': page_obj.number,82 'next': page_obj.next_page_number(),83 'previous': page_obj.previous_page_number(),84 'first_on_page': page_obj.start_index(),85 'last_on_page': page_obj.end_index(),86 'pages': paginator.num_pages,87 'hits': paginator.count,88 'page_range': paginator.page_range,89 }, context_processors)90 else:91 c = RequestContext(request, {92 '%s_list' % template_object_name: queryset,93 'paginator': None,94 'page_obj': None,95 'is_paginated': False,96 }, context_processors)97 if not allow_empty and len(queryset) == 0:98 raise Http40499 for key, value in extra_context.items():100 if callable(value):101 c[key] = value()102 else:103 c[key] = value104 if not template_name:105 model = queryset.model106 template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())107 t = template_loader.get_template(template_name)108 return HttpResponse(t.render(c), mimetype=mimetype)109 110 def object_detail(request, queryset, object_id=None, slug=None,111 slug_field='slug', template_name=None, template_name_field=None,112 template_loader=loader, extra_context=None,113 context_processors=None, template_object_name='object',114 mimetype=None):115 """116 Generic detail of an object.117 118 Templates: ``<app_label>/<model_name>_detail.html``119 Context:120 object121 the object122 """123 if extra_context is None: extra_context = {}124 model = queryset.model125 if object_id:126 queryset = queryset.filter(pk=object_id)127 elif slug and slug_field:128 queryset = queryset.filter(**{slug_field: slug})129 else:130 raise AttributeError("Generic detail view must be called with either an object_id or a slug/slug_field.")131 try:132 obj = queryset.get()133 except ObjectDoesNotExist:134 raise Http404("No %s found matching the query" % (model._meta.verbose_name))135 if not template_name:136 template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())137 if template_name_field:138 template_name_list = [getattr(obj, template_name_field), template_name]139 t = template_loader.select_template(template_name_list)140 else:141 t = template_loader.get_template(template_name)142 c = RequestContext(request, {143 template_object_name: obj,144 }, context_processors)145 for key, value in extra_context.items():146 if callable(value):147 c[key] = value()148 else:149 c[key] = value150 response = HttpResponse(t.render(c), mimetype=mimetype)151 populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))152 return response -
deleted file django/views/generic/simple.py
diff --git a/django/views/generic/simple.py b/django/views/generic/simple.py deleted file mode 100644 index f63860a..0000000
+ - 1 from django.template import loader, RequestContext2 from django.http import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, HttpResponseGone3 from django.utils.log import getLogger4 5 import warnings6 warnings.warn(7 'Function-based generic views have been deprecated; use class-based views instead.',8 DeprecationWarning9 )10 11 logger = getLogger('django.request')12 13 14 def direct_to_template(request, template, extra_context=None, mimetype=None, **kwargs):15 """16 Render a given template with any extra URL parameters in the context as17 ``{{ params }}``.18 """19 if extra_context is None: extra_context = {}20 dictionary = {'params': kwargs}21 for key, value in extra_context.items():22 if callable(value):23 dictionary[key] = value()24 else:25 dictionary[key] = value26 c = RequestContext(request, dictionary)27 t = loader.get_template(template)28 return HttpResponse(t.render(c), content_type=mimetype)29 30 def redirect_to(request, url, permanent=True, query_string=False, **kwargs):31 """32 Redirect to a given URL.33 34 The given url may contain dict-style string formatting, which will be35 interpolated against the params in the URL. For example, to redirect from36 ``/foo/<id>/`` to ``/bar/<id>/``, you could use the following URLconf::37 38 urlpatterns = patterns('',39 ('^foo/(?P<id>\d+)/$', 'django.views.generic.simple.redirect_to', {'url' : '/bar/%(id)s/'}),40 )41 42 If the given url is ``None``, a HttpResponseGone (410) will be issued.43 44 If the ``permanent`` argument is False, then the response will have a 30245 HTTP status code. Otherwise, the status code will be 301.46 47 If the ``query_string`` argument is True, then the GET query string48 from the request is appended to the URL.49 50 """51 args = request.META.get('QUERY_STRING', '')52 53 if url is not None:54 if kwargs:55 url = url % kwargs56 57 if args and query_string:58 url = "%s?%s" % (url, args)59 60 klass = permanent and HttpResponsePermanentRedirect or HttpResponseRedirect61 return klass(url)62 else:63 logger.warning('Gone: %s', request.path,64 extra={65 'status_code': 410,66 'request': request67 })68 return HttpResponseGone() -
docs/glossary.txt
diff --git a/docs/glossary.txt b/docs/glossary.txt index 15776ce..4d0f8b9 100644
a b Glossary 16 16 A higher-order :term:`view` function that provides an abstract/generic 17 17 implementation of a common idiom or pattern found in view development. 18 18 19 See :doc:`/ref/ generic-views`.19 See :doc:`/ref/class-based-views`. 20 20 21 21 model 22 22 Models store your application's data. -
docs/index.txt
diff --git a/docs/index.txt b/docs/index.txt index 66c8e73..d596511 100644
a b Other batteries included 195 195 * :doc:`Unicode in Django <ref/unicode>` 196 196 * :doc:`Web design helpers <ref/contrib/webdesign>` 197 197 * :doc:`Validators <ref/validators>` 198 * 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>`199 198 200 199 The Django open-source project 201 200 ============================== -
docs/internals/deprecation.txt
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index e54adf0..e3a5e1a 100644
a b these changes. 134 134 135 135 * The function-based generic view modules will be removed in favor of their 136 136 class-based equivalents, outlined :doc:`here 137 </topics/ generic-views-migration>`:137 </topics/class-based-views>`: 138 138 139 139 * The :class:`~django.core.servers.basehttp.AdminMediaHandler` will be 140 140 removed. In its place use -
docs/intro/tutorial04.txt
diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt index 85d54c3..8a9f4ee 100644
a b function anymore -- generic views can be (and are) used multiple times 320 320 Run the server, and use your new polling app based on generic views. 321 321 322 322 For full details on generic views, see the :doc:`generic views documentation 323 </topics/ http/generic-views>`.323 </topics/class-based-views>`. 324 324 325 325 Coming soon 326 326 =========== -
docs/misc/api-stability.txt
diff --git a/docs/misc/api-stability.txt b/docs/misc/api-stability.txt index 75fa6b4..5517026 100644
a b of 1.0. This includes these APIs: 54 54 - :doc:`HTTP request/response handling </topics/http/index>`, including file 55 55 uploads, middleware, sessions, URL resolution, view, and shortcut APIs. 56 56 57 - :doc:`Generic views </topics/ http/generic-views>`.57 - :doc:`Generic views </topics/class-based-views>`. 58 58 59 59 - :doc:`Internationalization </topics/i18n/index>`. 60 60 -
docs/ref/class-based-views.txt
diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt index 5223aee..aa3f8f7 100644
a b Class-based generic views 6 6 7 7 .. note:: 8 8 Prior to Django 1.3, generic views were implemented as functions. The 9 function-based implementation has been deprecated in favor of the9 function-based implementation has been removed in favor of the 10 10 class-based approach described here. 11 11 12 For details on the previous generic views implementation,13 see the :doc:`topic guide </topics/generic-views>` and14 :doc:`detailed reference </ref/generic-views>`.15 16 12 Writing Web applications can be monotonous, because we repeat certain patterns 17 13 again and again. Django tries to take away some of that monotony at the model 18 14 and template layers, but Web developers also experience this boredom at the view -
docs/ref/contrib/messages.txt
diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt index 223a162..4ab9734 100644
a b example:: 274 274 fail_silently=True) 275 275 messages.info(request, 'Hello world.', fail_silently=True) 276 276 277 Internally, Django uses this functionality in the create, update, and delete278 :doc:`generic views </topics/http/generic-views>` so that they work even if the279 message framework is disabled.280 281 277 .. note:: 282 278 Setting ``fail_silently=True`` only hides the ``MessageFailure`` that would 283 279 otherwise occur when the messages framework disabled and one attempts to -
docs/ref/contrib/sitemaps.txt
diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt index 64400bc..d775092 100644
a b The sitemap framework provides a couple convenience classes for common cases: 240 240 241 241 .. class:: GenericSitemap 242 242 243 The :class:`django.contrib.sitemaps.GenericSitemap` class works with any244 :doc:`generic views </ref/generic-views>` you already have.245 To use it, create an instance, passing in the same :data:`info_dict` you pass to246 the generic views. The only requirement is that the dictionary have a247 :data:`queryset` entry. It may also have a :data:`date_field` entry that specifies a248 date field for objects retrieved from the :data:`queryset`. This will be used for249 the :attr:`~Sitemap.lastmod` attribute in the generated sitemap. You may250 also pass :attr:`~Sitemap.priority` and :attr:`~Sitemap.changefreq`251 keyword arguments to the :class:`~django.contrib.sitemaps.GenericSitemap`252 constructor to specifythese attributes for all URLs.243 The :class:`django.contrib.sitemaps.GenericSitemap` class allows you to 244 create a sitemap by passing it a dictionary which has to contain at least 245 a :data:`queryset` entry. This queryset will be used to generate the items 246 of the sitemap. It may also have a :data:`date_field` entry that 247 specifies a date field for objects retrieved from the :data:`queryset`. 248 This will be used for the :attr:`~Sitemap.lastmod` attribute in the 249 generated sitemap. You may also pass :attr:`~Sitemap.priority` and 250 :attr:`~Sitemap.changefreq` keyword arguments to the 251 :class:`~django.contrib.sitemaps.GenericSitemap` constructor to specify 252 these attributes for all URLs. 253 253 254 254 Example 255 255 ------- -
deleted file docs/ref/generic-views.txt
diff --git a/docs/ref/generic-views.txt b/docs/ref/generic-views.txt deleted file mode 100644 index eb65107..0000000
+ - 1 =============2 Generic views3 =============4 5 6 .. versionchanged:: 1.37 8 .. note::9 10 From Django 1.3, function-based generic views have been deprecated in favor11 of a class-based approach, described in the class-based views :doc:`topic12 guide </topics/class-based-views>` and :doc:`detailed reference13 </ref/class-based-views>`.14 15 Writing Web applications can be monotonous, because we repeat certain patterns16 again and again. In Django, the most common of these patterns have been17 abstracted into "generic views" that let you quickly provide common views of18 an object without actually needing to write any Python code.19 20 A general introduction to generic views can be found in the :doc:`topic guide21 </topics/generic-views>`.22 23 This reference contains details of Django's built-in generic views, along with24 a list of all keyword arguments that a generic view expects. Remember that25 arguments may either come from the URL pattern or from the ``extra_context``26 additional-information dictionary.27 28 Most generic views require the ``queryset`` key, which is a ``QuerySet``29 instance; see :doc:`/topics/db/queries` for more information about ``QuerySet``30 objects.31 32 .. module:: django.views.generic.simple33 34 "Simple" generic views35 ======================36 37 The ``django.views.generic.simple`` module contains simple views to handle a38 couple of common cases: rendering a template when no view logic is needed,39 and issuing a redirect.40 41 ``django.views.generic.simple.direct_to_template``42 --------------------------------------------------43 44 **Description:**45 46 Renders a given template, passing it a ``{{ params }}`` template variable,47 which is a dictionary of the parameters captured in the URL.48 49 **Required arguments:**50 51 * ``template``: The full name of a template to use.52 53 **Optional arguments:**54 55 * ``extra_context``: A dictionary of values to add to the template56 context. By default, this is an empty dictionary. If a value in the57 dictionary is callable, the generic view will call it58 just before rendering the template.59 60 * ``mimetype``: The MIME type to use for the resulting document. Defaults61 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.62 63 **Example:**64 65 Given the following URL patterns::66 67 from django.views.generic.simple import direct_to_template68 69 urlpatterns = patterns('',70 (r'^foo/$', direct_to_template, {'template': 'foo_index.html'}),71 (r'^foo/(?P<id>\d+)/$', direct_to_template, {'template': 'foo_detail.html'}),72 )73 74 ... a request to ``/foo/`` would render the template ``foo_index.html``, and a75 request to ``/foo/15/`` would render the ``foo_detail.html`` with a context76 variable ``{{ params.id }}`` that is set to ``15``.77 78 ``django.views.generic.simple.redirect_to``79 -------------------------------------------80 81 **Description:**82 83 Redirects to a given URL.84 85 The given URL may contain dictionary-style string formatting, which will be86 interpolated against the parameters captured in the URL. Because keyword87 interpolation is *always* done (even if no arguments are passed in), any ``"%"``88 characters in the URL must be written as ``"%%"`` so that Python will convert89 them to a single percent sign on output.90 91 If the given URL is ``None``, Django will return an ``HttpResponseGone`` (410).92 93 **Required arguments:**94 95 * ``url``: The URL to redirect to, as a string. Or ``None`` to raise a 41096 (Gone) HTTP error.97 98 **Optional arguments:**99 100 * ``permanent``: Whether the redirect should be permanent. The only101 difference here is the HTTP status code returned. If ``True``, then the102 redirect will use status code 301. If ``False``, then the redirect will103 use status code 302. By default, ``permanent`` is ``True``.104 105 * ``query_string``: Whether to pass along the GET query string to106 the new location. If ``True``, then the query string is appended107 to the URL. If ``False``, then the query string is discarded. By108 default, ``query_string`` is ``False``.109 110 .. versionadded:: 1.3111 The ``query_string`` keyword argument is new in Django 1.3.112 113 **Example:**114 115 This example issues a permanent redirect (HTTP status code 301) from116 ``/foo/<id>/`` to ``/bar/<id>/``::117 118 from django.views.generic.simple import redirect_to119 120 urlpatterns = patterns('',121 ('^foo/(?P<id>\d+)/$', redirect_to, {'url': '/bar/%(id)s/'}),122 )123 124 This example issues a non-permanent redirect (HTTP status code 302) from125 ``/foo/<id>/`` to ``/bar/<id>/``::126 127 from django.views.generic.simple import redirect_to128 129 urlpatterns = patterns('',130 ('^foo/(?P<id>\d+)/$', redirect_to, {'url': '/bar/%(id)s/', 'permanent': False}),131 )132 133 This example returns a 410 HTTP error for requests to ``/bar/``::134 135 from django.views.generic.simple import redirect_to136 137 urlpatterns = patterns('',138 ('^bar/$', redirect_to, {'url': None}),139 )140 141 This example shows how ``"%"`` characters must be written in the URL in order142 to avoid confusion with Python's string formatting markers. If the redirect143 string is written as ``"%7Ejacob/"`` (with only a single ``%``), an exception would be raised::144 145 from django.views.generic.simple import redirect_to146 147 urlpatterns = patterns('',148 ('^bar/$', redirect_to, {'url': '%%7Ejacob.'}),149 )150 151 .. module:: django.views.generic.date_based152 153 Date-based generic views154 ========================155 156 Date-based generic views (in the module ``django.views.generic.date_based``)157 are views for displaying drilldown pages for date-based data.158 159 ``django.views.generic.date_based.archive_index``160 -------------------------------------------------161 162 **Description:**163 164 A top-level index page showing the "latest" objects, by date. Objects with165 a date in the *future* are not included unless you set ``allow_future`` to166 ``True``.167 168 **Required arguments:**169 170 * ``queryset``: A ``QuerySet`` of objects for which the archive serves.171 172 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in173 the ``QuerySet``'s model that the date-based archive should use to174 determine the objects on the page.175 176 **Optional arguments:**177 178 * ``num_latest``: The number of latest objects to send to the template179 context. By default, it's 15.180 181 * ``template_name``: The full name of a template to use in rendering the182 page. This lets you override the default template name (see below).183 184 * ``template_loader``: The template loader to use when loading the185 template. By default, it's ``django.template.loader``.186 187 * ``extra_context``: A dictionary of values to add to the template188 context. By default, this is an empty dictionary. If a value in the189 dictionary is callable, the generic view will call it190 just before rendering the template.191 192 * ``allow_empty``: A boolean specifying whether to display the page if no193 objects are available. If this is ``False`` and no objects are available,194 the view will raise a 404 instead of displaying an empty page. By195 default, this is ``True``.196 197 * ``context_processors``: A list of template-context processors to apply to198 the view's template.199 200 * ``mimetype``: The MIME type to use for the resulting document. Defaults201 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.202 203 * ``allow_future``: A boolean specifying whether to include "future"204 objects on this page, where "future" means objects in which the field205 specified in ``date_field`` is greater than the current date/time. By206 default, this is ``False``.207 208 * ``template_object_name``: Designates the name of the template variable209 to use in the template context. By default, this is ``'latest'``.210 211 **Template name:**212 213 If ``template_name`` isn't specified, this view will use the template214 ``<app_label>/<model_name>_archive.html`` by default, where:215 216 * ``<model_name>`` is your model's name in all lowercase. For a model217 ``StaffMember``, that'd be ``staffmember``.218 219 * ``<app_label>`` is the right-most part of the full Python path to220 your model's app. For example, if your model lives in221 ``apps/blog/models.py``, that'd be ``blog``.222 223 **Template context:**224 225 In addition to ``extra_context``, the template's context will be:226 227 * ``date_list``: A ``DateQuerySet`` object containing all years that have228 have objects available according to ``queryset``, represented as229 ``datetime.datetime`` objects. These are ordered in reverse. This is230 equivalent to ``queryset.dates(date_field, 'year')[::-1]``.231 232 * ``latest``: The ``num_latest`` objects in the system, ordered descending233 by ``date_field``. For example, if ``num_latest`` is ``10``, then234 ``latest`` will be a list of the latest 10 objects in ``queryset``.235 236 This variable's name depends on the ``template_object_name`` parameter,237 which is ``'latest'`` by default. If ``template_object_name`` is238 ``'foo'``, this variable's name will be ``foo``.239 240 ``django.views.generic.date_based.archive_year``241 ------------------------------------------------242 243 **Description:**244 245 A yearly archive page showing all available months in a given year. Objects246 with a date in the *future* are not displayed unless you set ``allow_future``247 to ``True``.248 249 **Required arguments:**250 251 * ``year``: The four-digit year for which the archive serves.252 253 * ``queryset``: A ``QuerySet`` of objects for which the archive serves.254 255 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in256 the ``QuerySet``'s model that the date-based archive should use to257 determine the objects on the page.258 259 **Optional arguments:**260 261 * ``template_name``: The full name of a template to use in rendering the262 page. This lets you override the default template name (see below).263 264 * ``template_loader``: The template loader to use when loading the265 template. By default, it's ``django.template.loader``.266 267 * ``extra_context``: A dictionary of values to add to the template268 context. By default, this is an empty dictionary. If a value in the269 dictionary is callable, the generic view will call it270 just before rendering the template.271 272 * ``allow_empty``: A boolean specifying whether to display the page if no273 objects are available. If this is ``False`` and no objects are available,274 the view will raise a 404 instead of displaying an empty page. By275 default, this is ``False``.276 277 * ``context_processors``: A list of template-context processors to apply to278 the view's template.279 280 * ``template_object_name``: Designates the name of the template variable281 to use in the template context. By default, this is ``'object'``. The282 view will append ``'_list'`` to the value of this parameter in283 determining the variable's name.284 285 * ``make_object_list``: A boolean specifying whether to retrieve the full286 list of objects for this year and pass those to the template. If ``True``,287 this list of objects will be made available to the template as288 ``object_list``. (The name ``object_list`` may be different; see the docs289 for ``object_list`` in the "Template context" section below.) By default,290 this is ``False``.291 292 * ``mimetype``: The MIME type to use for the resulting document. Defaults293 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.294 295 * ``allow_future``: A boolean specifying whether to include "future"296 objects on this page, where "future" means objects in which the field297 specified in ``date_field`` is greater than the current date/time. By298 default, this is ``False``.299 300 **Template name:**301 302 If ``template_name`` isn't specified, this view will use the template303 ``<app_label>/<model_name>_archive_year.html`` by default.304 305 **Template context:**306 307 In addition to ``extra_context``, the template's context will be:308 309 * ``date_list``: A ``DateQuerySet`` object containing all months that have310 have objects available according to ``queryset``, represented as311 ``datetime.datetime`` objects, in ascending order.312 313 * ``year``: The given year, as a four-character string.314 315 * ``object_list``: If the ``make_object_list`` parameter is ``True``, this316 will be set to a list of objects available for the given year, ordered by317 the date field. This variable's name depends on the318 ``template_object_name`` parameter, which is ``'object'`` by default. If319 ``template_object_name`` is ``'foo'``, this variable's name will be320 ``foo_list``.321 322 If ``make_object_list`` is ``False``, ``object_list`` will be passed to323 the template as an empty list.324 325 ``django.views.generic.date_based.archive_month``326 -------------------------------------------------327 328 **Description:**329 330 A monthly archive page showing all objects in a given month. Objects with a331 date in the *future* are not displayed unless you set ``allow_future`` to332 ``True``.333 334 **Required arguments:**335 336 * ``year``: The four-digit year for which the archive serves (a string).337 338 * ``month``: The month for which the archive serves, formatted according to339 the ``month_format`` argument.340 341 * ``queryset``: A ``QuerySet`` of objects for which the archive serves.342 343 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in344 the ``QuerySet``'s model that the date-based archive should use to345 determine the objects on the page.346 347 **Optional arguments:**348 349 * ``month_format``: A format string that regulates what format the ``month``350 parameter uses. This should be in the syntax accepted by Python's351 :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a352 three-letter month abbreviation. To change it to use numbers, use353 ``"%m"``.354 355 * ``template_name``: The full name of a template to use in rendering the356 page. This lets you override the default template name (see below).357 358 * ``template_loader``: The template loader to use when loading the359 template. By default, it's ``django.template.loader``.360 361 * ``extra_context``: A dictionary of values to add to the template362 context. By default, this is an empty dictionary. If a value in the363 dictionary is callable, the generic view will call it364 just before rendering the template.365 366 * ``allow_empty``: A boolean specifying whether to display the page if no367 objects are available. If this is ``False`` and no objects are available,368 the view will raise a 404 instead of displaying an empty page. By369 default, this is ``False``.370 371 * ``context_processors``: A list of template-context processors to apply to372 the view's template.373 374 * ``template_object_name``: Designates the name of the template variable375 to use in the template context. By default, this is ``'object'``. The376 view will append ``'_list'`` to the value of this parameter in377 determining the variable's name.378 379 * ``mimetype``: The MIME type to use for the resulting document. Defaults380 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.381 382 * ``allow_future``: A boolean specifying whether to include "future"383 objects on this page, where "future" means objects in which the field384 specified in ``date_field`` is greater than the current date/time. By385 default, this is ``False``.386 387 **Template name:**388 389 If ``template_name`` isn't specified, this view will use the template390 ``<app_label>/<model_name>_archive_month.html`` by default.391 392 **Template context:**393 394 .. versionadded:: 1.2395 The inclusion of ``date_list`` in the template's context is new.396 397 In addition to ``extra_context``, the template's context will be:398 399 * ``date_list``: A ``DateQuerySet`` object containing all days that have400 have objects available in the given month, according to ``queryset``,401 represented as ``datetime.datetime`` objects, in ascending order.402 403 * ``month``: A ``datetime.date`` object representing the given month.404 405 * ``next_month``: A ``datetime.date`` object representing the first day of406 the next month. If the next month is in the future, this will be407 ``None``.408 409 * ``previous_month``: A ``datetime.date`` object representing the first day410 of the previous month. Unlike ``next_month``, this will never be411 ``None``.412 413 * ``object_list``: A list of objects available for the given month. This414 variable's name depends on the ``template_object_name`` parameter, which415 is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,416 this variable's name will be ``foo_list``.417 418 ``django.views.generic.date_based.archive_week``419 ------------------------------------------------420 421 **Description:**422 423 A weekly archive page showing all objects in a given week. Objects with a date424 in the *future* are not displayed unless you set ``allow_future`` to ``True``.425 426 **Required arguments:**427 428 * ``year``: The four-digit year for which the archive serves (a string).429 430 * ``week``: The week of the year for which the archive serves (a string).431 Weeks start with Sunday.432 433 * ``queryset``: A ``QuerySet`` of objects for which the archive serves.434 435 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in436 the ``QuerySet``'s model that the date-based archive should use to437 determine the objects on the page.438 439 **Optional arguments:**440 441 * ``template_name``: The full name of a template to use in rendering the442 page. This lets you override the default template name (see below).443 444 * ``template_loader``: The template loader to use when loading the445 template. By default, it's ``django.template.loader``.446 447 * ``extra_context``: A dictionary of values to add to the template448 context. By default, this is an empty dictionary. If a value in the449 dictionary is callable, the generic view will call it450 just before rendering the template.451 452 * ``allow_empty``: A boolean specifying whether to display the page if no453 objects are available. If this is ``False`` and no objects are available,454 the view will raise a 404 instead of displaying an empty page. By455 default, this is ``True``.456 457 * ``context_processors``: A list of template-context processors to apply to458 the view's template.459 460 * ``template_object_name``: Designates the name of the template variable461 to use in the template context. By default, this is ``'object'``. The462 view will append ``'_list'`` to the value of this parameter in463 determining the variable's name.464 465 * ``mimetype``: The MIME type to use for the resulting document. Defaults466 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.467 468 * ``allow_future``: A boolean specifying whether to include "future"469 objects on this page, where "future" means objects in which the field470 specified in ``date_field`` is greater than the current date/time. By471 default, this is ``False``.472 473 **Template name:**474 475 If ``template_name`` isn't specified, this view will use the template476 ``<app_label>/<model_name>_archive_week.html`` by default.477 478 **Template context:**479 480 In addition to ``extra_context``, the template's context will be:481 482 * ``week``: A ``datetime.date`` object representing the first day of the483 given week.484 485 * ``object_list``: A list of objects available for the given week. This486 variable's name depends on the ``template_object_name`` parameter, which487 is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,488 this variable's name will be ``foo_list``.489 490 ``django.views.generic.date_based.archive_day``491 -----------------------------------------------492 493 **Description:**494 495 A day archive page showing all objects in a given day. Days in the future throw496 a 404 error, regardless of whether any objects exist for future days, unless497 you set ``allow_future`` to ``True``.498 499 **Required arguments:**500 501 * ``year``: The four-digit year for which the archive serves (a string).502 503 * ``month``: The month for which the archive serves, formatted according to504 the ``month_format`` argument.505 506 * ``day``: The day for which the archive serves, formatted according to the507 ``day_format`` argument.508 509 * ``queryset``: A ``QuerySet`` of objects for which the archive serves.510 511 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in512 the ``QuerySet``'s model that the date-based archive should use to513 determine the objects on the page.514 515 **Optional arguments:**516 517 * ``month_format``: A format string that regulates what format the ``month``518 parameter uses. This should be in the syntax accepted by Python's519 :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a520 three-letter month abbreviation. To change it to use numbers, use521 ``"%m"``.522 523 * ``day_format``: Like ``month_format``, but for the ``day`` parameter.524 It defaults to ``"%d"`` (day of the month as a decimal number, 01-31).525 526 * ``template_name``: The full name of a template to use in rendering the527 page. This lets you override the default template name (see below).528 529 * ``template_loader``: The template loader to use when loading the530 template. By default, it's ``django.template.loader``.531 532 * ``extra_context``: A dictionary of values to add to the template533 context. By default, this is an empty dictionary. If a value in the534 dictionary is callable, the generic view will call it535 just before rendering the template.536 537 * ``allow_empty``: A boolean specifying whether to display the page if no538 objects are available. If this is ``False`` and no objects are available,539 the view will raise a 404 instead of displaying an empty page. By540 default, this is ``False``.541 542 * ``context_processors``: A list of template-context processors to apply to543 the view's template.544 545 * ``template_object_name``: Designates the name of the template variable546 to use in the template context. By default, this is ``'object'``. The547 view will append ``'_list'`` to the value of this parameter in548 determining the variable's name.549 550 * ``mimetype``: The MIME type to use for the resulting document. Defaults551 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.552 553 * ``allow_future``: A boolean specifying whether to include "future"554 objects on this page, where "future" means objects in which the field555 specified in ``date_field`` is greater than the current date/time. By556 default, this is ``False``.557 558 **Template name:**559 560 If ``template_name`` isn't specified, this view will use the template561 ``<app_label>/<model_name>_archive_day.html`` by default.562 563 **Template context:**564 565 In addition to ``extra_context``, the template's context will be:566 567 * ``day``: A ``datetime.date`` object representing the given day.568 569 * ``next_day``: A ``datetime.date`` object representing the next day. If570 the next day is in the future, this will be ``None``.571 572 * ``previous_day``: A ``datetime.date`` object representing the previous day.573 Unlike ``next_day``, this will never be ``None``.574 575 * ``object_list``: A list of objects available for the given day. This576 variable's name depends on the ``template_object_name`` parameter, which577 is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,578 this variable's name will be ``foo_list``.579 580 ``django.views.generic.date_based.archive_today``581 -------------------------------------------------582 583 **Description:**584 585 A day archive page showing all objects for *today*. This is exactly the same as586 ``archive_day``, except the ``year``/``month``/``day`` arguments are not used,587 and today's date is used instead.588 589 ``django.views.generic.date_based.object_detail``590 -------------------------------------------------591 592 **Description:**593 594 A page representing an individual object. If the object has a date value in the595 future, the view will throw a 404 error by default, unless you set596 ``allow_future`` to ``True``.597 598 **Required arguments:**599 600 * ``year``: The object's four-digit year (a string).601 602 * ``month``: The object's month , formatted according to the603 ``month_format`` argument.604 605 * ``day``: The object's day , formatted according to the ``day_format``606 argument.607 608 * ``queryset``: A ``QuerySet`` that contains the object.609 610 * ``date_field``: The name of the ``DateField`` or ``DateTimeField`` in611 the ``QuerySet``'s model that the generic view should use to look up the612 object according to ``year``, ``month`` and ``day``.613 614 * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.615 616 If you provide ``object_id``, it should be the value of the primary-key617 field for the object being displayed on this page.618 619 Otherwise, ``slug`` should be the slug of the given object, and620 ``slug_field`` should be the name of the slug field in the ``QuerySet``'s621 model. By default, ``slug_field`` is ``'slug'``.622 623 **Optional arguments:**624 625 * ``month_format``: A format string that regulates what format the ``month``626 parameter uses. This should be in the syntax accepted by Python's627 :func:`~time.strftime`. It's set to ``"%b"`` by default, which is a628 three-letter month abbreviation. To change it to use numbers, use629 ``"%m"``.630 631 * ``day_format``: Like ``month_format``, but for the ``day`` parameter.632 It defaults to ``"%d"`` (day of the month as a decimal number, 01-31).633 634 * ``template_name``: The full name of a template to use in rendering the635 page. This lets you override the default template name (see below).636 637 * ``template_name_field``: The name of a field on the object whose value is638 the template name to use. This lets you store template names in the data.639 In other words, if your object has a field ``'the_template'`` that640 contains a string ``'foo.html'``, and you set ``template_name_field`` to641 ``'the_template'``, then the generic view for this object will use the642 template ``'foo.html'``.643 644 It's a bit of a brain-bender, but it's useful in some cases.645 646 * ``template_loader``: The template loader to use when loading the647 template. By default, it's ``django.template.loader``.648 649 * ``extra_context``: A dictionary of values to add to the template650 context. By default, this is an empty dictionary. If a value in the651 dictionary is callable, the generic view will call it652 just before rendering the template.653 654 * ``context_processors``: A list of template-context processors to apply to655 the view's template.656 657 * ``template_object_name``: Designates the name of the template variable658 to use in the template context. By default, this is ``'object'``.659 660 * ``mimetype``: The MIME type to use for the resulting document. Defaults661 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.662 663 * ``allow_future``: A boolean specifying whether to include "future"664 objects on this page, where "future" means objects in which the field665 specified in ``date_field`` is greater than the current date/time. By666 default, this is ``False``.667 668 **Template name:**669 670 If ``template_name`` isn't specified, this view will use the template671 ``<app_label>/<model_name>_detail.html`` by default.672 673 **Template context:**674 675 In addition to ``extra_context``, the template's context will be:676 677 * ``object``: The object. This variable's name depends on the678 ``template_object_name`` parameter, which is ``'object'`` by default. If679 ``template_object_name`` is ``'foo'``, this variable's name will be680 ``foo``.681 682 .. module:: django.views.generic.list_detail683 684 List/detail generic views685 =========================686 687 The list-detail generic-view framework (in the688 ``django.views.generic.list_detail`` module) is similar to the date-based one,689 except the former simply has two views: a list of objects and an individual690 object page.691 692 ``django.views.generic.list_detail.object_list``693 ------------------------------------------------694 695 **Description:**696 697 A page representing a list of objects.698 699 **Required arguments:**700 701 * ``queryset``: A ``QuerySet`` that represents the objects.702 703 **Optional arguments:**704 705 * ``paginate_by``: An integer specifying how many objects should be706 displayed per page. If this is given, the view will paginate objects with707 ``paginate_by`` objects per page. The view will expect either a ``page``708 query string parameter (via ``GET``) or a ``page`` variable specified in709 the URLconf. See `Notes on pagination`_ below.710 711 * ``page``: The current page number, as an integer, or the string712 ``'last'``. This is 1-based. See `Notes on pagination`_ below.713 714 * ``template_name``: The full name of a template to use in rendering the715 page. This lets you override the default template name (see below).716 717 * ``template_loader``: The template loader to use when loading the718 template. By default, it's ``django.template.loader``.719 720 * ``extra_context``: A dictionary of values to add to the template721 context. By default, this is an empty dictionary. If a value in the722 dictionary is callable, the generic view will call it723 just before rendering the template.724 725 * ``allow_empty``: A boolean specifying whether to display the page if no726 objects are available. If this is ``False`` and no objects are available,727 the view will raise a 404 instead of displaying an empty page. By728 default, this is ``True``.729 730 * ``context_processors``: A list of template-context processors to apply to731 the view's template.732 733 * ``template_object_name``: Designates the name of the template variable734 to use in the template context. By default, this is ``'object'``. The735 view will append ``'_list'`` to the value of this parameter in736 determining the variable's name.737 738 * ``mimetype``: The MIME type to use for the resulting document. Defaults739 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.740 741 **Template name:**742 743 If ``template_name`` isn't specified, this view will use the template744 ``<app_label>/<model_name>_list.html`` by default.745 746 **Template context:**747 748 In addition to ``extra_context``, the template's context will be:749 750 * ``object_list``: The list of objects. This variable's name depends on the751 ``template_object_name`` parameter, which is ``'object'`` by default. If752 ``template_object_name`` is ``'foo'``, this variable's name will be753 ``foo_list``.754 755 * ``is_paginated``: A boolean representing whether the results are756 paginated. Specifically, this is set to ``False`` if the number of757 available objects is less than or equal to ``paginate_by``.758 759 If the results are paginated, the context will contain these extra variables:760 761 * ``paginator``: An instance of ``django.core.paginator.Paginator``.762 763 * ``page_obj``: An instance of ``django.core.paginator.Page``.764 765 Notes on pagination766 ~~~~~~~~~~~~~~~~~~~767 768 If ``paginate_by`` is specified, Django will paginate the results. You can769 specify the page number in the URL in one of two ways:770 771 * Use the ``page`` parameter in the URLconf. For example, this is what772 your URLconf might look like::773 774 (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))775 776 * Pass the page number via the ``page`` query-string parameter. For777 example, a URL would look like this::778 779 /objects/?page=3780 781 * To loop over all the available page numbers, use the ``page_range``782 variable. You can iterate over the list provided by ``page_range``783 to create a link to every page of results.784 785 These values and lists are 1-based, not 0-based, so the first page would be786 represented as page ``1``.787 788 For more on pagination, read the :doc:`pagination documentation789 </topics/pagination>`.790 791 As a special case, you are also permitted to use ``last`` as a value for792 ``page``::793 794 /objects/?page=last795 796 This allows you to access the final page of results without first having to797 determine how many pages there are.798 799 Note that ``page`` *must* be either a valid page number or the value ``last``;800 any other value for ``page`` will result in a 404 error.801 802 ``django.views.generic.list_detail.object_detail``803 --------------------------------------------------804 805 A page representing an individual object.806 807 **Description:**808 809 A page representing an individual object.810 811 **Required arguments:**812 813 * ``queryset``: A ``QuerySet`` that contains the object.814 815 * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.816 817 If you provide ``object_id``, it should be the value of the primary-key818 field for the object being displayed on this page.819 820 Otherwise, ``slug`` should be the slug of the given object, and821 ``slug_field`` should be the name of the slug field in the ``QuerySet``'s822 model. By default, ``slug_field`` is ``'slug'``.823 824 **Optional arguments:**825 826 * ``template_name``: The full name of a template to use in rendering the827 page. This lets you override the default template name (see below).828 829 * ``template_name_field``: The name of a field on the object whose value is830 the template name to use. This lets you store template names in the data.831 In other words, if your object has a field ``'the_template'`` that832 contains a string ``'foo.html'``, and you set ``template_name_field`` to833 ``'the_template'``, then the generic view for this object will use the834 template ``'foo.html'``.835 836 It's a bit of a brain-bender, but it's useful in some cases.837 838 * ``template_loader``: The template loader to use when loading the839 template. By default, it's ``django.template.loader``.840 841 * ``extra_context``: A dictionary of values to add to the template842 context. By default, this is an empty dictionary. If a value in the843 dictionary is callable, the generic view will call it844 just before rendering the template.845 846 * ``context_processors``: A list of template-context processors to apply to847 the view's template.848 849 * ``template_object_name``: Designates the name of the template variable850 to use in the template context. By default, this is ``'object'``.851 852 * ``mimetype``: The MIME type to use for the resulting document. Defaults853 to the value of the :setting:`DEFAULT_CONTENT_TYPE` setting.854 855 **Template name:**856 857 If ``template_name`` isn't specified, this view will use the template858 ``<app_label>/<model_name>_detail.html`` by default.859 860 **Template context:**861 862 In addition to ``extra_context``, the template's context will be:863 864 * ``object``: The object. This variable's name depends on the865 ``template_object_name`` parameter, which is ``'object'`` by default. If866 ``template_object_name`` is ``'foo'``, this variable's name will be867 ``foo``.868 869 .. module:: django.views.generic.create_update870 871 Create/update/delete generic views872 ==================================873 874 The ``django.views.generic.create_update`` module contains a set of functions875 for creating, editing and deleting objects.876 877 ``django.views.generic.create_update.create_object``878 ----------------------------------------------------879 880 **Description:**881 882 A page that displays a form for creating an object, redisplaying the form with883 validation errors (if there are any) and saving the object.884 885 **Required arguments:**886 887 * Either ``form_class`` or ``model`` is required.888 889 If you provide ``form_class``, it should be a ``django.forms.ModelForm``890 subclass. Use this argument when you need to customize the model's form.891 See the :doc:`ModelForm docs </topics/forms/modelforms>` for more892 information.893 894 Otherwise, ``model`` should be a Django model class and the form used895 will be a standard ``ModelForm`` for ``model``.896 897 **Optional arguments:**898 899 * ``post_save_redirect``: A URL to which the view will redirect after900 saving the object. By default, it's ``object.get_absolute_url()``.901 902 ``post_save_redirect`` may contain dictionary string formatting, which903 will be interpolated against the object's field attributes. For example,904 you could use ``post_save_redirect="/polls/%(slug)s/"``.905 906 * ``login_required``: A boolean that designates whether a user must be907 logged in, in order to see the page and save changes. This hooks into the908 Django :doc:`authentication system </topics/auth>`. By default, this is909 ``False``.910 911 If this is ``True``, and a non-logged-in user attempts to visit this page912 or save the form, Django will redirect the request to ``/accounts/login/``.913 914 * ``template_name``: The full name of a template to use in rendering the915 page. This lets you override the default template name (see below).916 917 * ``template_loader``: The template loader to use when loading the918 template. By default, it's ``django.template.loader``.919 920 * ``extra_context``: A dictionary of values to add to the template921 context. By default, this is an empty dictionary. If a value in the922 dictionary is callable, the generic view will call it923 just before rendering the template.924 925 * ``context_processors``: A list of template-context processors to apply to926 the view's template.927 928 **Template name:**929 930 If ``template_name`` isn't specified, this view will use the template931 ``<app_label>/<model_name>_form.html`` by default.932 933 **Template context:**934 935 In addition to ``extra_context``, the template's context will be:936 937 * ``form``: A ``django.forms.ModelForm`` instance representing the form938 for creating the object. This lets you refer to form fields easily in the939 template system.940 941 For example, if the model has two fields, ``name`` and ``address``::942 943 <form action="" method="post">944 <p>{{ form.name.label_tag }} {{ form.name }}</p>945 <p>{{ form.address.label_tag }} {{ form.address }}</p>946 </form>947 948 See the :doc:`forms documentation </topics/forms/index>` for more949 information about using ``Form`` objects in templates.950 951 ``django.views.generic.create_update.update_object``952 ----------------------------------------------------953 954 **Description:**955 956 A page that displays a form for editing an existing object, redisplaying the957 form with validation errors (if there are any) and saving changes to the958 object. This uses a form automatically generated from the object's959 model class.960 961 **Required arguments:**962 963 * Either ``form_class`` or ``model`` is required.964 965 If you provide ``form_class``, it should be a ``django.forms.ModelForm``966 subclass. Use this argument when you need to customize the model's form.967 See the :doc:`ModelForm docs </topics/forms/modelforms>` for more968 information.969 970 Otherwise, ``model`` should be a Django model class and the form used971 will be a standard ``ModelForm`` for ``model``.972 973 * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.974 975 If you provide ``object_id``, it should be the value of the primary-key976 field for the object being displayed on this page.977 978 Otherwise, ``slug`` should be the slug of the given object, and979 ``slug_field`` should be the name of the slug field in the ``QuerySet``'s980 model. By default, ``slug_field`` is ``'slug'``.981 982 **Optional arguments:**983 984 * ``post_save_redirect``: A URL to which the view will redirect after985 saving the object. By default, it's ``object.get_absolute_url()``.986 987 ``post_save_redirect`` may contain dictionary string formatting, which988 will be interpolated against the object's field attributes. For example,989 you could use ``post_save_redirect="/polls/%(slug)s/"``.990 991 * ``login_required``: A boolean that designates whether a user must be992 logged in, in order to see the page and save changes. This hooks into the993 Django :doc:`authentication system </topics/auth>`. By default, this is994 ``False``.995 996 If this is ``True``, and a non-logged-in user attempts to visit this page997 or save the form, Django will redirect to :setting:`LOGIN_URL` (which998 defaults to ``/accounts/login/``).999 1000 * ``template_name``: The full name of a template to use in rendering the1001 page. This lets you override the default template name (see below).1002 1003 * ``template_loader``: The template loader to use when loading the1004 template. By default, it's ``django.template.loader``.1005 1006 * ``extra_context``: A dictionary of values to add to the template1007 context. By default, this is an empty dictionary. If a value in the1008 dictionary is callable, the generic view will call it1009 just before rendering the template.1010 1011 * ``context_processors``: A list of template-context processors to apply to1012 the view's template.1013 1014 * ``template_object_name``: Designates the name of the template variable1015 to use in the template context. By default, this is ``'object'``.1016 1017 **Template name:**1018 1019 If ``template_name`` isn't specified, this view will use the template1020 ``<app_label>/<model_name>_form.html`` by default.1021 1022 **Template context:**1023 1024 In addition to ``extra_context``, the template's context will be:1025 1026 * ``form``: A ``django.forms.ModelForm`` instance representing the form1027 for editing the object. This lets you refer to form fields easily in the1028 template system.1029 1030 For example, if the model has two fields, ``name`` and ``address``::1031 1032 <form action="" method="post">1033 <p>{{ form.name.label_tag }} {{ form.name }}</p>1034 <p>{{ form.address.label_tag }} {{ form.address }}</p>1035 </form>1036 1037 See the :doc:`forms documentation </topics/forms/index>` for more1038 information about using ``Form`` objects in templates.1039 1040 * ``object``: The original object being edited. This variable's name1041 depends on the ``template_object_name`` parameter, which is ``'object'``1042 by default. If ``template_object_name`` is ``'foo'``, this variable's1043 name will be ``foo``.1044 1045 ``django.views.generic.create_update.delete_object``1046 ----------------------------------------------------1047 1048 **Description:**1049 1050 A view that displays a confirmation page and deletes an existing object. The1051 given object will only be deleted if the request method is ``POST``. If this1052 view is fetched via ``GET``, it will display a confirmation page that should1053 contain a form that POSTs to the same URL.1054 1055 **Required arguments:**1056 1057 * ``model``: The Django model class of the object that the form will1058 delete.1059 1060 * Either ``object_id`` or (``slug`` *and* ``slug_field``) is required.1061 1062 If you provide ``object_id``, it should be the value of the primary-key1063 field for the object being displayed on this page.1064 1065 Otherwise, ``slug`` should be the slug of the given object, and1066 ``slug_field`` should be the name of the slug field in the ``QuerySet``'s1067 model. By default, ``slug_field`` is ``'slug'``.1068 1069 * ``post_delete_redirect``: A URL to which the view will redirect after1070 deleting the object.1071 1072 **Optional arguments:**1073 1074 * ``login_required``: A boolean that designates whether a user must be1075 logged in, in order to see the page and save changes. This hooks into the1076 Django :doc:`authentication system </topics/auth>`. By default, this is1077 ``False``.1078 1079 If this is ``True``, and a non-logged-in user attempts to visit this page1080 or save the form, Django will redirect to :setting:`LOGIN_URL` (which1081 defaults to ``/accounts/login/``).1082 1083 * ``template_name``: The full name of a template to use in rendering the1084 page. This lets you override the default template name (see below).1085 1086 * ``template_loader``: The template loader to use when loading the1087 template. By default, it's ``django.template.loader``.1088 1089 * ``extra_context``: A dictionary of values to add to the template1090 context. By default, this is an empty dictionary. If a value in the1091 dictionary is callable, the generic view will call it1092 just before rendering the template.1093 1094 * ``context_processors``: A list of template-context processors to apply to1095 the view's template.1096 1097 * ``template_object_name``: Designates the name of the template variable1098 to use in the template context. By default, this is ``'object'``.1099 1100 **Template name:**1101 1102 If ``template_name`` isn't specified, this view will use the template1103 ``<app_label>/<model_name>_confirm_delete.html`` by default.1104 1105 **Template context:**1106 1107 In addition to ``extra_context``, the template's context will be:1108 1109 * ``object``: The original object that's about to be deleted. This1110 variable's name depends on the ``template_object_name`` parameter, which1111 is ``'object'`` by default. If ``template_object_name`` is ``'foo'``,1112 this variable's name will be ``foo``. -
docs/ref/index.txt
diff --git a/docs/ref/index.txt b/docs/ref/index.txt index db09afe..32b2631 100644
a b API Reference 24 24 unicode 25 25 utils 26 26 validators 27 28 Deprecated features29 -------------------30 31 .. toctree::32 :maxdepth: 133 34 generic-views -
docs/releases/1.1-alpha-1.txt
diff --git a/docs/releases/1.1-alpha-1.txt b/docs/releases/1.1-alpha-1.txt index b123a06..10b0d5d 100644
a b Other new features and changes introduced since Django 1.0 include: 88 88 which return the list of hidden -- i.e., ``<input type="hidden">`` -- and 89 89 visible fields on the form, respectively. 90 90 91 * The ``redirect_to`` generic view (see :doc:`the generic views documentation92 </ref/generic-views>`)now accepts an additional keyword argument91 * The ``redirect_to`` generic view 92 now accepts an additional keyword argument 93 93 ``permanent``. If ``permanent`` is ``True``, the view will emit an HTTP 94 94 permanent redirect (status code 301). If ``False``, the view will emit an HTTP 95 95 temporary redirect (status code 302). -
docs/releases/1.1.txt
diff --git a/docs/releases/1.1.txt b/docs/releases/1.1.txt index 15e9c84..1294011 100644
a b Other new features and changes introduced since Django 1.0 include: 396 396 which return the list of hidden -- i.e., ``<input type="hidden">`` -- and 397 397 visible fields on the form, respectively. 398 398 399 * The ``redirect_to`` generic view (see :doc:`the generic views documentation400 </ref/generic-views>`)now accepts an additional keyword argument399 * The ``redirect_to`` generic view 400 now accepts an additional keyword argument 401 401 ``permanent``. If ``permanent`` is ``True``, the view will emit an HTTP 402 402 permanent redirect (status code 301). If ``False``, the view will emit an HTTP 403 403 temporary redirect (status code 302). -
docs/releases/1.3-alpha-1.txt
diff --git a/docs/releases/1.3-alpha-1.txt b/docs/releases/1.3-alpha-1.txt index f1ff23b..4e6c72a 100644
a b the basis for reusable applications that can be easily extended. 41 41 See :doc:`the documentation on Class-based Generic Views 42 42 </topics/class-based-views>` for more details. There is also a document to 43 43 help you :doc:`convert your function-based generic views to class-based 44 views </topics/generic-views-migration>`.44 views <https://docs.djangoproject.com/en/1.4/topics/generic-views-migration/>`_. 45 45 46 46 Logging 47 47 ~~~~~~~ -
docs/releases/1.3.txt
diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt index 224cd47..3548a00 100644
a b used as the basis for reusable applications that can be easily 81 81 extended. 82 82 83 83 See :doc:`the documentation on class-based generic views</topics/class-based-views>` 84 for more details. There is also a document to help you :doc:`convert84 for more details. There is also a document to help you `convert 85 85 your function-based generic views to class-based 86 views </topics/generic-views-migration>`.86 views <https://docs.djangoproject.com/en/1.4/topics/generic-views-migration/>`_. 87 87 88 88 Logging 89 89 ~~~~~~~ -
docs/topics/auth.txt
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt index d266b92..b3ed834 100644
a b To limit access to a :doc:`class-based generic view </ref/class-based-views>`, 1472 1472 decorate the :meth:`View.dispatch <django.views.generic.base.View.dispatch>` 1473 1473 method on the class. See :ref:`decorating-class-based-views` for details. 1474 1474 1475 Function-based generic views1476 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~1477 1478 To limit access to a :doc:`function-based generic view </ref/generic-views>`,1479 write a thin wrapper around the view, and point your URLconf to your wrapper1480 instead of the generic view itself. For example::1481 1482 from django.views.generic.date_based import object_detail1483 1484 @login_required1485 def limited_object_detail(*args, **kwargs):1486 return object_detail(*args, **kwargs)1487 1488 1475 .. _permissions: 1489 1476 1490 1477 Permissions -
docs/topics/class-based-views.txt
diff --git a/docs/topics/class-based-views.txt b/docs/topics/class-based-views.txt index e1e2618..6df8f78 100644
a b Class-based generic views 6 6 7 7 .. note:: 8 8 Prior to Django 1.3, generic views were implemented as functions. The 9 function-based implementation has been deprecated in favor of the9 function-based implementation has been removed in favor of the 10 10 class-based approach described here. 11 11 12 For details on the previous generic views implementation,13 see the :doc:`topic guide </topics/generic-views>` and14 :doc:`detailed reference </ref/generic-views>`.15 16 12 Writing Web applications can be monotonous, because we repeat certain patterns 17 13 again and again. Django tries to take away some of that monotony at the model 18 14 and template layers, but Web developers also experience this boredom at the view -
deleted file docs/topics/generic-views-migration.txt
diff --git a/docs/topics/generic-views-migration.txt b/docs/topics/generic-views-migration.txt deleted file mode 100644 index 0647336..0000000
+ - 1 ======================================2 Migrating function-based generic views3 ======================================4 5 All the :doc:`function-based generic views</ref/generic-views>`6 that existed in Django 1.2 have analogs as :doc:`class-based generic7 views</ref/class-based-views>` in Django 1.3. The feature set8 exposed in those function-based views can be replicated in a9 class-based way.10 11 How to migrate12 ==============13 14 Replace generic views with generic classes15 ------------------------------------------16 17 Existing usage of function-based generic views should be replaced with18 their class-based analogs:19 20 ==================================================== ====================================================21 Old function-based generic view New class-based generic view22 ==================================================== ====================================================23 ``django.views.generic.simple.direct_to_template`` :class:`django.views.generic.base.TemplateView`24 ``django.views.generic.simple.redirect_to`` :class:`django.views.generic.base.RedirectView`25 ``django.views.generic.list_detail.object_list`` :class:`django.views.generic.list.ListView`26 ``django.views.generic.list_detail.object_detail`` :class:`django.views.generic.detail.DetailView`27 ``django.views.generic.create_update.create_object`` :class:`django.views.generic.edit.CreateView`28 ``django.views.generic.create_update.update_object`` :class:`django.views.generic.edit.UpdateView`29 ``django.views.generic.create_update.delete_object`` :class:`django.views.generic.edit.DeleteView`30 ``django.views.generic.date_based.archive_index`` :class:`django.views.generic.dates.ArchiveIndexView`31 ``django.views.generic.date_based.archive_year`` :class:`django.views.generic.dates.YearArchiveView`32 ``django.views.generic.date_based.archive_month`` :class:`django.views.generic.dates.MonthArchiveView`33 ``django.views.generic.date_based.archive_week`` :class:`django.views.generic.dates.WeekArchiveView`34 ``django.views.generic.date_based.archive_day`` :class:`django.views.generic.dates.DayArchiveView`35 ``django.views.generic.date_based.archive_today`` :class:`django.views.generic.dates.TodayArchiveView`36 ``django.views.generic.date_based.object_detail`` :class:`django.views.generic.dates.DateDetailView`37 ==================================================== ====================================================38 39 To do this, replace the reference to the generic view function with40 a ``as_view()`` instantiation of the class-based view. For example,41 the old-style ``direct_to_template`` pattern::42 43 ('^about/$', direct_to_template, {'template': 'about.html'})44 45 can be replaced with an instance of46 :class:`~django.views.generic.base.TemplateView`::47 48 ('^about/$', TemplateView.as_view(template_name='about.html'))49 50 ``template`` argument to ``direct_to_template`` views51 -----------------------------------------------------52 53 The ``template`` argument to the ``direct_to_template`` view has been renamed54 ``template_name``. This has been done to maintain consistency with other views.55 56 ``object_id`` argument to detail views57 --------------------------------------58 59 The object_id argument to the ``object_detail`` view has been renamed60 ``pk`` on the :class:`~django.views.generic.detail.DetailView`.61 62 ``template_object_name``63 ------------------------64 65 ``template_object_name`` has been renamed ``context_object_name``,66 reflecting the fact that the context data can be used for purposes67 other than template rendering (e.g., to populate JSON output).68 69 The ``_list`` suffix on list views70 ----------------------------------71 72 In a function-based :class:`ListView`, the ``template_object_name``73 was appended with the suffix ``'_list'`` to yield the final context74 variable name. In a class-based ``ListView``, the75 ``context_object_name`` is used verbatim. The ``'_list'`` suffix76 is only applied when generating a default context object name.77 78 The context data for ``object_list`` views79 ------------------------------------------80 81 The context provided by :class:`~django.views.generic.list.MultipleObjectMixin`82 is quite different from that provided by ``object_list``, with most pagination83 related variables replaced by a single ``page_obj`` object. The following are no84 longer provided:85 86 * ``first_on_page``87 * ``has_next``88 * ``has_previous``89 * ``hits``90 * ``last_on_page``91 * ``next``92 * ``page_range``93 * ``page``94 * ``pages``95 * ``previous``96 * ``results_per_page``97 98 ``extra_context``99 -----------------100 101 Function-based generic views provided an ``extra_context`` argument102 as way to insert extra items into the context at time of rendering.103 104 Class-based views don't provide an ``extra_context`` argument.105 Instead, you subclass the view, overriding :meth:`get_context_data()`.106 For example::107 108 class MyListView(ListView):109 def get_context_data(self, **kwargs):110 context = super(MyListView, self).get_context_data(**kwargs)111 context.update({112 'foo': 42,113 'bar': 37114 })115 return context116 117 ``post_save_redirect`` argument to create and update views118 ----------------------------------------------------------119 120 The ``post_save_redirect`` argument to the create and update views121 has been renamed ``success_url`` on the122 :class:`~django.views.generic.edit.ModelFormMixin`.123 124 ``mimetype``125 ------------126 127 Some function-based generic views provided a ``mimetype`` argument128 as way to control the mimetype of the response.129 130 Class-based views don't provide a ``mimetype`` argument. Instead, you131 subclass the view, overriding132 :meth:`TemplateResponseMixin.render_to_response()` and pass in arguments for133 the TemplateResponse constructor. For example::134 135 class MyListView(ListView):136 def render_to_response(self, context, **kwargs):137 return super(MyListView, self).render_to_response(context,138 content_type='application/json', **kwargs)139 140 ``context_processors``141 ----------------------142 143 Some function-based generic views provided a ``context_processors``144 argument that could be used to force the use of specialized context145 processors when rendering template content.146 147 Class-based views don't provide a ``context_processors`` argument.148 Instead, you subclass the view, overriding149 :meth:`TemplateResponseMixin.render_to_response()`, and passing in150 a context instance that has been instantiated with the processors151 you want to use. For example::152 153 class MyListView(ListView):154 def render_to_response(self, context, **kwargs):155 return super(MyListView, self).render_to_response(156 RequestContext(self.request,157 context,158 processors=[custom_processor]),159 **kwargs) -
deleted file docs/topics/generic-views.txt
diff --git a/docs/topics/generic-views.txt b/docs/topics/generic-views.txt deleted file mode 100644 index 77232bc..0000000
+ - 1 =============2 Generic views3 =============4 5 6 .. versionchanged:: 1.37 8 .. note::9 10 From Django 1.3, function-based generic views have been deprecated in favor11 of a class-based approach, described in the class-based views :doc:`topic12 guide </topics/class-based-views>` and :doc:`detailed reference13 </ref/class-based-views>`.14 15 Writing Web applications can be monotonous, because we repeat certain patterns16 again and again. Django tries to take away some of that monotony at the model17 and template layers, but Web developers also experience this boredom at the view18 level.19 20 Django's *generic views* were developed to ease that pain. They take certain21 common idioms and patterns found in view development and abstract them so that22 you can quickly write common views of data without having to write too much23 code.24 25 We can recognize certain common tasks, like displaying a list of objects, and26 write code that displays a list of *any* object. Then the model in question can27 be passed as an extra argument to the URLconf.28 29 Django ships with generic views to do the following:30 31 * Perform common "simple" tasks: redirect to a different page and32 render a given template.33 34 * Display list and detail pages for a single object. If we were creating an35 application to manage conferences then a ``talk_list`` view and a36 ``registered_user_list`` view would be examples of list views. A single37 talk page is an example of what we call a "detail" view.38 39 * Present date-based objects in year/month/day archive pages,40 associated detail, and "latest" pages. The Django Weblog's41 (https://www.djangoproject.com/weblog/) year, month, and42 day archives are built with these, as would be a typical43 newspaper's archives.44 45 * Allow users to create, update, and delete objects -- with or46 without authorization.47 48 Taken together, these views provide easy interfaces to perform the most common49 tasks developers encounter.50 51 Using generic views52 ===================53 54 All of these views are used by creating configuration dictionaries in55 your URLconf files and passing those dictionaries as the third member of the56 URLconf tuple for a given pattern.57 58 For example, here's a simple URLconf you could use to present a static "about"59 page::60 61 from django.conf.urls import patterns, url, include62 from django.views.generic.simple import direct_to_template63 64 urlpatterns = patterns('',65 ('^about/$', direct_to_template, {66 'template': 'about.html'67 })68 )69 70 Though this might seem a bit "magical" at first glance -- look, a view with no71 code! --, actually the ``direct_to_template`` view simply grabs information from72 the extra-parameters dictionary and uses that information when rendering the73 view.74 75 Because this generic view -- and all the others -- is a regular view function76 like any other, we can reuse it inside our own views. As an example, let's77 extend our "about" example to map URLs of the form ``/about/<whatever>/`` to78 statically rendered ``about/<whatever>.html``. We'll do this by first modifying79 the URLconf to point to a view function:80 81 .. parsed-literal::82 83 from django.conf.urls import patterns, url, include84 from django.views.generic.simple import direct_to_template85 **from books.views import about_pages**86 87 urlpatterns = patterns('',88 ('^about/$', direct_to_template, {89 'template': 'about.html'90 }),91 **('^about/(\\w+)/$', about_pages),**92 )93 94 Next, we'll write the ``about_pages`` view::95 96 from django.http import Http40497 from django.template import TemplateDoesNotExist98 from django.views.generic.simple import direct_to_template99 100 def about_pages(request, page):101 try:102 return direct_to_template(request, template="about/%s.html" % page)103 except TemplateDoesNotExist:104 raise Http404()105 106 Here we're treating ``direct_to_template`` like any other function. Since it107 returns an ``HttpResponse``, we can simply return it as-is. The only slightly108 tricky business here is dealing with missing templates. We don't want a109 nonexistent template to cause a server error, so we catch110 ``TemplateDoesNotExist`` exceptions and return 404 errors instead.111 112 .. admonition:: Is there a security vulnerability here?113 114 Sharp-eyed readers may have noticed a possible security hole: we're115 constructing the template name using interpolated content from the browser116 (``template="about/%s.html" % page``). At first glance, this looks like a117 classic *directory traversal* vulnerability. But is it really?118 119 Not exactly. Yes, a maliciously crafted value of ``page`` could cause120 directory traversal, but although ``page`` *is* taken from the request URL,121 not every value will be accepted. The key is in the URLconf: we're using122 the regular expression ``\w+`` to match the ``page`` part of the URL, and123 ``\w`` only accepts letters and numbers. Thus, any malicious characters124 (dots and slashes, here) will be rejected by the URL resolver before they125 reach the view itself.126 127 Generic views of objects128 ========================129 130 The ``direct_to_template`` certainly is useful, but Django's generic views131 really shine when it comes to presenting views on your database content. Because132 it's such a common task, Django comes with a handful of built-in generic views133 that make generating list and detail views of objects incredibly easy.134 135 Let's take a look at one of these generic views: the "object list" view. We'll136 be using these models::137 138 # models.py139 from django.db import models140 141 class Publisher(models.Model):142 name = models.CharField(max_length=30)143 address = models.CharField(max_length=50)144 city = models.CharField(max_length=60)145 state_province = models.CharField(max_length=30)146 country = models.CharField(max_length=50)147 website = models.URLField()148 149 def __unicode__(self):150 return self.name151 152 class Meta:153 ordering = ["-name"]154 155 class Book(models.Model):156 title = models.CharField(max_length=100)157 authors = models.ManyToManyField('Author')158 publisher = models.ForeignKey(Publisher)159 publication_date = models.DateField()160 161 To build a list page of all publishers, we'd use a URLconf along these lines::162 163 from django.conf.urls import patterns, url, include164 from django.views.generic import list_detail165 from books.models import Publisher166 167 publisher_info = {168 "queryset" : Publisher.objects.all(),169 }170 171 urlpatterns = patterns('',172 (r'^publishers/$', list_detail.object_list, publisher_info)173 )174 175 That's all the Python code we need to write. We still need to write a template,176 however. We could explicitly tell the ``object_list`` view which template to use177 by including a ``template_name`` key in the extra arguments dictionary, but in178 the absence of an explicit template Django will infer one from the object's179 name. In this case, the inferred template will be180 ``"books/publisher_list.html"`` -- the "books" part comes from the name of the181 app that defines the model, while the "publisher" bit is just the lowercased182 version of the model's name.183 184 .. highlightlang:: html+django185 186 This template will be rendered against a context containing a variable called187 ``object_list`` that contains all the publisher objects. A very simple template188 might look like the following::189 190 {% extends "base.html" %}191 192 {% block content %}193 <h2>Publishers</h2>194 <ul>195 {% for publisher in object_list %}196 <li>{{ publisher.name }}</li>197 {% endfor %}198 </ul>199 {% endblock %}200 201 That's really all there is to it. All the cool features of generic views come202 from changing the "info" dictionary passed to the generic view. The203 :doc:`generic views reference</ref/generic-views>` documents all the generic204 views and all their options in detail; the rest of this document will consider205 some of the common ways you might customize and extend generic views.206 207 Extending generic views208 =======================209 210 .. highlightlang:: python211 212 There's no question that using generic views can speed up development213 substantially. In most projects, however, there comes a moment when the214 generic views no longer suffice. Indeed, the most common question asked by new215 Django developers is how to make generic views handle a wider array of216 situations.217 218 Luckily, in nearly every one of these cases, there are ways to simply extend219 generic views to handle a larger array of use cases. These situations usually220 fall into a handful of patterns dealt with in the sections that follow.221 222 Making "friendly" template contexts223 -----------------------------------224 225 You might have noticed that our sample publisher list template stores all the226 books in a variable named ``object_list``. While this works just fine, it isn't227 all that "friendly" to template authors: they have to "just know" that they're228 dealing with publishers here. A better name for that variable would be229 ``publisher_list``; that variable's content is pretty obvious.230 231 We can change the name of that variable easily with the ``template_object_name``232 argument:233 234 .. parsed-literal::235 236 publisher_info = {237 "queryset" : Publisher.objects.all(),238 **"template_object_name" : "publisher",**239 }240 241 urlpatterns = patterns('',242 (r'^publishers/$', list_detail.object_list, publisher_info)243 )244 245 Providing a useful ``template_object_name`` is always a good idea. Your246 coworkers who design templates will thank you.247 248 Adding extra context249 --------------------250 251 Often you simply need to present some extra information beyond that provided by252 the generic view. For example, think of showing a list of all the books on each253 publisher detail page. The ``object_detail`` generic view provides the254 publisher to the context, but it seems there's no way to get additional255 information in that template.256 257 But there is: all generic views take an extra optional parameter,258 ``extra_context``. This is a dictionary of extra objects that will be added to259 the template's context. So, to provide the list of all books on the detail260 detail view, we'd use an info dict like this:261 262 .. parsed-literal::263 264 from books.models import Publisher, **Book**265 266 publisher_info = {267 "queryset" : Publisher.objects.all(),268 "template_object_name" : "publisher",269 **"extra_context" : {"book_list" : Book.objects.all()}**270 }271 272 This would populate a ``{{ book_list }}`` variable in the template context.273 This pattern can be used to pass any information down into the template for the274 generic view. It's very handy.275 276 However, there's actually a subtle bug here -- can you spot it?277 278 The problem has to do with when the queries in ``extra_context`` are evaluated.279 Because this example puts ``Book.objects.all()`` in the URLconf, it will280 be evaluated only once (when the URLconf is first loaded). Once you add or281 remove books, you'll notice that the generic view doesn't reflect those282 changes until you reload the Web server (see :ref:`caching-and-querysets`283 for more information about when QuerySets are cached and evaluated).284 285 .. note::286 287 This problem doesn't apply to the ``queryset`` generic view argument. Since288 Django knows that particular QuerySet should *never* be cached, the generic289 view takes care of clearing the cache when each view is rendered.290 291 The solution is to use a callback in ``extra_context`` instead of a value. Any292 callable (i.e., a function) that's passed to ``extra_context`` will be evaluated293 when the view is rendered (instead of only once). You could do this with an294 explicitly defined function:295 296 .. parsed-literal::297 298 def get_books():299 return Book.objects.all()300 301 publisher_info = {302 "queryset" : Publisher.objects.all(),303 "template_object_name" : "publisher",304 "extra_context" : **{"book_list" : get_books}**305 }306 307 or you could use a less obvious but shorter version that relies on the fact that308 ``Book.objects.all`` is itself a callable:309 310 .. parsed-literal::311 312 publisher_info = {313 "queryset" : Publisher.objects.all(),314 "template_object_name" : "publisher",315 "extra_context" : **{"book_list" : Book.objects.all}**316 }317 318 Notice the lack of parentheses after ``Book.objects.all``; this references319 the function without actually calling it (which the generic view will do later).320 321 Viewing subsets of objects322 --------------------------323 324 Now let's take a closer look at this ``queryset`` key we've been using all325 along. Most generic views take one of these ``queryset`` arguments -- it's how326 the view knows which set of objects to display (see :doc:`/topics/db/queries` for327 more information about ``QuerySet`` objects, and see the328 :doc:`generic views reference</ref/generic-views>` for the complete details).329 330 To pick a simple example, we might want to order a list of books by331 publication date, with the most recent first:332 333 .. parsed-literal::334 335 book_info = {336 "queryset" : Book.objects.all().order_by("-publication_date"),337 }338 339 urlpatterns = patterns('',340 (r'^publishers/$', list_detail.object_list, publisher_info),341 **(r'^books/$', list_detail.object_list, book_info),**342 )343 344 345 That's a pretty simple example, but it illustrates the idea nicely. Of course,346 you'll usually want to do more than just reorder objects. If you want to347 present a list of books by a particular publisher, you can use the same348 technique:349 350 .. parsed-literal::351 352 **acme_books = {**353 **"queryset": Book.objects.filter(publisher__name="Acme Publishing"),**354 **"template_name" : "books/acme_list.html"**355 **}**356 357 urlpatterns = patterns('',358 (r'^publishers/$', list_detail.object_list, publisher_info),359 **(r'^books/acme/$', list_detail.object_list, acme_books),**360 )361 362 Notice that along with a filtered ``queryset``, we're also using a custom363 template name. If we didn't, the generic view would use the same template as the364 "vanilla" object list, which might not be what we want.365 366 Also notice that this isn't a very elegant way of doing publisher-specific367 books. If we want to add another publisher page, we'd need another handful of368 lines in the URLconf, and more than a few publishers would get unreasonable.369 We'll deal with this problem in the next section.370 371 .. note::372 373 If you get a 404 when requesting ``/books/acme/``, check to ensure you374 actually have a Publisher with the name 'ACME Publishing'. Generic375 views have an ``allow_empty`` parameter for this case. See the376 :doc:`generic views reference</ref/generic-views>` for more details.377 378 Complex filtering with wrapper functions379 ----------------------------------------380 381 Another common need is to filter down the objects given in a list page by some382 key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but383 what if we wanted to write a view that displayed all the books by some arbitrary384 publisher? We can "wrap" the ``object_list`` generic view to avoid writing a lot385 of code by hand. As usual, we'll start by writing a URLconf:386 387 .. parsed-literal::388 389 from books.views import books_by_publisher390 391 urlpatterns = patterns('',392 (r'^publishers/$', list_detail.object_list, publisher_info),393 **(r'^books/(\\w+)/$', books_by_publisher),**394 )395 396 Next, we'll write the ``books_by_publisher`` view itself::397 398 from django.http import Http404399 from django.views.generic import list_detail400 from books.models import Book, Publisher401 402 def books_by_publisher(request, name):403 404 # Look up the publisher (and raise a 404 if it can't be found).405 try:406 publisher = Publisher.objects.get(name__iexact=name)407 except Publisher.DoesNotExist:408 raise Http404409 410 # Use the object_list view for the heavy lifting.411 return list_detail.object_list(412 request,413 queryset = Book.objects.filter(publisher=publisher),414 template_name = "books/books_by_publisher.html",415 template_object_name = "books",416 extra_context = {"publisher" : publisher}417 )418 419 This works because there's really nothing special about generic views -- they're420 just Python functions. Like any view function, generic views expect a certain421 set of arguments and return ``HttpResponse`` objects. Thus, it's incredibly easy422 to wrap a small function around a generic view that does additional work before423 (or after; see the next section) handing things off to the generic view.424 425 .. note::426 427 Notice that in the preceding example we passed the current publisher being428 displayed in the ``extra_context``. This is usually a good idea in wrappers429 of this nature; it lets the template know which "parent" object is currently430 being browsed.431 432 Performing extra work433 ---------------------434 435 The last common pattern we'll look at involves doing some extra work before436 or after calling the generic view.437 438 Imagine we had a ``last_accessed`` field on our ``Author`` object that we were439 using to keep track of the last time anybody looked at that author::440 441 # models.py442 443 class Author(models.Model):444 salutation = models.CharField(max_length=10)445 first_name = models.CharField(max_length=30)446 last_name = models.CharField(max_length=40)447 email = models.EmailField()448 headshot = models.ImageField(upload_to='/tmp')449 last_accessed = models.DateTimeField()450 451 The generic ``object_detail`` view, of course, wouldn't know anything about this452 field, but once again we could easily write a custom view to keep that field453 updated.454 455 First, we'd need to add an author detail bit in the URLconf to point to a456 custom view:457 458 .. parsed-literal::459 460 from books.views import author_detail461 462 urlpatterns = patterns('',463 #...464 **(r'^authors/(?P<author_id>\\d+)/$', author_detail),**465 )466 467 Then we'd write our wrapper function::468 469 import datetime470 from books.models import Author471 from django.views.generic import list_detail472 from django.shortcuts import get_object_or_404473 474 def author_detail(request, author_id):475 # Look up the Author (and raise a 404 if she's not found)476 author = get_object_or_404(Author, pk=author_id)477 478 # Record the last accessed date479 author.last_accessed = datetime.datetime.now()480 author.save()481 482 # Show the detail page483 return list_detail.object_detail(484 request,485 queryset = Author.objects.all(),486 object_id = author_id,487 )488 489 .. note::490 491 This code won't actually work unless you create a492 ``books/author_detail.html`` template.493 494 We can use a similar idiom to alter the response returned by the generic view.495 If we wanted to provide a downloadable plain-text version of the list of496 authors, we could use a view like this::497 498 def author_list_plaintext(request):499 response = list_detail.object_list(500 request,501 queryset = Author.objects.all(),502 mimetype = "text/plain",503 template_name = "books/author_list.txt"504 )505 response["Content-Disposition"] = "attachment; filename=authors.txt"506 return response507 508 This works because the generic views return simple ``HttpResponse`` objects509 that can be treated like dictionaries to set HTTP headers. This510 ``Content-Disposition`` business, by the way, instructs the browser to511 download and save the page instead of displaying it in the browser. -
docs/topics/http/generic-views.txt
diff --git a/docs/topics/http/generic-views.txt b/docs/topics/http/generic-views.txt index 15f895e..fdaa27d 100644
a b 2 2 Generic views 3 3 ============= 4 4 5 See :doc:`/ref/ generic-views`.5 See :doc:`/ref/class-based-views`. -
docs/topics/http/urls.txt
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 73c06ca..ee1d4e8 100644
a b Old:: 416 416 from django.conf.urls import patterns, url, include 417 417 418 418 urlpatterns = patterns('', 419 (r'^$', ' django.views.generic.date_based.archive_index'),420 (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', ' django.views.generic.date_based.archive_month'),419 (r'^$', 'myapp.views.app_index'), 420 (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'myapp.views.month_display'), 421 421 (r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'), 422 422 ) 423 423 … … New:: 425 425 426 426 from django.conf.urls import patterns, url, include 427 427 428 urlpatterns = patterns(' django.views.generic.date_based',429 (r'^$', 'a rchive_index'),430 (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$',' archive_month'),428 urlpatterns = patterns('myapp.views', 429 (r'^$', 'app_index'), 430 (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','month_display'), 431 431 ) 432 432 433 433 urlpatterns += patterns('weblog.views', … … In this example, for a request to ``/blog/2005/``, Django will call the 579 579 580 580 year='2005', foo='bar' 581 581 582 This technique is used in :doc:`generic views </ref/generic-views>` and inthe582 This technique is used in the 583 583 :doc:`syndication framework </ref/contrib/syndication>` to pass metadata and 584 584 options to views. 585 585 -
docs/topics/index.txt
diff --git a/docs/topics/index.txt b/docs/topics/index.txt index 4b33099..95ca76e 100644
a b Introductions to all the key parts of Django you'll need to know: 12 12 forms/index 13 13 templates 14 14 class-based-views 15 generic-views-migration16 15 files 17 16 testing 18 17 auth … … Introductions to all the key parts of Django you'll need to know: 27 26 serialization 28 27 settings 29 28 signals 30 31 Deprecated features32 -------------------33 34 .. toctree::35 :maxdepth: 136 37 generic-views -
tests/regressiontests/special_headers/tests.py
diff --git a/tests/regressiontests/special_headers/tests.py b/tests/regressiontests/special_headers/tests.py index 4de518c..087bfe9 100644
a b 1 import warnings2 3 1 from django.contrib.auth.models import User 4 2 from django.test import TestCase 5 3 … … class SpecialHeadersTest(TestCase): 8 6 fixtures = ['data.xml'] 9 7 urls = 'regressiontests.special_headers.urls' 10 8 11 def setUp(self):12 self.save_warnings_state()13 warnings.filterwarnings('ignore', category=DeprecationWarning,14 module='django.views.generic.list_detail')15 16 def tearDown(self):17 self.restore_warnings_state()18 19 9 def test_xheaders(self): 20 10 user = User.objects.get(username='super') 21 11 response = self.client.get('/special_headers/article/1/') -
tests/regressiontests/special_headers/urls.py
diff --git a/tests/regressiontests/special_headers/urls.py b/tests/regressiontests/special_headers/urls.py index 2e6a305..f7ba141 100644
a b 2 2 from __future__ import absolute_import 3 3 4 4 from django.conf.urls import patterns 5 from django.views.generic.list_detail import object_detail6 5 7 6 from . import views 8 7 from .models import Article 9 8 10 9 urlpatterns = patterns('', 11 (r'^special_headers/article/(?P<object_id>\d+)/$', object_detail, {'queryset': Article.objects.all()}),10 (r'^special_headers/article/(?P<object_id>\d+)/$', views.xview_xheaders), 12 11 (r'^special_headers/xview/func/$', views.xview_dec(views.xview)), 13 12 (r'^special_headers/xview/class/$', views.xview_dec(views.XViewClass.as_view())), 14 13 ) -
tests/regressiontests/special_headers/views.py
diff --git a/tests/regressiontests/special_headers/views.py b/tests/regressiontests/special_headers/views.py index ce94036..a8bbd65 100644
a b 1 # -*- coding:utf-8 -*- 1 from django.core.xheaders import populate_xheaders 2 2 from django.http import HttpResponse 3 3 from django.utils.decorators import decorator_from_middleware 4 4 from django.views.generic import View 5 5 from django.middleware.doc import XViewMiddleware 6 6 7 from .models import Article 8 7 9 xview_dec = decorator_from_middleware(XViewMiddleware) 8 10 9 11 def xview(request): 10 12 return HttpResponse() 11 13 14 def xview_xheaders(request, object_id): 15 response = HttpResponse() 16 populate_xheaders(request, response, Article, 1) 17 return response 18 12 19 class XViewClass(View): 13 20 def get(self, request): 14 21 return HttpResponse() -
tests/regressiontests/views/generic_urls.py
diff --git a/tests/regressiontests/views/generic_urls.py b/tests/regressiontests/views/generic_urls.py index 40a6c01..5bf929e 100644
a b 2 2 from __future__ import absolute_import 3 3 4 4 from django.conf.urls import patterns, url 5 from django.views.generic import RedirectView 5 6 6 7 from . import views 7 8 from .models import Article, DateArticle, UrlArticle … … urlpatterns = patterns('', 35 36 url(u'^中文/target/$', 'regressiontests.views.views.index_page'), 36 37 ) 37 38 38 # Date-based generic views.39 urlpatterns += patterns('django.views.generic.date_based',40 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$',41 'object_detail',42 dict(slug_field='slug', **date_based_info_dict)),43 (r'^date_based/object_detail/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/allow_future/$',44 'object_detail',45 dict(allow_future=True, slug_field='slug', **date_based_info_dict)),46 (r'^date_based/archive_day/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$',47 'archive_day',48 numeric_days_info_dict),49 (r'^date_based/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',50 'archive_month',51 date_based_info_dict),52 (r'^date_based/datefield/archive_month/(?P<year>\d{4})/(?P<month>\d{1,2})/$',53 'archive_month',54 date_based_datefield_info_dict),55 )56 57 # crud generic views.58 urlpatterns += patterns('django.views.generic.create_update',59 (r'^create_update/member/create/article/$', 'create_object',60 dict(login_required=True, model=Article)),61 (r'^create_update/create/article/$', 'create_object',62 dict(post_save_redirect='/create_update/view/article/%(slug)s/',63 model=Article)),64 (r'^create_update/update/article/(?P<slug>[-\w]+)/$', 'update_object',65 dict(post_save_redirect='/create_update/view/article/%(slug)s/',66 slug_field='slug', model=Article)),67 (r'^create_update/create_custom/article/$', views.custom_create),68 (r'^create_update/delete/article/(?P<slug>[-\w]+)/$', 'delete_object',69 dict(post_delete_redirect='/create_update/', slug_field='slug',70 model=Article)),71 72 # No post_save_redirect and no get_absolute_url on model.73 (r'^create_update/no_redirect/create/article/$', 'create_object',74 dict(model=Article)),75 (r'^create_update/no_redirect/update/article/(?P<slug>[-\w]+)/$',76 'update_object', dict(slug_field='slug', model=Article)),77 78 # get_absolute_url on model, but no passed post_save_redirect.79 (r'^create_update/no_url/create/article/$', 'create_object',80 dict(model=UrlArticle)),81 (r'^create_update/no_url/update/article/(?P<slug>[-\w]+)/$',82 'update_object', dict(slug_field='slug', model=UrlArticle)),83 )84 85 urlpatterns += patterns('django.views.generic.list_detail',86 (r'^object_list/page(?P<page>[\w]*)/$', 'object_list', object_list_dict),87 (r'^object_list_no_paginate_by/page(?P<page>[0-9]+)/$', 'object_list',88 object_list_no_paginate_by),89 )90 91 39 # rediriects, both temporary and permanent, with non-ASCII targets 92 urlpatterns += patterns(' django.views.generic.simple',93 ('^nonascii_redirect/$', 'redirect_to',94 {'url': u'/中文/target/', 'permanent': False}),95 ('^permanent_nonascii_redirect/$', 'redirect_to',96 {'url': u'/中文/target/', 'permanent': True}),40 urlpatterns += patterns('', 41 ('^nonascii_redirect/$', RedirectView.as_view( 42 url=u'/中文/target/', permanent=False)), 43 ('^permanent_nonascii_redirect/$', RedirectView.as_view( 44 url=u'/中文/target/', permanent=True)), 97 45 ) 98 46 99 47 urlpatterns += patterns('regressiontests.views.views', … … urlpatterns += patterns('regressiontests.views.views', 107 55 (r'^shortcuts/render/current_app/$', 'render_view_with_current_app'), 108 56 (r'^shortcuts/render/current_app_conflict/$', 'render_view_with_current_app_conflict'), 109 57 ) 110 111 # simple generic views.112 urlpatterns += patterns('django.views.generic.simple',113 (r'^simple/redirect_to/$', 'redirect_to', dict(url='/simple/target/')),114 (r'^simple/redirect_to_temp/$', 'redirect_to', dict(url='/simple/target/', permanent=False)),115 (r'^simple/redirect_to_none/$', 'redirect_to', dict(url=None)),116 (r'^simple/redirect_to_arg/(?P<id>\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/')),117 (r'^simple/redirect_to_query/$', 'redirect_to', dict(url='/simple/target/', query_string=True)),118 (r'^simple/redirect_to_arg_and_query/(?P<id>\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/', query_string=True)),119 ) -
tests/regressiontests/views/tests/__init__.py
diff --git a/tests/regressiontests/views/tests/__init__.py b/tests/regressiontests/views/tests/__init__.py index 04537a2..63db5da 100644
a b from .debug import (DebugViewTests, ExceptionReporterTests, 4 4 ExceptionReporterTests, PlainTextReportTests, ExceptionReporterFilterTests, 5 5 AjaxResponseExceptionReporterFilter) 6 6 from .defaults import DefaultsTests 7 from .generic.create_update import (UpdateDeleteObjectTest, CreateObjectTest,8 PostSaveRedirectTests, NoPostSaveNoAbsoluteUrl, AbsoluteUrlNoPostSave)9 from .generic.date_based import MonthArchiveTest, ObjectDetailTest, DayArchiveTests10 from .generic.object_list import ObjectListTest11 from .generic.simple import RedirectToTest12 7 from .i18n import JsI18NTests, I18NTests, JsI18NTestsMultiPackage 13 8 from .shortcuts import ShortcutTests 14 9 from .specials import URLHandling -
deleted file tests/regressiontests/views/tests/generic/create_update.py
diff --git a/tests/regressiontests/views/tests/generic/__init__.py b/tests/regressiontests/views/tests/generic/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/regressiontests/views/tests/generic/create_update.py b/tests/regressiontests/views/tests/generic/create_update.py deleted file mode 100644 index 2abcfb4..0000000
+ - 1 import datetime2 import warnings3 4 from django.test import TestCase5 from django.core.exceptions import ImproperlyConfigured6 from regressiontests.views.models import Article, UrlArticle7 8 class CreateObjectTest(TestCase):9 fixtures = ['testdata.json']10 urls = 'regressiontests.views.generic_urls'11 12 def setUp(self):13 self.save_warnings_state()14 warnings.filterwarnings('ignore', category=DeprecationWarning,15 module='django.views.generic.create_update')16 17 def tearDown(self):18 self.restore_warnings_state()19 20 def test_login_required_view(self):21 """22 Verifies that an unauthenticated user attempting to access a23 login_required view gets redirected to the login page and that24 an authenticated user is let through.25 """26 view_url = '/create_update/member/create/article/'27 response = self.client.get(view_url)28 self.assertRedirects(response, '/accounts/login/?next=%s' % view_url)29 # Now login and try again.30 login = self.client.login(username='testclient', password='password')31 self.assertTrue(login, 'Could not log in')32 response = self.client.get(view_url)33 self.assertEqual(response.status_code, 200)34 self.assertTemplateUsed(response, 'views/article_form.html')35 36 def test_create_article_display_page(self):37 """38 Ensures the generic view returned the page and contains a form.39 """40 view_url = '/create_update/create/article/'41 response = self.client.get(view_url)42 self.assertEqual(response.status_code, 200)43 self.assertTemplateUsed(response, 'views/article_form.html')44 if not response.context.get('form'):45 self.fail('No form found in the response.')46 47 def test_create_article_with_errors(self):48 """49 POSTs a form that contains validation errors.50 """51 view_url = '/create_update/create/article/'52 num_articles = Article.objects.count()53 response = self.client.post(view_url, {54 'title': 'My First Article',55 })56 self.assertFormError(response, 'form', 'slug', [u'This field is required.'])57 self.assertTemplateUsed(response, 'views/article_form.html')58 self.assertEqual(num_articles, Article.objects.count(),59 "Number of Articles should not have changed.")60 61 def test_create_custom_save_article(self):62 """63 Creates a new article using a custom form class with a save method64 that alters the slug entered.65 """66 view_url = '/create_update/create_custom/article/'67 response = self.client.post(view_url, {68 'title': 'Test Article',69 'slug': 'this-should-get-replaced',70 'author': 1,71 'date_created': datetime.datetime(2007, 6, 25),72 })73 self.assertRedirects(response,74 '/create_update/view/article/some-other-slug/',75 target_status_code=404)76 77 class UpdateDeleteObjectTest(TestCase):78 fixtures = ['testdata.json']79 urls = 'regressiontests.views.generic_urls'80 81 def setUp(self):82 self.save_warnings_state()83 warnings.filterwarnings('ignore', category=DeprecationWarning,84 module='django.views.generic.create_update')85 86 def tearDown(self):87 self.restore_warnings_state()88 89 def test_update_object_form_display(self):90 """91 Verifies that the form was created properly and with initial values.92 """93 response = self.client.get('/create_update/update/article/old_article/')94 self.assertTemplateUsed(response, 'views/article_form.html')95 self.assertHTMLEqual(unicode(response.context['form']['title']),96 u'<input id="id_title" type="text" name="title" value="Old Article" maxlength="100" />')97 98 def test_update_object(self):99 """100 Verifies the updating of an Article.101 """102 response = self.client.post('/create_update/update/article/old_article/', {103 'title': 'Another Article',104 'slug': 'another-article-slug',105 'author': 1,106 'date_created': datetime.datetime(2007, 6, 25),107 })108 article = Article.objects.get(pk=1)109 self.assertEqual(article.title, "Another Article")110 111 def test_delete_object_confirm(self):112 """113 Verifies the confirm deletion page is displayed using a GET.114 """115 response = self.client.get('/create_update/delete/article/old_article/')116 self.assertTemplateUsed(response, 'views/article_confirm_delete.html')117 118 def test_delete_object(self):119 """120 Verifies the object actually gets deleted on a POST.121 """122 view_url = '/create_update/delete/article/old_article/'123 response = self.client.post(view_url)124 try:125 Article.objects.get(slug='old_article')126 except Article.DoesNotExist:127 pass128 else:129 self.fail('Object was not deleted.')130 131 class PostSaveRedirectTests(TestCase):132 """133 Verifies that the views redirect to the correct locations depending on134 if a post_save_redirect was passed and a get_absolute_url method exists135 on the Model.136 """137 138 fixtures = ['testdata.json']139 article_model = Article140 urls = 'regressiontests.views.generic_urls'141 142 create_url = '/create_update/create/article/'143 update_url = '/create_update/update/article/old_article/'144 delete_url = '/create_update/delete/article/old_article/'145 146 create_redirect = '/create_update/view/article/my-first-article/'147 update_redirect = '/create_update/view/article/another-article-slug/'148 delete_redirect = '/create_update/'149 150 def setUp(self):151 self.save_warnings_state()152 warnings.filterwarnings('ignore', category=DeprecationWarning,153 module='django.views.generic.create_update')154 155 def tearDown(self):156 self.restore_warnings_state()157 158 def test_create_article(self):159 num_articles = self.article_model.objects.count()160 response = self.client.post(self.create_url, {161 'title': 'My First Article',162 'slug': 'my-first-article',163 'author': '1',164 'date_created': datetime.datetime(2007, 6, 25),165 })166 self.assertRedirects(response, self.create_redirect,167 target_status_code=404)168 self.assertEqual(num_articles + 1, self.article_model.objects.count(),169 "A new Article should have been created.")170 171 def test_update_article(self):172 num_articles = self.article_model.objects.count()173 response = self.client.post(self.update_url, {174 'title': 'Another Article',175 'slug': 'another-article-slug',176 'author': 1,177 'date_created': datetime.datetime(2007, 6, 25),178 })179 self.assertRedirects(response, self.update_redirect,180 target_status_code=404)181 self.assertEqual(num_articles, self.article_model.objects.count(),182 "A new Article should not have been created.")183 184 def test_delete_article(self):185 num_articles = self.article_model.objects.count()186 response = self.client.post(self.delete_url)187 self.assertRedirects(response, self.delete_redirect,188 target_status_code=404)189 self.assertEqual(num_articles - 1, self.article_model.objects.count(),190 "An Article should have been deleted.")191 192 class NoPostSaveNoAbsoluteUrl(PostSaveRedirectTests):193 """194 Tests that when no post_save_redirect is passed and no get_absolute_url195 method exists on the Model that the view raises an ImproperlyConfigured196 error.197 """198 urls = 'regressiontests.views.generic_urls'199 200 create_url = '/create_update/no_redirect/create/article/'201 update_url = '/create_update/no_redirect/update/article/old_article/'202 203 def setUp(self):204 self.save_warnings_state()205 warnings.filterwarnings('ignore', category=DeprecationWarning,206 module='django.views.generic.create_update')207 208 def tearDown(self):209 self.restore_warnings_state()210 211 def test_create_article(self):212 self.assertRaises(ImproperlyConfigured,213 super(NoPostSaveNoAbsoluteUrl, self).test_create_article)214 215 def test_update_article(self):216 self.assertRaises(ImproperlyConfigured,217 super(NoPostSaveNoAbsoluteUrl, self).test_update_article)218 219 def test_delete_article(self):220 """221 The delete_object view requires a post_delete_redirect, so skip testing222 here.223 """224 pass225 226 class AbsoluteUrlNoPostSave(PostSaveRedirectTests):227 """228 Tests that the views redirect to the Model's get_absolute_url when no229 post_save_redirect is passed.230 """231 urls = 'regressiontests.views.generic_urls'232 233 # Article model with get_absolute_url method.234 article_model = UrlArticle235 236 create_url = '/create_update/no_url/create/article/'237 update_url = '/create_update/no_url/update/article/old_article/'238 239 create_redirect = '/urlarticles/my-first-article/'240 update_redirect = '/urlarticles/another-article-slug/'241 242 def setUp(self):243 self.save_warnings_state()244 warnings.filterwarnings('ignore', category=DeprecationWarning,245 module='django.views.generic.create_update')246 247 def tearDown(self):248 self.restore_warnings_state()249 250 def test_delete_article(self):251 """252 The delete_object view requires a post_delete_redirect, so skip testing253 here.254 """255 pass -
deleted file tests/regressiontests/views/tests/generic/date_based.py
diff --git a/tests/regressiontests/views/tests/generic/date_based.py b/tests/regressiontests/views/tests/generic/date_based.py deleted file mode 100644 index 96555e5..0000000
+ - 1 # coding: utf-82 import warnings3 4 from django.test import TestCase5 from datetime import datetime, date6 from datetime import timedelta7 from regressiontests.views.models import Article, Author, DateArticle8 9 class ObjectDetailTest(TestCase):10 fixtures = ['testdata.json']11 urls = 'regressiontests.views.generic_urls'12 13 def setUp(self):14 self.save_warnings_state()15 warnings.filterwarnings('ignore', category=DeprecationWarning,16 module='django.views.generic.date_based')17 # Correct the date for the current article18 current_article = Article.objects.get(title="Current Article")19 current_article.date_created = datetime.now()20 current_article.save()21 22 def tearDown(self):23 self.restore_warnings_state()24 25 def test_finds_past(self):26 "date_based.object_detail can view a page in the past"27 response = self.client.get('/date_based/object_detail/2001/01/01/old_article/')28 self.assertEqual(response.status_code, 200)29 self.assertEqual(response.context['object'].title, "Old Article")30 31 def test_object_detail_finds_today(self):32 "date_based.object_detail can view a page from today"33 today_url = datetime.now().strftime('%Y/%m/%d')34 response = self.client.get('/date_based/object_detail/%s/current_article/' % today_url)35 self.assertEqual(response.status_code, 200)36 self.assertEqual(response.context['object'].title, "Current Article")37 38 def test_object_detail_ignores_future(self):39 "date_based.object_detail can view a page from the future, but only if allowed."40 response = self.client.get('/date_based/object_detail/3000/01/01/future_article/')41 self.assertEqual(response.status_code, 404)42 43 def test_object_detail_allowed_future_if_enabled(self):44 "date_based.object_detail can view a page from the future if explicitly allowed."45 response = self.client.get('/date_based/object_detail/3000/01/01/future_article/allow_future/')46 self.assertEqual(response.status_code, 200)47 self.assertEqual(response.context['object'].title, "Future Article")48 49 class MonthArchiveTest(TestCase):50 urls = 'regressiontests.views.generic_urls'51 52 def setUp(self):53 self.save_warnings_state()54 warnings.filterwarnings('ignore', category=DeprecationWarning,55 module='django.views.generic.date_based')56 57 def tearDown(self):58 self.restore_warnings_state()59 60 def test_archive_month_includes_only_month(self):61 "Regression for #3031: Archives around Feburary include only one month"62 author = Author(name="John Smith")63 author.save()64 65 # 2004 was a leap year, so it should be weird enough to not cheat66 first_second_of_feb = datetime(2004, 2, 1, 0, 0, 1)67 first_second_of_mar = datetime(2004, 3, 1, 0, 0, 1)68 two_seconds = timedelta(0, 2, 0)69 article = Article(title="example", author=author)70 71 article.date_created = first_second_of_feb72 article.save()73 response = self.client.get('/date_based/archive_month/2004/02/')74 self.assertEqual(response.status_code, 200)75 self.assertEqual(response.context['next_month'], date(2004, 3, 1))76 self.assertEqual(response.context['previous_month'], date(2004, 1, 1))77 78 article.date_created = first_second_of_feb-two_seconds79 article.save()80 response = self.client.get('/date_based/archive_month/2004/02/')81 self.assertEqual(response.status_code, 404)82 83 article.date_created = first_second_of_mar-two_seconds84 article.save()85 response = self.client.get('/date_based/archive_month/2004/02/')86 self.assertEqual(response.status_code, 200)87 self.assertEqual(response.context['next_month'], date(2004, 3, 1))88 self.assertEqual(response.context['previous_month'], date(2004, 1, 1))89 90 article.date_created = first_second_of_mar91 article.save()92 response = self.client.get('/date_based/archive_month/2004/02/')93 self.assertEqual(response.status_code, 404)94 95 article2 = DateArticle(title="example", author=author)96 97 article2.date_created = first_second_of_feb.date()98 article2.save()99 response = self.client.get('/date_based/datefield/archive_month/2004/02/')100 self.assertEqual(response.status_code, 200)101 self.assertEqual(response.context['next_month'], date(2004, 3, 1))102 self.assertEqual(response.context['previous_month'], date(2004, 1, 1))103 104 article2.date_created = (first_second_of_feb-two_seconds).date()105 article2.save()106 response = self.client.get('/date_based/datefield/archive_month/2004/02/')107 self.assertEqual(response.status_code, 404)108 109 article2.date_created = (first_second_of_mar-two_seconds).date()110 article2.save()111 response = self.client.get('/date_based/datefield/archive_month/2004/02/')112 self.assertEqual(response.status_code, 200)113 self.assertEqual(response.context['next_month'], date(2004, 3, 1))114 self.assertEqual(response.context['previous_month'], date(2004, 1, 1))115 116 article2.date_created = first_second_of_mar.date()117 article2.save()118 response = self.client.get('/date_based/datefield/archive_month/2004/02/')119 self.assertEqual(response.status_code, 404)120 121 now = datetime.now()122 prev_month = now.date().replace(day=1)123 if prev_month.month == 1:124 prev_month = prev_month.replace(year=prev_month.year-1, month=12)125 else:126 prev_month = prev_month.replace(month=prev_month.month-1)127 article2.date_created = now128 article2.save()129 response = self.client.get('/date_based/datefield/archive_month/%s/' % now.strftime('%Y/%m'))130 self.assertEqual(response.status_code, 200)131 self.assertEqual(response.context['next_month'], None)132 self.assertEqual(response.context['previous_month'], prev_month)133 134 def test_archive_month_date_list(self):135 author = Author(name="John Smith")136 author.save()137 date1 = datetime(2010, 1, 1, 0, 0, 0)138 date2 = datetime(2010, 1, 2, 0, 0, 0)139 Article.objects.create(title='example1', author=author, date_created=date1)140 Article.objects.create(title='example2', author=author, date_created=date2)141 response = self.client.get('/date_based/archive_month/2010/1/')142 self.assertEqual(response.status_code, 200)143 self.assertEqual(len(response.context['date_list']), 2)144 self.assertEqual(response.context['date_list'][0], date1)145 # Checks that the same date is not included more than once in the list146 Article.objects.create(title='example2', author=author, date_created=date2)147 response = self.client.get('/date_based/archive_month/2010/1/')148 self.assertEqual(len(response.context['date_list']), 2)149 150 class DayArchiveTests(TestCase):151 urls = 'regressiontests.views.generic_urls'152 153 def setUp(self):154 self.save_warnings_state()155 warnings.filterwarnings('ignore', category=DeprecationWarning,156 module='django.views.generic.date_based')157 warnings.filterwarnings('ignore', category=DeprecationWarning,158 module='django.views.generic.create_update')159 160 def tearDown(self):161 self.restore_warnings_state()162 163 def test_year_month_day_format(self):164 """165 Make sure day views don't get confused with numeric month formats (#7944)166 """167 author = Author.objects.create(name="John Smith")168 article = Article.objects.create(title="example", author=author, date_created=datetime(2004, 1, 21, 0, 0, 1))169 response = self.client.get('/date_based/archive_day/2004/1/21/')170 self.assertEqual(response.status_code, 200)171 self.assertEqual(response.context['object_list'][0], article) -
deleted file tests/regressiontests/views/tests/generic/object_list.py
diff --git a/tests/regressiontests/views/tests/generic/object_list.py b/tests/regressiontests/views/tests/generic/object_list.py deleted file mode 100644 index 3fa871a..0000000
+ - 1 import warnings2 3 from django.test import TestCase4 5 6 class ObjectListTest(TestCase):7 fixtures = ['testdata.json']8 urls = 'regressiontests.views.generic_urls'9 10 def setUp(self):11 self.save_warnings_state()12 warnings.filterwarnings('ignore', category=DeprecationWarning,13 module='django.views.generic.list_detail')14 15 def tearDown(self):16 self.restore_warnings_state()17 18 def check_pagination(self, url, expected_status_code, object_count=None):19 response = self.client.get(url)20 self.assertEqual(response.status_code, expected_status_code)21 22 if object_count:23 self.assertEqual(response.context['is_paginated'], True)24 self.assertEqual(len(response.context['page_obj'].object_list),25 object_count)26 27 return response28 29 def test_finds_pages(self):30 # Check page count doesn't start at 0.31 self.check_pagination('/object_list/page0/', 404)32 33 # Check basic pages.34 self.check_pagination('/object_list/page/', 200, 2)35 self.check_pagination('/object_list/page1/', 200, 2)36 self.check_pagination('/object_list/page2/', 200, 1)37 self.check_pagination('/object_list/page3/', 404)38 39 # Check the special "last" page.40 self.check_pagination('/object_list/pagelast/', 200, 1)41 self.check_pagination('/object_list/pagenotlast/', 404)42 43 def test_no_paginate_by(self):44 # Ensure that the view isn't paginated by default.45 url = '/object_list_no_paginate_by/page1/'46 response = self.check_pagination(url, 200)47 self.assertEqual(response.context['is_paginated'], False) -
deleted file tests/regressiontests/views/tests/generic/simple.py
diff --git a/tests/regressiontests/views/tests/generic/simple.py b/tests/regressiontests/views/tests/generic/simple.py deleted file mode 100644 index 7dcf08a..0000000
+ - 1 # coding: utf-82 import warnings3 4 from django.test import TestCase5 6 class RedirectToTest(TestCase):7 urls = 'regressiontests.views.generic_urls'8 9 def setUp(self):10 self.save_warnings_state()11 warnings.filterwarnings('ignore', category=DeprecationWarning,12 module='django.views.generic.simple')13 14 def tearDown(self):15 self.restore_warnings_state()16 17 def test_redirect_to_returns_permanent_redirect(self):18 "simple.redirect_to returns a permanent redirect (301) by default"19 response = self.client.get('/simple/redirect_to/')20 self.assertEqual(response.status_code, 301)21 self.assertEqual('http://testserver/simple/target/', response['Location'])22 23 def test_redirect_to_can_return_a_temporary_redirect(self):24 "simple.redirect_to returns a temporary redirect (302) when explicitely asked to"25 response = self.client.get('/simple/redirect_to_temp/')26 self.assertEqual(response.status_code, 302)27 self.assertEqual('http://testserver/simple/target/', response['Location'])28 29 def test_redirect_to_on_empty_url_returns_gone(self):30 "simple.redirect_to returns resource gone (410) when given a None url"31 response = self.client.get('/simple/redirect_to_none/')32 self.assertEqual(response.status_code, 410)33 34 def test_redirect_to_allows_formatted_url_string(self):35 "simple.redirect_to uses string interpolation on target url for keyword args"36 response = self.client.get('/simple/redirect_to_arg/42/')37 self.assertEqual(response.status_code, 301)38 self.assertEqual('http://testserver/simple/target_arg/42/', response['Location'])39 40 def test_redirect_to_allows_query_string_to_be_passed(self):41 "simple.redirect_to configured with query_string=True passes on any query string"42 # the default is to not forward the query string43 response = self.client.get('/simple/redirect_to/?param1=foo¶m2=bar')44 self.assertEqual(response.status_code, 301)45 self.assertEqual('http://testserver/simple/target/', response['Location'])46 # views configured with query_string=True however passes the query string along47 response = self.client.get('/simple/redirect_to_query/?param1=foo¶m2=bar')48 self.assertEqual(response.status_code, 301)49 self.assertEqual('http://testserver/simple/target/?param1=foo¶m2=bar', response['Location'])50 51 # Confirm that the contents of the query string are not subject to52 # string interpolation (Refs #17111):53 response = self.client.get('/simple/redirect_to_query/?param1=foo¶m2=hist%C3%B3ria')54 self.assertEqual(response.status_code, 301)55 self.assertEqual('http://testserver/simple/target/?param1=foo¶m2=hist%C3%B3ria', response['Location'])56 response = self.client.get('/simple/redirect_to_arg_and_query/99/?param1=foo¶m2=hist%C3%B3ria')57 self.assertEqual(response.status_code, 301)58 self.assertEqual('http://testserver/simple/target_arg/99/?param1=foo¶m2=hist%C3%B3ria', response['Location'])59 60 def test_redirect_to_when_meta_contains_no_query_string(self):61 "regression for #16705"62 # we can't use self.client.get because it always sets QUERY_STRING63 response = self.client.request(PATH_INFO='/simple/redirect_to/')64 self.assertEqual(response.status_code, 301) -
tests/regressiontests/views/tests/shortcuts.py
diff --git a/tests/regressiontests/views/tests/shortcuts.py b/tests/regressiontests/views/tests/shortcuts.py index d20b6d1..a48bb25 100644
a b 1 import warnings2 3 1 from django.conf import settings 4 2 from django.test import TestCase 5 3 from django.test.utils import override_settings … … from django.test.utils import override_settings 11 9 class ShortcutTests(TestCase): 12 10 urls = 'regressiontests.views.generic_urls' 13 11 14 def setUp(self):15 self.save_warnings_state()16 warnings.filterwarnings('ignore', category=DeprecationWarning,17 module='django.views.generic.simple')18 19 def tearDown(self):20 self.restore_warnings_state()21 22 12 def test_render_to_response(self): 23 13 response = self.client.get('/shortcuts/render_to_response/') 24 14 self.assertEqual(response.status_code, 200) -
tests/regressiontests/views/tests/specials.py
diff --git a/tests/regressiontests/views/tests/specials.py b/tests/regressiontests/views/tests/specials.py index 7855704..cd8ac5b 100644
a b 1 1 # coding: utf-8 2 import warnings3 4 2 from django.test import TestCase 5 3 6 4 … … class URLHandling(TestCase): 11 9 urls = 'regressiontests.views.generic_urls' 12 10 redirect_target = "/%E4%B8%AD%E6%96%87/target/" 13 11 14 def setUp(self):15 self.save_warnings_state()16 warnings.filterwarnings('ignore', category=DeprecationWarning,17 module='django.views.generic.simple')18 19 def tearDown(self):20 self.restore_warnings_state()21 22 12 def test_combining_redirect(self): 23 13 """ 24 14 Tests that redirecting to an IRI, requiring encoding before we use it -
tests/regressiontests/views/views.py
diff --git a/tests/regressiontests/views/views.py b/tests/regressiontests/views/views.py index 1d17e6e..8e530cd 100644
a b def index_page(request): 21 21 """Dummy index page""" 22 22 return HttpResponse('<html><body>Dummy page</body></html>') 23 23 24 def custom_create(request):25 """26 Calls create_object generic view with a custom form class.27 """28 class SlugChangingArticleForm(forms.ModelForm):29 """Custom form class to overwrite the slug."""30 31 class Meta:32 model = Article33 34 def save(self, *args, **kwargs):35 self.instance.slug = 'some-other-slug'36 return super(SlugChangingArticleForm, self).save(*args, **kwargs)37 38 from django.views.generic.create_update import create_object39 return create_object(request,40 post_save_redirect='/create_update/view/article/%(slug)s/',41 form_class=SlugChangingArticleForm)42 43 24 def raises(request): 44 25 # Make sure that a callable that raises an exception in the stack frame's 45 26 # local vars won't hijack the technical 500 response. See: