A bunch of generics: documentation of generic views; cleaned up existing generic views, and added create/update generic views.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@304 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8bd30b01e4
commit
371144f134
|
@ -0,0 +1,185 @@
|
||||||
|
from django import models
|
||||||
|
from django.core.xheaders import populate_xheaders
|
||||||
|
from django.core import template_loader, formfields
|
||||||
|
from django.views.auth.login import redirect_to_login
|
||||||
|
from django.core.extensions import DjangoContext as Context
|
||||||
|
from django.core.paginator import ObjectPaginator, InvalidPage
|
||||||
|
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.core.exceptions import Http404, ObjectDoesNotExist, ImproperlyConfigured
|
||||||
|
|
||||||
|
def create_object(request, app_label, module_name, template_name=None,
|
||||||
|
extra_context=None, post_save_redirect=None, login_required=False):
|
||||||
|
"""
|
||||||
|
Generic object-creation function.
|
||||||
|
|
||||||
|
Templates: ``<app_label>/<module_name>_form``
|
||||||
|
Context:
|
||||||
|
form
|
||||||
|
the form wrapper for the object
|
||||||
|
"""
|
||||||
|
if login_required and request.user.is_anonymous():
|
||||||
|
return redirect_to_login(request)
|
||||||
|
|
||||||
|
mod = models.get_module(app_label, module_name)
|
||||||
|
manipulator = mod.AddManipulator()
|
||||||
|
if request.POST:
|
||||||
|
# If data was POSTed, we're trying to create a new object
|
||||||
|
new_data = request.POST.copy()
|
||||||
|
|
||||||
|
# Check for errors
|
||||||
|
errors = manipulator.get_validation_errors(new_data)
|
||||||
|
|
||||||
|
if not errors:
|
||||||
|
# No errors -- this means we can save the data!
|
||||||
|
manipulator.do_html2python(new_data)
|
||||||
|
new_object = manipulator.save(new_data)
|
||||||
|
|
||||||
|
if not request.user.is_anonymous():
|
||||||
|
request.user.add_message("The %s was created sucessfully." % mod.Klass._meta.verbose_name)
|
||||||
|
|
||||||
|
# Redirect to the new object: first by trying post_save_redirect,
|
||||||
|
# then by obj.get_absolute_url; fail if neither works.
|
||||||
|
if post_save_redirect:
|
||||||
|
return HttpResponseRedirect(post_save_redirect % new_object.__dict__)
|
||||||
|
elif hasattr(new_object, 'get_absolute_url'):
|
||||||
|
return HttpResponseRedirect(new_object.get_absolute_url())
|
||||||
|
else:
|
||||||
|
raise ImproperlyConfigured("No URL to redirect to from generic create view.")
|
||||||
|
else:
|
||||||
|
# No POST, so we want a brand new form without any data or errors
|
||||||
|
errors = new_data = {}
|
||||||
|
|
||||||
|
# Create the FormWrapper, template, context, response
|
||||||
|
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||||
|
if not template_name:
|
||||||
|
template_name = "%s/%s_form" % (app_label, module_name)
|
||||||
|
t = template_loader.get_template(template_name)
|
||||||
|
c = Context(request, {
|
||||||
|
'form' : form,
|
||||||
|
})
|
||||||
|
if extra_context:
|
||||||
|
c.update(extra_context)
|
||||||
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
|
def update_object(request, app_label, module_name, object_id=None, slug=None,
|
||||||
|
slug_field=None, template_name=None, extra_lookup_kwargs={},
|
||||||
|
extra_context=None, post_save_redirect=None, login_required=False):
|
||||||
|
"""
|
||||||
|
Generic object-update function.
|
||||||
|
|
||||||
|
Templates: ``<app_label>/<module_name>_form``
|
||||||
|
Context:
|
||||||
|
form
|
||||||
|
the form wrapper for the object
|
||||||
|
object
|
||||||
|
the original object being edited
|
||||||
|
"""
|
||||||
|
if login_required and request.user.is_anonymous():
|
||||||
|
return redirect_to_login(request)
|
||||||
|
|
||||||
|
mod = models.get_module(app_label, module_name)
|
||||||
|
|
||||||
|
# Look up the object to be edited
|
||||||
|
lookup_kwargs = {}
|
||||||
|
if object_id:
|
||||||
|
lookup_kwargs['%s__exact' % mod.Klass._meta.pk.name] = object_id
|
||||||
|
elif slug and slug_field:
|
||||||
|
lookup_kwargs['%s__exact' % slug_field] = slug
|
||||||
|
else:
|
||||||
|
raise AttributeError("Generic edit view must be called with either an object_id or a slug/slug_field")
|
||||||
|
lookup_kwargs.update(extra_lookup_kwargs)
|
||||||
|
try:
|
||||||
|
object = mod.get_object(**lookup_kwargs)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise Http404("%s.%s does not exist for %s" % (app_label, module_name, lookup_kwargs))
|
||||||
|
|
||||||
|
manipulator = mod.ChangeManipulator(object.id)
|
||||||
|
|
||||||
|
if request.POST:
|
||||||
|
new_data = request.POST.copy()
|
||||||
|
errors = manipulator.get_validation_errors(new_data)
|
||||||
|
if not errors:
|
||||||
|
manipulator.do_html2python(new_data)
|
||||||
|
manipulator.save(new_data)
|
||||||
|
|
||||||
|
if not request.user.is_anonymous():
|
||||||
|
request.user.add_message("The %s was updated sucessfully." % mod.Klass._meta.verbose_name)
|
||||||
|
|
||||||
|
# Do a post-after-redirect so that reload works, etc.
|
||||||
|
if post_save_redirect:
|
||||||
|
return HttpResponseRedirect(post_save_redirect % object.__dict__)
|
||||||
|
elif hasattr(object, 'get_absolute_url'):
|
||||||
|
return HttpResponseRedirect(object.get_absolute_url())
|
||||||
|
else:
|
||||||
|
raise ImproperlyConfigured("No URL to redirect to from generic create view.")
|
||||||
|
else:
|
||||||
|
errors = {}
|
||||||
|
# This makes sure the form acurate represents the fields of the place.
|
||||||
|
new_data = object.__dict__
|
||||||
|
|
||||||
|
form = formfields.FormWrapper(manipulator, new_data, errors)
|
||||||
|
if not template_name:
|
||||||
|
template_name = "%s/%s_form" % (app_label, module_name)
|
||||||
|
t = template_loader.get_template(template_name)
|
||||||
|
c = Context(request, {
|
||||||
|
'form' : form,
|
||||||
|
'object' : object,
|
||||||
|
})
|
||||||
|
if extra_context:
|
||||||
|
c.update(extra_context)
|
||||||
|
response = HttpResponse(t.render(c))
|
||||||
|
populate_xheaders(request, response, app_label, module_name, getattr(object, object._meta.pk.name))
|
||||||
|
return response
|
||||||
|
|
||||||
|
def delete_object(request, app_label, module_name, post_delete_redirect,
|
||||||
|
object_id=None, slug=None, slug_field=None, template_name=None,
|
||||||
|
extra_lookup_kwargs={}, extra_context=None, login_required=False):
|
||||||
|
"""
|
||||||
|
Generic object-delete function.
|
||||||
|
|
||||||
|
The given template will be used to confirm deletetion if this view is
|
||||||
|
fetched using GET; for safty, deletion will only be performed if this
|
||||||
|
view is POSTed.
|
||||||
|
|
||||||
|
Templates: ``<app_label>/<module_name>_confirm_delete``
|
||||||
|
Context:
|
||||||
|
object
|
||||||
|
the original object being deleted
|
||||||
|
"""
|
||||||
|
if login_required and request.user.is_anonymous():
|
||||||
|
return redirect_to_login(request)
|
||||||
|
|
||||||
|
mod = models.get_module(app_label, module_name)
|
||||||
|
|
||||||
|
# Look up the object to be edited
|
||||||
|
lookup_kwargs = {}
|
||||||
|
if object_id:
|
||||||
|
lookup_kwargs['%s__exact' % mod.Klass._meta.pk.name] = object_id
|
||||||
|
elif slug and slug_field:
|
||||||
|
lookup_kwargs['%s__exact' % slug_field] = slug
|
||||||
|
else:
|
||||||
|
raise AttributeError("Generic delete view must be called with either an object_id or a slug/slug_field")
|
||||||
|
lookup_kwargs.update(extra_lookup_kwargs)
|
||||||
|
try:
|
||||||
|
object = mod.get_object(**lookup_kwargs)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise Http404("%s.%s does not exist for %s" % (app_label, module_name, lookup_kwargs))
|
||||||
|
|
||||||
|
if request.META['REQUEST_METHOD'] == 'POST':
|
||||||
|
object.delete()
|
||||||
|
if not request.user.is_anonymous():
|
||||||
|
request.user.add_message("The %s was deleted." % mod.Klass._meta.verbose_name)
|
||||||
|
return HttpResponseRedirect(post_delete_redirect)
|
||||||
|
else:
|
||||||
|
if not template_name:
|
||||||
|
template_name = "%s/%s_confirm_delete" % (app_label, module_name)
|
||||||
|
t = template_loader.get_template(template_name)
|
||||||
|
c = Context(request, {
|
||||||
|
'object' : object,
|
||||||
|
})
|
||||||
|
if extra_context:
|
||||||
|
c.update(extra_context)
|
||||||
|
response = HttpResponse(t.render(c))
|
||||||
|
populate_xheaders(request, response, app_label, module_name, getattr(object, object._meta.pk.name))
|
||||||
|
return response
|
||||||
|
|
|
@ -6,7 +6,8 @@ from django.models import get_module
|
||||||
from django.utils.httpwrappers import HttpResponse
|
from django.utils.httpwrappers import HttpResponse
|
||||||
import datetime, time
|
import datetime, time
|
||||||
|
|
||||||
def archive_index(request, app_label, module_name, date_field, num_latest=15, template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
def archive_index(request, app_label, module_name, date_field, num_latest=15,
|
||||||
|
template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic top-level archive of date-based objects.
|
Generic top-level archive of date-based objects.
|
||||||
|
|
||||||
|
@ -44,7 +45,8 @@ def archive_index(request, app_label, module_name, date_field, num_latest=15, te
|
||||||
c.update(extra_context)
|
c.update(extra_context)
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def archive_year(request, year, app_label, module_name, date_field, template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
def archive_year(request, year, app_label, module_name, date_field,
|
||||||
|
template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic yearly archive view.
|
Generic yearly archive view.
|
||||||
|
|
||||||
|
@ -76,7 +78,8 @@ def archive_year(request, year, app_label, module_name, date_field, template_nam
|
||||||
c.update(extra_context)
|
c.update(extra_context)
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def archive_month(request, year, month, app_label, module_name, date_field, template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
def archive_month(request, year, month, app_label, module_name, date_field,
|
||||||
|
template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic monthly archive view.
|
Generic monthly archive view.
|
||||||
|
|
||||||
|
@ -122,7 +125,9 @@ def archive_month(request, year, month, app_label, module_name, date_field, temp
|
||||||
c.update(extra_context)
|
c.update(extra_context)
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def archive_day(request, year, month, day, app_label, module_name, date_field, template_name=None, extra_lookup_kwargs={}, extra_context=None, allow_empty=False):
|
def archive_day(request, year, month, day, app_label, module_name, date_field,
|
||||||
|
template_name=None, extra_lookup_kwargs={}, extra_context=None,
|
||||||
|
allow_empty=False):
|
||||||
"""
|
"""
|
||||||
Generic daily archive view.
|
Generic daily archive view.
|
||||||
|
|
||||||
|
@ -178,7 +183,9 @@ def archive_today(request, **kwargs):
|
||||||
})
|
})
|
||||||
return archive_day(request, **kwargs)
|
return archive_day(request, **kwargs)
|
||||||
|
|
||||||
def object_detail(request, year, month, day, app_label, module_name, date_field, object_id=None, slug=None, slug_field=None, template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
def object_detail(request, year, month, day, app_label, module_name, date_field,
|
||||||
|
object_id=None, slug=None, slug_field=None, template_name=None,
|
||||||
|
template_name_field=None, extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic detail view from year/month/day/slug or year/month/day/id structure.
|
Generic detail view from year/month/day/slug or year/month/day/id structure.
|
||||||
|
|
||||||
|
@ -212,7 +219,11 @@ def object_detail(request, year, month, day, app_label, module_name, date_field,
|
||||||
raise Http404("%s.%s does not exist for %s" % (app_label, module_name, lookup_kwargs))
|
raise Http404("%s.%s does not exist for %s" % (app_label, module_name, lookup_kwargs))
|
||||||
if not template_name:
|
if not template_name:
|
||||||
template_name = "%s/%s_detail" % (app_label, module_name)
|
template_name = "%s/%s_detail" % (app_label, module_name)
|
||||||
t = template_loader.get_template(template_name)
|
if template_name_field:
|
||||||
|
template_name_list = [getattr(object, template_name_field), template_name]
|
||||||
|
t = template_loader.select_template(template_name_list)
|
||||||
|
else:
|
||||||
|
t = template_loader.get_template(template_name)
|
||||||
c = Context(request, {
|
c = Context(request, {
|
||||||
'object': object,
|
'object': object,
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,7 +6,8 @@ from django.core.extensions import DjangoContext as Context
|
||||||
from django.core.paginator import ObjectPaginator, InvalidPage
|
from django.core.paginator import ObjectPaginator, InvalidPage
|
||||||
from django.core.exceptions import Http404, ObjectDoesNotExist
|
from django.core.exceptions import Http404, ObjectDoesNotExist
|
||||||
|
|
||||||
def object_list(request, app_label, module_name, paginate_by=None, allow_empty=False, template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
def object_list(request, app_label, module_name, paginate_by=None, allow_empty=False,
|
||||||
|
template_name=None, extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic list of objects.
|
Generic list of objects.
|
||||||
|
|
||||||
|
@ -67,7 +68,9 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F
|
||||||
t = template_loader.get_template(template_name)
|
t = template_loader.get_template(template_name)
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
def object_detail(request, app_label, module_name, object_id=None, slug=None, slug_field=None, template_name=None, template_name_field=None, extra_lookup_kwargs={}, extra_context=None):
|
def object_detail(request, app_label, module_name, object_id=None, slug=None,
|
||||||
|
slug_field=None, template_name=None, template_name_field=None,
|
||||||
|
extra_lookup_kwargs={}, extra_context=None):
|
||||||
"""
|
"""
|
||||||
Generic list of objects.
|
Generic list of objects.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,301 @@
|
||||||
|
===================
|
||||||
|
Using generic views
|
||||||
|
===================
|
||||||
|
|
||||||
|
Writing web applications can often be monotonous as we repeat certain patterns
|
||||||
|
again and again. In Django, the most common of these patterns have been abstracted into
|
||||||
|
"generic views" that let you quickly provide common views of object without actually
|
||||||
|
needing to write any views.
|
||||||
|
|
||||||
|
Django's generic views contain the following:
|
||||||
|
|
||||||
|
* A set of views for doing list/detail interfaces (for example,
|
||||||
|
Django's `documentation index`_ and `detail pages`_).
|
||||||
|
|
||||||
|
* A set of views for year/month/day archive pages and associated
|
||||||
|
detail and "latest" pages (for example, the Django weblog's year_,
|
||||||
|
month_, day_, detail_, and latest_ pages).
|
||||||
|
|
||||||
|
* A set of views for creating, editing, and deleting objects.
|
||||||
|
|
||||||
|
.. _`documentation index`: http://www.djangoproject.com/documentation/
|
||||||
|
.. _`detail pages`: http://www.djangoproject.com/documentation/faq/
|
||||||
|
.. _year: http://www.djangoproject.com/weblog/2005/
|
||||||
|
.. _month: http://www.djangoproject.com/weblog/2005/jul/
|
||||||
|
.. _day: http://www.djangoproject.com/weblog/2005/jul/20/
|
||||||
|
.. _detail: http://www.djangoproject.com/weblog/2005/jul/20/autoreload/
|
||||||
|
.. _latest: http://www.djangoproject.com/weblog/
|
||||||
|
|
||||||
|
All of these views are used by creating configuration dictionaries in
|
||||||
|
your urlconfig files and passing those dicts as the third member of the
|
||||||
|
urlconf tuple. For example, here's the urlconf for the simple weblog
|
||||||
|
app that drives the blog on djangoproject.com::
|
||||||
|
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
info_dict = {
|
||||||
|
'app_label': 'blog',
|
||||||
|
'module_name': 'entries',
|
||||||
|
'date_field': 'pub_date',
|
||||||
|
}
|
||||||
|
|
||||||
|
urlpatterns = patterns('django.views.generic.date_based',
|
||||||
|
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>\w+)/$', 'object_detail', dict(info_dict, slug_field='slug')),
|
||||||
|
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict),
|
||||||
|
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict),
|
||||||
|
(r'^(?P<year>\d{4})/$', 'archive_year', info_dict),
|
||||||
|
(r'^/?$', 'archive_index', info_dict),
|
||||||
|
)
|
||||||
|
|
||||||
|
As you can see, this urlconf defines a few options in ``info_dict`` that tell
|
||||||
|
the generic view which model to use (``blog.entries`` in this case), as well as
|
||||||
|
some extra information.
|
||||||
|
|
||||||
|
Documentation of each generic view follows along with a list of all keyword arguments
|
||||||
|
that a generic view expects. Remember that as in the example above, arguments may
|
||||||
|
either come from the URL pattern (as ``month``, ``day``, ``year``, etc. do above) or
|
||||||
|
from the additional information dict (as for ``app_label``, ``module_name``, etc.).
|
||||||
|
|
||||||
|
All the generic views that follow require the ``app_label`` and ``module_name`` keys.
|
||||||
|
These values are easiest to explain through example::
|
||||||
|
|
||||||
|
>>> from django.models.blog import entries
|
||||||
|
|
||||||
|
In the above line, ``blog`` is the ``app_label`` (this is the name of the file that
|
||||||
|
holds all your model definitions) and ``entries`` is the ``module_name`` (this is
|
||||||
|
either a pluralized, lowercased version of the model class name or the value of
|
||||||
|
the ``module_name`` option of your model). In the docs below, these keys will not
|
||||||
|
be repeated, but each generic view requires them.
|
||||||
|
|
||||||
|
Using date-based generic views
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Date-based generic views (in the module ``django.views.generic.date_based``)
|
||||||
|
export six functions for dealing with date-based data. Besides ``app_label``
|
||||||
|
and ``module_name``, all date-based generic views require that the ``date_field``
|
||||||
|
argument to passed to them; this is the name of the field that stores the date
|
||||||
|
the objects should key off of.
|
||||||
|
|
||||||
|
Additional, all date-based generic views have the following optional arguments:
|
||||||
|
|
||||||
|
======================= ==================================================
|
||||||
|
Argument Description
|
||||||
|
======================= ==================================================
|
||||||
|
``template_name`` Override the default template name used for the
|
||||||
|
view.
|
||||||
|
|
||||||
|
``extra_lookup_kwargs`` A dictionary of extra lookup parameters (see
|
||||||
|
the `database API docs`_).
|
||||||
|
|
||||||
|
``extra_context`` A dict of extra data to put into the template's
|
||||||
|
context.
|
||||||
|
======================= ==================================================
|
||||||
|
|
||||||
|
.. _`database API docs`: http://www.djangoproject.com/documentation/db_api/
|
||||||
|
|
||||||
|
The date-based generic functions are:
|
||||||
|
|
||||||
|
``archive_index``
|
||||||
|
A top-level index page showing the "latest" objects. Has an optional argument,
|
||||||
|
``num_latest`` which is the number of items to display on the page (defaults
|
||||||
|
to 15).
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name_archive`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
``date_list``
|
||||||
|
List of years with objects
|
||||||
|
``latest``
|
||||||
|
Latest objects by date
|
||||||
|
|
||||||
|
``archive_year``
|
||||||
|
Yearly archive. Requires that the ``year`` argument be present in the URL
|
||||||
|
pattern.
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__archive_year`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
``date_list``
|
||||||
|
List of months in this year with objects
|
||||||
|
``year``
|
||||||
|
This year
|
||||||
|
|
||||||
|
``archive_month``
|
||||||
|
Monthly archive; requires that ``year`` and ``month`` arguments be given.
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__archive_month`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
``month``
|
||||||
|
(datetime object) this month
|
||||||
|
``object_list``
|
||||||
|
list of objects published in the given month
|
||||||
|
|
||||||
|
``archive_day``
|
||||||
|
Daily archive; requires that ``year``, ``month``, and ``day`` arguments
|
||||||
|
be given.
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__archive_day`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
``object_list``
|
||||||
|
list of objects published this day
|
||||||
|
``day``
|
||||||
|
(datetime) the day
|
||||||
|
``previous_day``
|
||||||
|
(datetime) the previous day
|
||||||
|
``next_day``
|
||||||
|
(datetime) the next day, or None if the current day is today
|
||||||
|
|
||||||
|
|
||||||
|
``archive_today``
|
||||||
|
List of objects for today; exactly the same as ``archive_day``, except
|
||||||
|
that the year/month/day arguments are not given and today's date is
|
||||||
|
used instead.
|
||||||
|
|
||||||
|
``object_detail``
|
||||||
|
Individual object page; requires ``year``/``month``/``day`` arguments like
|
||||||
|
``archive_day``. This function can be used with two types of URLs: either
|
||||||
|
``/year/month/day/slug/`` or ``/year/month/day/object_id/``.
|
||||||
|
|
||||||
|
If you're using the slug-style URLs, you'll need to have a ``slug`` item in
|
||||||
|
your urlconf, and you'll need to pass a ``slug_field`` key in your info
|
||||||
|
dict to indicate the name of the slug field.
|
||||||
|
|
||||||
|
If your using the object_id-style URLs, you'll just need to have the URL
|
||||||
|
pattern have an ``object_id`` field.
|
||||||
|
|
||||||
|
You can also pass the ``template_name_field`` argument to indicate that the
|
||||||
|
the object stores the name of its template in a field on the object itself.
|
||||||
|
|
||||||
|
Using list/detail generic views
|
||||||
|
===============================
|
||||||
|
|
||||||
|
The list-detail generic views (in the ``django.views.generic.list_detail`` module)
|
||||||
|
are similar to the data-based ones, except the list-detail views simply have two
|
||||||
|
views: a list of objects, and an individual object page.
|
||||||
|
|
||||||
|
All these views take the same three optional arguments as the date-based ones do
|
||||||
|
(and they obviously do not accept or require the date field argument).
|
||||||
|
|
||||||
|
Individual views are:
|
||||||
|
|
||||||
|
``object_list``
|
||||||
|
List of objects.
|
||||||
|
|
||||||
|
Takes the following optional arguments:
|
||||||
|
|
||||||
|
======================= =================================================
|
||||||
|
Argument Description
|
||||||
|
======================= =================================================
|
||||||
|
``paginate_by`` If set to an integer, the view will paginate
|
||||||
|
objects with ``paginate_by`` objects per page.
|
||||||
|
The view will expect a ``page`` GET param with
|
||||||
|
the (zero-indexed) page number.
|
||||||
|
|
||||||
|
``allow_empty`` If ``False`` and there are no objects to display
|
||||||
|
the view will raise a 404 instead of displaying
|
||||||
|
an empty index page.
|
||||||
|
======================= =================================================
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__list`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
``object_list``
|
||||||
|
list of objects
|
||||||
|
``is_paginated``
|
||||||
|
are the results paginated?
|
||||||
|
|
||||||
|
If the results are paginated, the context will have some extra variables:
|
||||||
|
|
||||||
|
``results_per_page``
|
||||||
|
number of objects per page
|
||||||
|
``has_next``
|
||||||
|
is there a next page?
|
||||||
|
``has_previous``
|
||||||
|
is there a prev page?
|
||||||
|
``page``
|
||||||
|
the current page
|
||||||
|
``next``
|
||||||
|
the next page
|
||||||
|
``previous``
|
||||||
|
the previous page
|
||||||
|
``pages``
|
||||||
|
number of pages, total
|
||||||
|
|
||||||
|
``object_detail``
|
||||||
|
Object detail page. This works like and takes the same arguments as
|
||||||
|
the date-based ``object_detail`` above, except this one obviously
|
||||||
|
does not take the year/month/day arguments.
|
||||||
|
|
||||||
|
Using create/update/delete generic views
|
||||||
|
========================================
|
||||||
|
|
||||||
|
The ``django.views.generic.create_update`` module contains a set of functions
|
||||||
|
for creating, editing, and deleting objects. These views take the same global
|
||||||
|
arguments as the above sets of generic views; they also have a
|
||||||
|
``login_required`` argument which, if ``True``, requires the user to be logged
|
||||||
|
in to have access to the page (``login_required`` defaults to ``False``).
|
||||||
|
|
||||||
|
The create/update/delete views are:
|
||||||
|
|
||||||
|
``create_object``
|
||||||
|
Create a new object. Has an extra optional argument, ``post_save_redirect``,
|
||||||
|
which is a URL that the view will redirect to after saving the object
|
||||||
|
(defaults to ``object.get_absolute_url()``).
|
||||||
|
|
||||||
|
``post_save_redirect`` may contain dictionary string formatting which will
|
||||||
|
be interpolated against the object's dict (so you could use
|
||||||
|
``post_save_redirect="/polls/%(slug)s/"``, for example).
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__form`` by default (this is the
|
||||||
|
same template as the ``update_object`` view below; your template can tell
|
||||||
|
the different by the presence or absence of ``{{ object }}`` in the context.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
form
|
||||||
|
the form wrapper for the object
|
||||||
|
|
||||||
|
.. admonition:: Note
|
||||||
|
|
||||||
|
See the `manipulator and formfield documentation`_ for more information
|
||||||
|
about using form wrappers in templates.
|
||||||
|
|
||||||
|
.. _`manipulator and formfield documentation`: http://www.djangoproject.com/documentation/forms/
|
||||||
|
|
||||||
|
``update_object``
|
||||||
|
Edit an existing object. Has the same extra slug/ID parameters as
|
||||||
|
``list_detail.object_detail`` does (see above), and the same ``post_save_redirect``
|
||||||
|
as ``create_object`` does.
|
||||||
|
|
||||||
|
Uses the template ``app_label/module_name__form`` by default.
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
form
|
||||||
|
the form wrapper for the object
|
||||||
|
object
|
||||||
|
the original object being edited
|
||||||
|
|
||||||
|
``delete_object``
|
||||||
|
Delete an existing object. The given object will only actually be deleted if
|
||||||
|
the request method is POST; if this view is fetched with GET it will display
|
||||||
|
a confirmation page that should contain a form that POSTs to the same URL.
|
||||||
|
|
||||||
|
You must provide the ``post_delete_redirect`` argument to this function so
|
||||||
|
that the view knows where to go after the object is deleted.
|
||||||
|
|
||||||
|
If fetched with GET, uses the template
|
||||||
|
``app_label/module_name_s_confirm_delete`` by default (uses no template if
|
||||||
|
POSTed; simply deletes the object).
|
||||||
|
|
||||||
|
Has the following template context:
|
||||||
|
|
||||||
|
object
|
||||||
|
the object about to be deleted
|
Loading…
Reference in New Issue