mirror of
https://github.com/django/django.git
synced 2025-06-29 15:29: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:
parent
795e6cbcf2
commit
c4e2e4e881
@ -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 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.contrib.admin.views.changelist import IS_POPUP_VAR, EMPTY_CHANGELIST_VALUE, MONTHS
|
||||||
from django import template
|
from django import template
|
||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import dateformat
|
from django.utils import dateformat
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import get_date_formats
|
from django.utils.translation import get_date_formats
|
||||||
from django.conf import settings
|
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
from django import template
|
from django import template
|
||||||
|
from django.contrib.admin.views.main import AdminBoundField
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.functional import curry
|
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.fields import BoundField, Field
|
||||||
from django.db.models.related import BoundRelatedObject
|
from django.db.models.related import BoundRelatedObject
|
||||||
from django.db.models import TABULAR, STACKED
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import re
|
import re
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django.template import Library
|
from django.template import Library
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
def admin_media_prefix():
|
def admin_media_prefix():
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from django.contrib.admin.models import LogEntry
|
|
||||||
from django import template
|
from django import template
|
||||||
|
from django.contrib.admin.models import LogEntry
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -20,9 +20,11 @@ urlpatterns = patterns('',
|
|||||||
('^doc/models/(?P<model>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'),
|
('^doc/models/(?P<model>[^/]+)/$', 'django.contrib.admin.views.doc.model_detail'),
|
||||||
# ('^doc/templates/$', 'django.views.admin.doc.template_index'),
|
# ('^doc/templates/$', 'django.views.admin.doc.template_index'),
|
||||||
('^doc/templates/(?P<template>.*)/$', 'django.contrib.admin.views.doc.template_detail'),
|
('^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'),
|
('^((?:[^/]+/)+?)([^/]+)/history/$', 'django.contrib.admin.views.main.history'),
|
||||||
('^((?:[^/]+/)+?)([^/]+)/delete/$', 'django.contrib.admin.views.stages.delete.delete_stage'),
|
('^((?:[^/]+/)+?)([^/]+)/delete/$', 'django.contrib.admin.views.main.delete_stage'),
|
||||||
('^((?:[^/]+/)+?)([^/]+)/change/$', 'django.contrib.admin.views.stages.change.change_stage'),
|
('^((?:[^/]+/)+?)([^/]+)/change/$', 'django.contrib.admin.views.main.change_stage'),
|
||||||
('^((?:[^/]+/)+?)$', 'django.contrib.admin.views.changelist.change_list'),
|
('^((?:[^/]+/)+?)$', 'django.contrib.admin.views.changelist.change_list'),
|
||||||
)
|
)
|
||||||
|
@ -95,5 +95,5 @@ if docutils_is_available:
|
|||||||
docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
|
docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
|
||||||
docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference'
|
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)
|
create_reference_role(name, urlbase)
|
||||||
|
@ -8,6 +8,7 @@ from django.core.paginator import ObjectPaginator, InvalidPage
|
|||||||
from django.template import RequestContext as Context
|
from django.template import RequestContext as Context
|
||||||
from django.core.extensions import render_to_response
|
from django.core.extensions import render_to_response
|
||||||
from django.utils.dates import MONTHS
|
from django.utils.dates import MONTHS
|
||||||
|
|
||||||
# The system will display a "Show all" link only if the total result count
|
# The system will display a "Show all" link only if the total result count
|
||||||
# is less than or equal to this setting.
|
# is less than or equal to this setting.
|
||||||
MAX_SHOW_ALL_ALLOWED = 200
|
MAX_SHOW_ALL_ALLOWED = 200
|
||||||
@ -67,7 +68,6 @@ class ChangeList(object):
|
|||||||
|
|
||||||
def resolve_model(self, path, request):
|
def resolve_model(self, path, request):
|
||||||
self.model, self.app_label = get_model_and_app(path)
|
self.model, self.app_label = get_model_and_app(path)
|
||||||
# _get_mod_opts(app_label, module_name)
|
|
||||||
self.opts = self.model._meta
|
self.opts = self.model._meta
|
||||||
|
|
||||||
if not request.user.has_perm(self.app_label + '.' + self.opts.get_change_permission()):
|
if not request.user.has_perm(self.app_label + '.' + self.opts.get_change_permission()):
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from django.core.extensions import render_to_response
|
from django import http, template
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User, SESSION_KEY
|
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
|
from django.utils.translation import gettext_lazy
|
||||||
import base64, datetime, md5
|
import base64, datetime, md5
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
@ -25,7 +24,7 @@ def _display_login_form(request, error_message=''):
|
|||||||
'app_path': request.path,
|
'app_path': request.path,
|
||||||
'post_data': post_data,
|
'post_data': post_data,
|
||||||
'error_message': error_message
|
'error_message': error_message
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=template.RequestContext(request))
|
||||||
|
|
||||||
def _encode_post_data(post_data):
|
def _encode_post_data(post_data):
|
||||||
pickled = pickle.dumps(post_data)
|
pickled = pickle.dumps(post_data)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from django import template
|
from django import forms, template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
|
||||||
from django.core.extensions import get_object_or_404, render_to_response
|
from django.core.extensions import get_object_or_404, render_to_response
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models.fields import BoundField, BoundFieldLine, BoundFieldSet
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
from django.template import loader, RequestContext
|
from django.template import loader, RequestContext
|
||||||
from django.utils import dateformat
|
from django.utils import dateformat
|
||||||
@ -12,8 +13,15 @@ from django.utils.text import capfirst, get_text_list
|
|||||||
import operator
|
import operator
|
||||||
from itertools import izip
|
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/"
|
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):
|
def matches_app(mod, comps):
|
||||||
modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models'
|
modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models'
|
||||||
for c, mc in izip(comps, modcomps):
|
for c, mc in izip(comps, modcomps):
|
||||||
@ -69,10 +77,452 @@ def url_for_model(model):
|
|||||||
return url
|
return url
|
||||||
raise ImproperlyConfigured, '%s is not a model in an installed app' % model.__name__
|
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):
|
def index(request):
|
||||||
return render_to_response('admin/index', {'title': _('Site administration')}, context_instance=RequestContext(request))
|
return render_to_response('admin/index', {'title': _('Site administration')}, context_instance=RequestContext(request))
|
||||||
index = staff_member_required(index)
|
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):
|
def history(request, app_label, module_name, object_id):
|
||||||
mod, opts = _get_mod_opts(app_label, module_name)
|
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(),
|
action_list = LogEntry.objects.get_list(object_id__exact=object_id, content_type__id__exact=opts.get_content_type_id(),
|
||||||
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -2,7 +2,6 @@ from django.contrib.admin.views.decorators import staff_member_required
|
|||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django import template, forms
|
from django import template, forms
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.template import RequestContext as Context
|
|
||||||
from django.core.extensions import render_to_response
|
from django.core.extensions import render_to_response
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -27,7 +26,7 @@ def template_validator(request):
|
|||||||
return render_to_response('admin/template_validator', {
|
return render_to_response('admin/template_validator', {
|
||||||
'title': 'Template validator',
|
'title': 'Template validator',
|
||||||
'form': forms.FormWrapper(manipulator, new_data, errors),
|
'form': forms.FormWrapper(manipulator, new_data, errors),
|
||||||
}, context_instance=RequestContext(request))
|
}, context_instance=template.RequestContext(request))
|
||||||
template_validator = staff_member_required(template_validator)
|
template_validator = staff_member_required(template_validator)
|
||||||
|
|
||||||
class TemplateValidator(forms.Manipulator):
|
class TemplateValidator(forms.Manipulator):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user