Url and Page classes used to encapsulate the "site map" information (URL
regular expressions, Django views, menu item names, etc.) and the relation
between pages in the site map.
There are still lots of TODOs in this first pass.
Patch by: Todd Larsen
Review by: to-be-reviewed
from django.core.xheaders import populate_xheaders
from django.template import loader
from django import oldforms
from django.db.models import FileField
from django.contrib.auth.views import redirect_to_login
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.utils.translation import ugettext
def create_object(request, model, template_name=None,
template_loader=loader, extra_context=None, post_save_redirect=None,
login_required=False, follow=None, context_processors=None):
"""
Generic object-creation function.
Templates: ``<app_label>/<model_name>_form.html``
Context:
form
the form wrapper for the object
"""
if extra_context is None: extra_context = {}
if login_required and not request.user.is_authenticated():
return redirect_to_login(request.path)
manipulator = model.AddManipulator(follow=follow)
if request.POST:
# If data was POSTed, we're trying to create a new object
new_data = request.POST.copy()
if model._meta.has_field_type(FileField):
new_data.update(request.FILES)
# Check for errors
errors = manipulator.get_validation_errors(new_data)
manipulator.do_html2python(new_data)
if not errors:
# No errors -- this means we can save the data!
new_object = manipulator.save(new_data)
if request.user.is_authenticated():
request.user.message_set.create(message=ugettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._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 = manipulator.flatten_data()
# Create the FormWrapper, template, context, response
form = oldforms.FormWrapper(manipulator, new_data, errors)
if not template_name:
template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'form': form,
}, context_processors)
for key, value in extra_context.items():
if callable(value):
c[key] = value()
else:
c[key] = value
return HttpResponse(t.render(c))
def update_object(request, model, object_id=None, slug=None,
slug_field='slug', template_name=None, template_loader=loader,
extra_context=None, post_save_redirect=None,
login_required=False, follow=None, context_processors=None,
template_object_name='object'):
"""
Generic object-update function.
Templates: ``<app_label>/<model_name>_form.html``
Context:
form
the form wrapper for the object
object
the original object being edited
"""
if extra_context is None: extra_context = {}
if login_required and not request.user.is_authenticated():
return redirect_to_login(request.path)
# Look up the object to be edited
lookup_kwargs = {}
if object_id:
lookup_kwargs['%s__exact' % model._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")
try:
object = model.objects.get(**lookup_kwargs)
except ObjectDoesNotExist:
raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs)
manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow)
if request.POST:
new_data = request.POST.copy()
if model._meta.has_field_type(FileField):
new_data.update(request.FILES)
errors = manipulator.get_validation_errors(new_data)
manipulator.do_html2python(new_data)
if not errors:
object = manipulator.save(new_data)
if request.user.is_authenticated():
request.user.message_set.create(message=ugettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._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 = manipulator.flatten_data()
form = oldforms.FormWrapper(manipulator, new_data, errors)
if not template_name:
template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'form': form,
template_object_name: object,
}, context_processors)
for key, value in extra_context.items():
if callable(value):
c[key] = value()
else:
c[key] = value
response = HttpResponse(t.render(c))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
return response
def delete_object(request, model, post_delete_redirect,
object_id=None, slug=None, slug_field='slug', template_name=None,
template_loader=loader, extra_context=None,
login_required=False, context_processors=None, template_object_name='object'):
"""
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>/<model_name>_confirm_delete.html``
Context:
object
the original object being deleted
"""
if extra_context is None: extra_context = {}
if login_required and not request.user.is_authenticated():
return redirect_to_login(request.path)
# Look up the object to be edited
lookup_kwargs = {}
if object_id:
lookup_kwargs['%s__exact' % model._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")
try:
object = model._default_manager.get(**lookup_kwargs)
except ObjectDoesNotExist:
raise Http404, "No %s found for %s" % (model._meta.app_label, lookup_kwargs)
if request.method == 'POST':
object.delete()
if request.user.is_authenticated():
request.user.message_set.create(message=ugettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name})
return HttpResponseRedirect(post_delete_redirect)
else:
if not template_name:
template_name = "%s/%s_confirm_delete.html" % (model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
template_object_name: object,
}, context_processors)
for key, value in extra_context.items():
if callable(value):
c[key] = value()
else:
c[key] = value
response = HttpResponse(t.render(c))
populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
return response