1
0
mirror of https://github.com/django/django.git synced 2025-06-08 13:09:13 +00:00

magic-removal: Continued cleanup of various messiness in admin code. Tightened sprawling django.contrib.admin.views.stages package into django.contrib.admin.views.main module, as previously organized.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2043 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-01-17 22:57:50 +00:00
parent 795e6cbcf2
commit c4e2e4e881
15 changed files with 468 additions and 505 deletions

View File

@ -2,13 +2,13 @@ from django.contrib.admin.views.changelist import MAX_SHOW_ALL_ALLOWED, DEFAULT_
from django.contrib.admin.views.changelist import ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR
from django.contrib.admin.views.changelist import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE, MONTHS
from django import template
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils import dateformat
from django.utils.html import escape
from django.utils.text import capfirst
from django.utils.translation import get_date_formats
from django.conf import settings
from django.template import Library
register = Library()

View File

@ -1,12 +1,12 @@
from django import template
from django.contrib.admin.views.main import AdminBoundField
from django.template import loader
from django.utils.html import escape
from django.utils.text import capfirst
from django.utils.functional import curry
from django.contrib.admin.views.stages.modify import AdminBoundField
from django.db.models import TABULAR, STACKED
from django.db.models.fields import BoundField, Field
from django.db.models.related import BoundRelatedObject
from django.db.models import TABULAR, STACKED
from django.db import models
from django.conf import settings
import re
@ -126,7 +126,7 @@ class TabularBoundRelatedObject(BoundRelatedObject):
self.field_wrapper_list = [FieldWrapper(field) for field in self.relation.editable_fields()]
fields = self.relation.editable_fields()
self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping, fields, i)
for (i,field_mapping) in self.field_mappings.items() ]
self.original_row_needed = max([fw.use_raw_id_admin() for fw in self.field_wrapper_list])

View File

@ -1,4 +1,5 @@
from django.template import Library
register = Library()
def admin_media_prefix():

View File

@ -1,5 +1,5 @@
from django.contrib.admin.models import LogEntry
from django import template
from django.contrib.admin.models import LogEntry
register = template.Library()

View File

@ -20,9 +20,11 @@ urlpatterns = patterns('',
('^doc/models/(?P<model>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'),
# ('^doc/templates/$', 'django.views.admin.doc.template_index'),
('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'),
('^((?:[^/]+/)+?)add/$', 'django.contrib.admin.views.stages.add.add_stage'),
# Add/change/delete/history
('^((?:[^/]+/)+?)add/$', 'django.contrib.admin.views.main.add_stage'),
('^((?:[^/]+/)+?)([^/]+)/history/$', 'django.contrib.admin.views.main.history'),
('^((?:[^/]+/)+?)([^/]+)/delete/$', 'django.contrib.admin.views.stages.delete.delete_stage'),
('^((?:[^/]+/)+?)([^/]+)/change/$', 'django.contrib.admin.views.stages.change.change_stage'),
('^((?:[^/]+/)+?)([^/]+)/delete/$', 'django.contrib.admin.views.main.delete_stage'),
('^((?:[^/]+/)+?)([^/]+)/change/$', 'django.contrib.admin.views.main.change_stage'),
('^((?:[^/]+/)+?)$', 'django.contrib.admin.views.changelist.change_list'),
)

View File

@ -95,5 +95,5 @@ if docutils_is_available:
docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference'
for (name, urlbase) in ROLES.items():
for name, urlbase in ROLES.items():
create_reference_role(name, urlbase)

View File

@ -8,6 +8,7 @@ from django.core.paginator import ObjectPaginator, InvalidPage
from django.template import RequestContext as Context
from django.core.extensions import render_to_response
from django.utils.dates import MONTHS
# The system will display a "Show all" link only if the total result count
# is less than or equal to this setting.
MAX_SHOW_ALL_ALLOWED = 200
@ -67,7 +68,6 @@ class ChangeList(object):
def resolve_model(self, path, request):
self.model, self.app_label = get_model_and_app(path)
# _get_mod_opts(app_label, module_name)
self.opts = self.model._meta
if not request.user.has_perm(self.app_label + '.' + self.opts.get_change_permission()):

View File

@ -1,8 +1,7 @@
from django.core.extensions import render_to_response
from django.template import RequestContext
from django import http, template
from django.conf import settings
from django.contrib.auth.models import User, SESSION_KEY
from django import http
from django.core.extensions import render_to_response
from django.utils.translation import gettext_lazy
import base64, datetime, md5
import cPickle as pickle
@ -25,7 +24,7 @@ def _display_login_form(request, error_message=''):
'app_path': request.path,
'post_data': post_data,
'error_message': error_message
}, context_instance=RequestContext(request))
}, context_instance=template.RequestContext(request))
def _encode_post_data(post_data):
pickled = pickle.dumps(post_data)

View File

@ -1,9 +1,10 @@
from django import template
from django import forms, template
from django.conf import settings
from django.contrib.admin.views.decorators import staff_member_required
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
from django.core.extensions import get_object_or_404, render_to_response
from django.db import models
from django.db.models.fields import BoundField, BoundFieldLine, BoundFieldSet
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.template import loader, RequestContext
from django.utils import dateformat
@ -12,8 +13,15 @@ from django.utils.text import capfirst, get_text_list
import operator
from itertools import izip
try:
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
except ImportError:
raise ImproperlyConfigured, "You don't have 'django.contrib.admin' in INSTALLED_APPS."
ADMIN_PREFIX = "/admin/"
use_raw_id_admin = lambda field: isinstance(field.rel, (models.ManyToOne, models.ManyToMany)) and field.rel.raw_id_admin
def matches_app(mod, comps):
modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models'
for c, mc in izip(comps, modcomps):
@ -69,10 +77,452 @@ def url_for_model(model):
return url
raise ImproperlyConfigured, '%s is not a model in an installed app' % model.__name__
def log_add_message(user, opts, manipulator, new_object):
pk_value = getattr(new_object, opts.pk.attname)
LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), ADDITION)
def get_javascript_imports(opts, auto_populated_fields, ordered_objects, field_sets):
# Put in any necessary JavaScript imports.
js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
if auto_populated_fields:
js.append('js/urlify.js')
if opts.has_field_type(models.DateTimeField) or opts.has_field_type(models.TimeField) or opts.has_field_type(models.DateField):
js.extend(['js/calendar.js', 'js/admin/DateTimeShortcuts.js'])
if ordered_objects:
js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
if opts.admin.js:
js.extend(opts.admin.js)
seen_collapse = False
for field_set in field_sets:
if not seen_collapse and 'collapse' in field_set.classes:
seen_collapse = True
js.append('js/admin/CollapsedFieldsets.js' )
for field_line in field_set:
try:
for f in field_line:
if f.rel and isinstance(f, models.ManyToManyField) and f.rel.filter_interface:
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
raise StopIteration
except StopIteration:
break
return js
class AdminBoundField(BoundField):
def __init__(self, field, field_mapping, original):
super(AdminBoundField, self).__init__(field, field_mapping, original)
self.element_id = self.form_fields[0].get_id()
self.has_label_first = not isinstance(self.field, models.BooleanField)
self.raw_id_admin = use_raw_id_admin(field)
self.is_date_time = isinstance(field, models.DateTimeField)
self.is_file_field = isinstance(field, models.FileField)
self.needs_add_label = field.rel and isinstance(field.rel, models.ManyToOne) or isinstance(field.rel, models.ManyToMany) and field.rel.to._meta.admin
self.hidden = isinstance(self.field, models.AutoField)
self.first = False
classes = []
if self.raw_id_admin:
classes.append('nowrap')
if max([bool(f.errors()) for f in self.form_fields]):
classes.append('error')
if classes:
self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
self._repr_filled = False
if field.rel:
self.related_url = url_for_model(field.rel.to)
def _fetch_existing_display(self, func_name):
class_dict = self.original.__class__.__dict__
func = class_dict.get(func_name)
return func(self.original)
def _fill_existing_display(self):
if getattr(self, '_display_filled', False):
return
# HACK
if isinstance(self.field.rel, models.ManyToOne):
func_name = 'get_%s' % self.field.name
self._display = self._fetch_existing_display(func_name)
elif isinstance(self.field.rel, models.ManyToMany):
func_name = 'get_%s_list' % self.field.rel.singular
self._display = ", ".join([str(obj) for obj in self._fetch_existing_display(func_name)])
self._display_filled = True
def existing_display(self):
self._fill_existing_display()
return self._display
def __repr__(self):
return repr(self.__dict__)
def html_error_list(self):
return " ".join([form_field.html_error_list() for form_field in self.form_fields if form_field.errors])
def original_url(self):
if self.is_file_field and self.original and self.field.attname:
url_method = getattr(self.original, 'get_%s_url' % self.field.attname)
if callable(url_method):
return url_method()
return ''
class AdminBoundFieldLine(BoundFieldLine):
def __init__(self, field_line, field_mapping, original):
super(AdminBoundFieldLine, self).__init__(field_line, field_mapping, original, AdminBoundField)
for bound_field in self:
bound_field.first = True
break
class AdminBoundFieldSet(BoundFieldSet):
def __init__(self, field_set, field_mapping, original):
super(AdminBoundFieldSet, self).__init__(field_set, field_mapping, original, AdminBoundFieldLine)
class BoundManipulator(object):
def __init__(self, model, manipulator, field_mapping):
self.model = model
self.opts = model._meta
self.inline_related_objects = self.opts.get_followed_related_objects(manipulator.follow)
self.original = getattr(manipulator, 'original_object', None)
self.bound_field_sets = [field_set.bind(field_mapping, self.original, AdminBoundFieldSet)
for field_set in self.opts.admin.get_field_sets(self.opts)]
self.ordered_objects = self.opts.get_ordered_objects()[:]
class AdminBoundManipulator(BoundManipulator):
def __init__(self, model, manipulator, field_mapping):
super(AdminBoundManipulator, self).__init__(model, manipulator, field_mapping)
field_sets = self.opts.admin.get_field_sets(self.opts)
self.auto_populated_fields = [f for f in self.opts.fields if f.prepopulate_from]
self.javascript_imports = get_javascript_imports(self.opts, self.auto_populated_fields, self.ordered_objects, field_sets);
self.coltype = self.ordered_objects and 'colMS' or 'colM'
self.has_absolute_url = hasattr(model, 'get_absolute_url')
self.form_enc_attrib = self.opts.has_field_type(models.FileField) and 'enctype="multipart/form-data" ' or ''
self.first_form_field_id = self.bound_field_sets[0].bound_field_lines[0].bound_fields[0].form_fields[0].get_id();
self.ordered_object_pk_names = [o.pk.name for o in self.ordered_objects]
opts = self.opts
self.save_on_top = opts.admin.save_on_top
self.save_as = opts.admin.save_as
self.content_type_id = opts.get_content_type_id()
self.verbose_name_plural = opts.verbose_name_plural
self.verbose_name = opts.verbose_name
self.object_name = opts.object_name
def get_ordered_object_pk(self, ordered_obj):
for name in self.ordered_object_pk_names:
if hasattr(ordered_obj, name):
return str(getattr(ordered_obj, name))
return ""
def render_change_form(model, manipulator, app_label, context, add=False, change=False, show_delete=False, form_url=''):
opts = model._meta
extra_context = {
'add': add,
'change': change,
'bound_manipulator': AdminBoundManipulator(model, manipulator, context['form']),
'has_delete_permission': context['perms'][app_label][opts.get_delete_permission()],
'form_url': form_url,
'app_label': app_label,
}
context.update(extra_context)
return render_to_response(["admin/%s/%s/change_form" % (app_label, opts.object_name.lower() ),
"admin/%s/change_form" % app_label ,
"admin/change_form"], context_instance=context)
def index(request):
return render_to_response('admin/index', {'title': _('Site administration')}, context_instance=RequestContext(request))
index = staff_member_required(index)
def add_stage(request, path, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/change', object_id_override=None):
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
raise PermissionDenied
manipulator = model.AddManipulator()
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(models.FileField):
new_data.update(request.FILES)
#save a copy of the data to use for errors later.
data = new_data.copy()
manipulator.do_html2python(new_data)
#update the manipulator with the effects of previous commands.
manipulator.update(new_data)
#get the errors on the updated shape of the manipulator
#HACK - validators should not work on POSTED data directly...
errors = manipulator.get_validation_errors(data)
if request.POST.has_key("_preview"):
pass
elif request.POST.has_key("command"):
command_name = request.POST.get("command")
manipulator.do_command(command_name)
new_data = manipulator.flatten_data()
elif errors:
new_data = manipulator.flatten_data()
else:
new_object = manipulator.save_from_update()
log_add_message(request.user, opts, manipulator, new_object)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
pk_value = getattr(new_object, opts.pk.attname)
# Here, we distinguish between different save types by checking for
# the presence of keys in request.POST.
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.POST.has_key("_popup"):
post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value)
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
(pk_value, repr(new_object).replace('"', '\\"')))
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect(request.path)
else:
request.user.add_message(msg)
return HttpResponseRedirect(post_url)
else:
# Add default data.
new_data = manipulator.flatten_data()
# Override the defaults with GET params, if they exist.
new_data.update(dict(request.GET.items()))
errors = {}
# Populate the FormWrapper.
form = forms.FormWrapper(manipulator, new_data, errors)
c = RequestContext(request, {
'title': _('Add %s') % opts.verbose_name,
'form': form,
'is_popup': request.REQUEST.has_key('_popup'),
'show_delete': show_delete,
'path': path ,
})
if object_id_override is not None:
c['object_id'] = object_id_override
return render_change_form(model, manipulator, app_label, c, add=True)
add_stage = staff_member_required(add_stage)
def log_change_message(user, opts, manipulator, new_object):
pk_value = getattr(new_object, opts.pk.column)
# Construct the change message.
change_message = []
if manipulator.fields_added:
change_message.append(_('Added %s.') % get_text_list(manipulator.fields_added, _('and')))
if manipulator.fields_changed:
change_message.append(_('Changed %s.') % get_text_list(manipulator.fields_changed, _('and')))
if manipulator.fields_deleted:
change_message.append(_('Deleted %s.') % get_text_list(manipulator.fields_deleted, _('and')))
change_message = ' '.join(change_message)
if not change_message:
change_message = _('No fields changed.')
LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), CHANGE, change_message)
def change_stage(request, path, object_id):
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
raise PermissionDenied
if request.POST and request.POST.has_key("_saveasnew"):
return add_stage(request, path, form_url='../../add/')
try:
manipulator = model.ChangeManipulator(object_id)
except ObjectDoesNotExist:
raise Http404
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(models.FileField):
new_data.update(request.FILES)
#save a copy of the data to use for errors later.
data = new_data.copy()
manipulator.do_html2python(new_data)
#update the manipulator with the effects of previous commands.
manipulator.update(new_data)
#get the errors on the updated shape of the manipulator
#HACK - validators should not work on POSTED data directly...
if request.POST.has_key("_preview"):
errors = manipulator.get_validation_errors(data)
elif request.POST.has_key("command"):
command_name = request.POST.get("command")
manipulator.do_command(command_name)
errors = manipulator.get_validation_errors(data)
new_data = manipulator.flatten_data()
else:
errors = manipulator.get_validation_errors(data)
if errors:
new_data = manipulator.flatten_data()
else:
new_object = manipulator.save_from_update()
log_change_message(request.user, opts, manipulator, new_object)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
pk_value = getattr(new_object, opts.pk.attname)
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.REQUEST.has_key('_popup'):
return HttpResponseRedirect(request.path + "?_popup=1")
else:
return HttpResponseRedirect(request.path)
elif request.POST.has_key("_saveasnew"):
request.user.add_message(_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
return HttpResponseRedirect("../../%s/" % pk_value)
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect("../../add/")
else:
request.user.add_message(msg)
return HttpResponseRedirect("../../")
else:
# Populate new_data with a "flattened" version of the current data.
new_data = manipulator.flatten_data()
errors = {}
# Populate the FormWrapper.
form = forms.FormWrapper(manipulator, new_data, errors)
form.original = manipulator.original_object
form.order_objects = []
c = RequestContext(request, {
'title': _('Change %s') % opts.verbose_name,
'form': form,
'object_id': object_id,
'original': manipulator.original_object,
'is_popup': request.REQUEST.has_key('_popup'),
'path': path ,
})
return render_change_form(model, manipulator, app_label, c, change=True)
change_stage = staff_member_required(change_stage)
def _nest_help(obj, depth, val):
current = obj
for i in range(depth):
current = current[-1]
current.append(val)
def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth):
"Helper function that recursively populates deleted_objects."
nh = _nest_help # Bind to local variable for performance
if current_depth > 16:
return # Avoid recursing too deep.
opts_seen = []
for related in opts.get_all_related_objects():
if related.opts in opts_seen:
continue
opts_seen.append(related.opts)
rel_opts_name = related.get_method_name_part()
if isinstance(related.field.rel, models.OneToOne):
try:
sub_obj = getattr(obj, 'get_%s' % rel_opts_name)()
except ObjectDoesNotExist:
pass
else:
if related.opts.admin:
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
# We don't care about populating deleted_objects now.
continue
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/change/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
getattr(sub_obj, related.opts.pk.attname), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
else:
has_related_objs = False
for sub_obj in getattr(obj, 'get_%s_list' % rel_opts_name)():
has_related_objs = True
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(str(sub_obj))), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/change/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), getattr(sub_obj, related.opts.pk.attname), escape(str(sub_obj))), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
# If there were related objects, and the user doesn't have
# permission to delete them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
if not user.has_perm(p):
perms_needed.add(rel_opts.verbose_name)
for related in opts.get_all_related_many_to_many_objects():
if related.opts in opts_seen:
continue
opts_seen.append(related.opts)
rel_opts_name = related.get_method_name_part()
has_related_objs = False
for sub_obj in getattr(obj, 'get_%s_list' % rel_opts_name)():
has_related_objs = True
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \
{'fieldname': related.field.name, 'name': related.opts.verbose_name, 'obj': escape(str(sub_obj))}, []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, [
(_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.name, 'name':related.opts.verbose_name}) + \
(' <a href="../../../../%s/%s/%s/">%s</a>' % \
(related.opts.app_label, related.opts.module_name, getattr(sub_obj, related.opts.pk.attname), escape(str(sub_obj)))), []])
# If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
def delete_stage(request, path, object_id):
import sets
#mod, opts = _get_mod_opts(app_label, module_name)
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_delete_permission()):
raise PermissionDenied
obj = get_object_or_404(model, pk=object_id)
# Populate deleted_objects, a data structure of all related objects that
# will also be deleted.
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(str(obj))), []]
perms_needed = sets.Set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
if request.POST: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied
obj_display = str(obj)
obj.delete()
LogEntry.objects.log_action(request.user.id, opts.get_content_type_id(), object_id, obj_display, DELETION)
request.user.add_message(_('The %(name)s "%(obj)s" was deleted successfully.') % {'name':opts.verbose_name, 'obj':obj_display})
return HttpResponseRedirect("../../")
return render_to_response('admin/delete_confirmation', {
"title": _("Are you sure?"),
"object_name": opts.verbose_name,
"object": obj,
"deleted_objects": deleted_objects,
"perms_lacking": perms_needed,
}, context_instance=RequestContext(request))
delete_stage = staff_member_required(delete_stage)
def history(request, app_label, module_name, object_id):
mod, opts = _get_mod_opts(app_label, module_name)
action_list = LogEntry.objects.get_list(object_id__exact=object_id, content_type__id__exact=opts.get_content_type_id(),

View File

@ -1,95 +0,0 @@
from django.contrib.admin.models import LogEntry
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.admin.views.main import get_model_and_app
from django.contrib.admin.views.stages.modify import render_change_form
from django import forms
from django import template
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
from django.template import RequestContext as Context
from django.db import models
from django.utils.text import capfirst, get_text_list
try:
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
except ImportError:
raise ImproperlyConfigured, "You don't have 'django.contrib.admin' in INSTALLED_APPS."
def log_add_message(user, opts, manipulator, new_object):
pk_value = getattr(new_object, opts.pk.attname)
LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), ADDITION)
def add_stage(request, path, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/change', object_id_override=None):
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
raise PermissionDenied
manipulator = model.AddManipulator()
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(models.FileField):
new_data.update(request.FILES)
#save a copy of the data to use for errors later.
data = new_data.copy()
manipulator.do_html2python(new_data)
#update the manipulator with the effects of previous commands.
manipulator.update(new_data)
#get the errors on the updated shape of the manipulator
#HACK - validators should not work on POSTED data directly...
errors = manipulator.get_validation_errors(data)
if request.POST.has_key("_preview"):
pass
elif request.POST.has_key("command"):
command_name = request.POST.get("command")
manipulator.do_command(command_name)
new_data = manipulator.flatten_data()
elif errors:
new_data = manipulator.flatten_data()
else:
new_object = manipulator.save_from_update()
log_add_message(request.user, opts, manipulator, new_object)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
pk_value = getattr(new_object, opts.pk.attname)
# Here, we distinguish between different save types by checking for
# the presence of keys in request.POST.
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.POST.has_key("_popup"):
post_url_continue += "?_popup=1"
return HttpResponseRedirect(post_url_continue % pk_value)
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
(pk_value, repr(new_object).replace('"', '\\"')))
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect(request.path)
else:
request.user.add_message(msg)
return HttpResponseRedirect(post_url)
else:
# Add default data.
new_data = manipulator.flatten_data()
# Override the defaults with GET params, if they exist.
new_data.update(dict(request.GET.items()))
errors = {}
# Populate the FormWrapper.
form = forms.FormWrapper(manipulator, new_data, errors)
c = Context(request, {
'title': _('Add %s') % opts.verbose_name,
'form': form,
'is_popup': request.REQUEST.has_key('_popup'),
'show_delete': show_delete,
'path': path ,
})
if object_id_override is not None:
c['object_id'] = object_id_override
return render_change_form(model, manipulator, app_label, c, add=True)
add_stage = staff_member_required(add_stage)

View File

@ -1,107 +0,0 @@
from django.contrib.admin.views.main import get_model_and_app
from django import forms
from django import template
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
from django.template import RequestContext as Context
from django.contrib.admin.views.stages.modify import render_change_form
from django.db import models
from django.utils.text import capfirst, get_text_list
from django.contrib.admin.views.decorators import staff_member_required
try:
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
except ImportError:
raise ImproperlyConfigured, "You don't have 'django.contrib.admin' in INSTALLED_APPS."
def log_change_message(user, opts, manipulator, new_object):
pk_value = getattr(new_object, opts.pk.column)
# Construct the change message.
change_message = []
if manipulator.fields_added:
change_message.append(_('Added %s.') % get_text_list(manipulator.fields_added, _('and')))
if manipulator.fields_changed:
change_message.append(_('Changed %s.') % get_text_list(manipulator.fields_changed, _('and')))
if manipulator.fields_deleted:
change_message.append(_('Deleted %s.') % get_text_list(manipulator.fields_deleted, _('and')))
change_message = ' '.join(change_message)
if not change_message:
change_message = _('No fields changed.')
LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), CHANGE, change_message)
def change_stage(request, path, object_id):
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
raise PermissionDenied
if request.POST and request.POST.has_key("_saveasnew"):
return add_stage(request, path, form_url='../../add/')
try:
manipulator = model.ChangeManipulator(object_id)
except ObjectDoesNotExist:
raise Http404
if request.POST:
new_data = request.POST.copy()
if opts.has_field_type(models.FileField):
new_data.update(request.FILES)
#save a copy of the data to use for errors later.
data = new_data.copy()
manipulator.do_html2python(new_data)
#update the manipulator with the effects of previous commands.
manipulator.update(new_data)
#get the errors on the updated shape of the manipulator
#HACK - validators should not work on POSTED data directly...
if request.POST.has_key("_preview"):
errors = manipulator.get_validation_errors(data)
elif request.POST.has_key("command"):
command_name = request.POST.get("command")
manipulator.do_command(command_name)
errors = manipulator.get_validation_errors(data)
new_data = manipulator.flatten_data()
else:
errors = manipulator.get_validation_errors(data)
if errors:
new_data = manipulator.flatten_data()
else:
new_object = manipulator.save_from_update()
log_change_message(request.user, opts, manipulator, new_object)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
pk_value = getattr(new_object, opts.pk.attname)
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.REQUEST.has_key('_popup'):
return HttpResponseRedirect(request.path + "?_popup=1")
else:
return HttpResponseRedirect(request.path)
elif request.POST.has_key("_saveasnew"):
request.user.add_message(_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
return HttpResponseRedirect("../../%s/" % pk_value)
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect("../../add/")
else:
request.user.add_message(msg)
return HttpResponseRedirect("../../")
else:
# Populate new_data with a "flattened" version of the current data.
new_data = manipulator.flatten_data()
errors = {}
# Populate the FormWrapper.
form = forms.FormWrapper(manipulator, new_data, errors)
form.original = manipulator.original_object
form.order_objects = []
c = Context(request, {
'title': _('Change %s') % opts.verbose_name,
'form': form,
'object_id': object_id,
'original': manipulator.original_object,
'is_popup': request.REQUEST.has_key('_popup'),
'path': path ,
})
return render_change_form(model, manipulator, app_label, c, change=True)
change_stage = staff_member_required(change_stage)

View File

@ -1,128 +0,0 @@
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.admin.views.main import get_model_and_app
from django.core.extensions import get_object_or_404, render_to_response
from django.template import RequestContext as Context
from django.utils.text import capfirst
from django.utils.html import escape
from django.db import models
try:
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
except ImportError:
raise ImproperlyConfigured, "You don't have 'django.contrib.admin' in INSTALLED_APPS."
from django.http import HttpResponse, HttpResponseRedirect
def _nest_help(obj, depth, val):
current = obj
for i in range(depth):
current = current[-1]
current.append(val)
def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth):
"Helper function that recursively populates deleted_objects."
nh = _nest_help # Bind to local variable for performance
if current_depth > 16:
return # Avoid recursing too deep.
opts_seen = []
for related in opts.get_all_related_objects():
if related.opts in opts_seen:
continue
opts_seen.append(related.opts)
rel_opts_name = related.get_method_name_part()
if isinstance(related.field.rel, models.OneToOne):
try:
sub_obj = getattr(obj, 'get_%s' % rel_opts_name)()
except ObjectDoesNotExist:
pass
else:
if related.opts.admin:
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
# We don't care about populating deleted_objects now.
continue
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/change/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
getattr(sub_obj, related.opts.pk.attname), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
else:
has_related_objs = False
for sub_obj in getattr(obj, 'get_%s_list' % rel_opts_name)():
has_related_objs = True
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(str(sub_obj))), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/change/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), getattr(sub_obj, related.opts.pk.attname), escape(str(sub_obj))), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
# If there were related objects, and the user doesn't have
# permission to delete them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
if not user.has_perm(p):
perms_needed.add(rel_opts.verbose_name)
for related in opts.get_all_related_many_to_many_objects():
if related.opts in opts_seen:
continue
opts_seen.append(related.opts)
rel_opts_name = related.get_method_name_part()
has_related_objs = False
for sub_obj in getattr(obj, 'get_%s_list' % rel_opts_name)():
has_related_objs = True
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \
{'fieldname': related.field.name, 'name': related.opts.verbose_name, 'obj': escape(str(sub_obj))}, []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, [
(_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.name, 'name':related.opts.verbose_name}) + \
(' <a href="../../../../%s/%s/%s/">%s</a>' % \
(related.opts.app_label, related.opts.module_name, getattr(sub_obj, related.opts.pk.attname), escape(str(sub_obj)))), []])
# If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
def delete_stage(request, path, object_id):
import sets
#mod, opts = _get_mod_opts(app_label, module_name)
model, app_label = get_model_and_app(path)
opts = model._meta
if not request.user.has_perm(app_label + '.' + opts.get_delete_permission()):
raise PermissionDenied
obj = get_object_or_404(model, pk=object_id)
# Populate deleted_objects, a data structure of all related objects that
# will also be deleted.
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(str(obj))), []]
perms_needed = sets.Set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
if request.POST: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied
obj_display = str(obj)
obj.delete()
LogEntry.objects.log_action(request.user.id, opts.get_content_type_id(), object_id, obj_display, DELETION)
request.user.add_message(_('The %(name)s "%(obj)s" was deleted successfully.') % {'name':opts.verbose_name, 'obj':obj_display})
return HttpResponseRedirect("../../")
return render_to_response('admin/delete_confirmation', {
"title": _("Are you sure?"),
"object_name": opts.verbose_name,
"object": obj,
"deleted_objects": deleted_objects,
"perms_lacking": perms_needed,
}, context_instance=Context(request))
delete_stage = staff_member_required(delete_stage)

View File

@ -1,158 +0,0 @@
from django.db.models.fields import BoundField, BoundFieldLine, BoundFieldSet
from django.db import models
from django.core.extensions import render_to_response
from django.contrib.admin.views.main import url_for_model
use_raw_id_admin = lambda field: isinstance(field.rel, (models.ManyToOne, models.ManyToMany)) and field.rel.raw_id_admin
def get_javascript_imports(opts, auto_populated_fields, ordered_objects, field_sets):
# Put in any necessary JavaScript imports.
js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
if auto_populated_fields:
js.append('js/urlify.js')
if opts.has_field_type(models.DateTimeField) or opts.has_field_type(models.TimeField) or opts.has_field_type(models.DateField):
js.extend(['js/calendar.js', 'js/admin/DateTimeShortcuts.js'])
if ordered_objects:
js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
if opts.admin.js:
js.extend(opts.admin.js)
seen_collapse = False
for field_set in field_sets:
if not seen_collapse and 'collapse' in field_set.classes:
seen_collapse = True
js.append('js/admin/CollapsedFieldsets.js' )
for field_line in field_set:
try:
for f in field_line:
if f.rel and isinstance(f, models.ManyToManyField) and f.rel.filter_interface:
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
raise StopIteration
except StopIteration:
break
return js
class AdminBoundField(BoundField):
def __init__(self, field, field_mapping, original):
super(AdminBoundField, self).__init__(field, field_mapping, original)
self.element_id = self.form_fields[0].get_id()
self.has_label_first = not isinstance(self.field, models.BooleanField)
self.raw_id_admin = use_raw_id_admin(field)
self.is_date_time = isinstance(field, models.DateTimeField)
self.is_file_field = isinstance(field, models.FileField)
self.needs_add_label = field.rel and isinstance(field.rel, models.ManyToOne) or isinstance(field.rel, models.ManyToMany) and field.rel.to._meta.admin
self.hidden = isinstance(self.field, models.AutoField)
self.first = False
classes = []
if self.raw_id_admin:
classes.append('nowrap')
if max([bool(f.errors()) for f in self.form_fields]):
classes.append('error')
if classes:
self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
self._repr_filled = False
if field.rel:
self.related_url = url_for_model(field.rel.to)
def _fetch_existing_display(self, func_name):
class_dict = self.original.__class__.__dict__
func = class_dict.get(func_name)
return func(self.original)
def _fill_existing_display(self):
if getattr(self, '_display_filled', False):
return
# HACK
if isinstance(self.field.rel, models.ManyToOne):
func_name = 'get_%s' % self.field.name
self._display = self._fetch_existing_display(func_name)
elif isinstance(self.field.rel, models.ManyToMany):
func_name = 'get_%s_list' % self.field.rel.singular
self._display = ", ".join([str(obj) for obj in self._fetch_existing_display(func_name)])
self._display_filled = True
def existing_display(self):
self._fill_existing_display()
return self._display
def __repr__(self):
return repr(self.__dict__)
def html_error_list(self):
return " ".join([form_field.html_error_list() for form_field in self.form_fields if form_field.errors])
def original_url(self):
if self.is_file_field and self.original and self.field.attname:
url_method = getattr(self.original, 'get_%s_url' % self.field.attname)
if callable(url_method):
return url_method()
return ''
class AdminBoundFieldLine(BoundFieldLine):
def __init__(self, field_line, field_mapping, original):
super(AdminBoundFieldLine, self).__init__(field_line, field_mapping, original, AdminBoundField)
for bound_field in self:
bound_field.first = True
break
class AdminBoundFieldSet(BoundFieldSet):
def __init__(self, field_set, field_mapping, original):
super(AdminBoundFieldSet, self).__init__(field_set, field_mapping, original, AdminBoundFieldLine)
class BoundManipulator(object):
def __init__(self, model, manipulator, field_mapping):
self.model = model
self.opts = model._meta
self.inline_related_objects = self.opts.get_followed_related_objects(manipulator.follow)
self.original = getattr(manipulator, 'original_object', None)
self.bound_field_sets = [field_set.bind(field_mapping, self.original, AdminBoundFieldSet)
for field_set in self.opts.admin.get_field_sets(self.opts)]
self.ordered_objects = self.opts.get_ordered_objects()[:]
class AdminBoundManipulator(BoundManipulator):
def __init__(self, model, manipulator, field_mapping):
super(AdminBoundManipulator, self).__init__(model, manipulator, field_mapping)
field_sets = self.opts.admin.get_field_sets(self.opts)
self.auto_populated_fields = [f for f in self.opts.fields if f.prepopulate_from]
self.javascript_imports = get_javascript_imports(self.opts, self.auto_populated_fields, self.ordered_objects, field_sets);
self.coltype = self.ordered_objects and 'colMS' or 'colM'
self.has_absolute_url = hasattr(model, 'get_absolute_url')
self.form_enc_attrib = self.opts.has_field_type(models.FileField) and 'enctype="multipart/form-data" ' or ''
self.first_form_field_id = self.bound_field_sets[0].bound_field_lines[0].bound_fields[0].form_fields[0].get_id();
self.ordered_object_pk_names = [o.pk.name for o in self.ordered_objects]
opts = self.opts
self.save_on_top = opts.admin.save_on_top
self.save_as = opts.admin.save_as
self.content_type_id = opts.get_content_type_id()
self.verbose_name_plural = opts.verbose_name_plural
self.verbose_name = opts.verbose_name
self.object_name = opts.object_name
def get_ordered_object_pk(self, ordered_obj):
for name in self.ordered_object_pk_names:
if hasattr(ordered_obj, name):
return str(getattr(ordered_obj, name))
return ""
def render_change_form(model, manipulator, app_label, context, add=False, change=False, show_delete=False, form_url=''):
opts = model._meta
extra_context = {
'add': add,
'change': change,
'bound_manipulator': AdminBoundManipulator(model, manipulator, context['form']),
'has_delete_permission': context['perms'][app_label][opts.get_delete_permission()],
'form_url': form_url,
'app_label': app_label,
}
context.update(extra_context)
return render_to_response(["admin/%s/%s/change_form" % (app_label, opts.object_name.lower() ),
"admin/%s/change_form" % app_label ,
"admin/change_form"], context_instance=context)

View File

@ -2,7 +2,6 @@ from django.contrib.admin.views.decorators import staff_member_required
from django.core import validators
from django import template, forms
from django.template import loader
from django.template import RequestContext as Context
from django.core.extensions import render_to_response
from django.contrib.sites.models import Site
from django.conf import settings
@ -27,7 +26,7 @@ def template_validator(request):
return render_to_response('admin/template_validator', {
'title': 'Template validator',
'form': forms.FormWrapper(manipulator, new_data, errors),
}, context_instance=RequestContext(request))
}, context_instance=template.RequestContext(request))
template_validator = staff_member_required(template_validator)
class TemplateValidator(forms.Manipulator):