mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +00:00
newforms-admin: Renamed ModelAdminView to ModelAdmin, moved it into django.contrib.admin.options and put model imports within methods to avoid import-order problems
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4326 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
40256823fd
commit
28990ef07b
346
django/contrib/admin/options.py
Normal file
346
django/contrib/admin/options.py
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
from django import oldforms, template
|
||||||
|
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||||
|
from django.db import models
|
||||||
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import get_object_or_404, render_to_response
|
||||||
|
from django.utils.html import escape
|
||||||
|
from django.utils.text import capfirst, get_text_list
|
||||||
|
import sets
|
||||||
|
|
||||||
|
class IncorrectLookupParameters(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unquote(s):
|
||||||
|
"""
|
||||||
|
Undo the effects of quote(). Based heavily on urllib.unquote().
|
||||||
|
"""
|
||||||
|
mychr = chr
|
||||||
|
myatoi = int
|
||||||
|
list = s.split('_')
|
||||||
|
res = [list[0]]
|
||||||
|
myappend = res.append
|
||||||
|
del list[0]
|
||||||
|
for item in list:
|
||||||
|
if item[1:2]:
|
||||||
|
try:
|
||||||
|
myappend(mychr(myatoi(item[:2], 16)) + item[2:])
|
||||||
|
except ValueError:
|
||||||
|
myappend('_' + item)
|
||||||
|
else:
|
||||||
|
myappend('_' + item)
|
||||||
|
return "".join(res)
|
||||||
|
|
||||||
|
class ModelAdmin(object):
|
||||||
|
"Encapsulates all admin options and functionality for a given model."
|
||||||
|
def __init__(self, model):
|
||||||
|
self.model = model
|
||||||
|
self.opts = model._meta
|
||||||
|
|
||||||
|
def __call__(self, request, url):
|
||||||
|
# Check that LogEntry, ContentType and the auth context processor are installed.
|
||||||
|
from django.conf import settings
|
||||||
|
if settings.DEBUG:
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.admin.models import LogEntry
|
||||||
|
if not LogEntry._meta.installed:
|
||||||
|
raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.")
|
||||||
|
if not ContentType._meta.installed:
|
||||||
|
raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.")
|
||||||
|
if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
|
||||||
|
raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
|
||||||
|
|
||||||
|
# Delegate to the appropriate method, based on the URL.
|
||||||
|
if url is None:
|
||||||
|
return self.change_list_view(request)
|
||||||
|
elif url.endswith('add'):
|
||||||
|
return self.add_view(request)
|
||||||
|
elif url.endswith('history'):
|
||||||
|
return self.history_view(request, unquote(url[:-8]))
|
||||||
|
elif url.endswith('delete'):
|
||||||
|
return self.delete_view(request, unquote(url[:-7]))
|
||||||
|
else:
|
||||||
|
return self.change_view(request, unquote(url))
|
||||||
|
|
||||||
|
def has_add_permission(self, request):
|
||||||
|
"Returns True if the given request has permission to add an object."
|
||||||
|
opts = self.opts
|
||||||
|
return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
|
||||||
|
|
||||||
|
def has_change_permission(self, request, object_id):
|
||||||
|
"""
|
||||||
|
Returns True if the given request has permission to change the object
|
||||||
|
with the given object_id.
|
||||||
|
"""
|
||||||
|
opts = self.opts
|
||||||
|
return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
|
||||||
|
|
||||||
|
def has_delete_permission(self, request, object_id):
|
||||||
|
"""
|
||||||
|
Returns True if the given request has permission to change the object
|
||||||
|
with the given object_id.
|
||||||
|
"""
|
||||||
|
opts = self.opts
|
||||||
|
return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())
|
||||||
|
|
||||||
|
def add_view(self, request, show_delete=False, form_url='', post_url=None, post_url_continue='../%s/', object_id_override=None):
|
||||||
|
"The 'add' admin view for this model."
|
||||||
|
from django.contrib.admin.views.main import render_change_form
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.admin.models import LogEntry, ADDITION
|
||||||
|
model = self.model
|
||||||
|
opts = model._meta
|
||||||
|
app_label = opts.app_label
|
||||||
|
|
||||||
|
if not self.has_add_permission(request):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
if post_url is None:
|
||||||
|
if self.has_change_permission(request, None):
|
||||||
|
# redirect to list view
|
||||||
|
post_url = '../'
|
||||||
|
else:
|
||||||
|
# Object list will give 'Permission Denied', so go back to admin home
|
||||||
|
post_url = '../../../'
|
||||||
|
|
||||||
|
manipulator = model.AddManipulator()
|
||||||
|
if request.POST:
|
||||||
|
new_data = request.POST.copy()
|
||||||
|
|
||||||
|
if opts.has_field_type(models.FileField):
|
||||||
|
new_data.update(request.FILES)
|
||||||
|
|
||||||
|
errors = manipulator.get_validation_errors(new_data)
|
||||||
|
manipulator.do_html2python(new_data)
|
||||||
|
|
||||||
|
if not errors:
|
||||||
|
new_object = manipulator.save(new_data)
|
||||||
|
pk_value = new_object._get_pk_val()
|
||||||
|
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION)
|
||||||
|
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
||||||
|
# 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.message_set.create(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"):
|
||||||
|
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
|
||||||
|
pk_value = '"%s"' % pk_value.replace('"', '\\"')
|
||||||
|
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
|
||||||
|
(pk_value, str(new_object).replace('"', '\\"')))
|
||||||
|
elif request.POST.has_key("_addanother"):
|
||||||
|
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
||||||
|
return HttpResponseRedirect(request.path)
|
||||||
|
else:
|
||||||
|
request.user.message_set.create(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 = oldforms.FormWrapper(manipulator, new_data, errors)
|
||||||
|
|
||||||
|
c = template.RequestContext(request, {
|
||||||
|
'title': _('Add %s') % opts.verbose_name,
|
||||||
|
'form': form,
|
||||||
|
'is_popup': request.REQUEST.has_key('_popup'),
|
||||||
|
'show_delete': show_delete,
|
||||||
|
})
|
||||||
|
|
||||||
|
if object_id_override is not None:
|
||||||
|
c['object_id'] = object_id_override
|
||||||
|
|
||||||
|
return render_change_form(model, manipulator, c, add=True)
|
||||||
|
|
||||||
|
def change_view(self, request, object_id):
|
||||||
|
"The 'change' admin view for this model."
|
||||||
|
from django.contrib.admin.views.main import render_change_form
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.admin.models import LogEntry, CHANGE
|
||||||
|
model = self.model
|
||||||
|
opts = model._meta
|
||||||
|
app_label = opts.app_label
|
||||||
|
|
||||||
|
if not self.has_change_permission(request, object_id):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
if request.POST and request.POST.has_key("_saveasnew"):
|
||||||
|
return self.add_view(request, form_url='../../add/')
|
||||||
|
|
||||||
|
try:
|
||||||
|
manipulator = model.ChangeManipulator(object_id)
|
||||||
|
except model.DoesNotExist:
|
||||||
|
raise Http404('%s object with primary key %r does not exist' % (model_name, escape(object_id)))
|
||||||
|
|
||||||
|
if request.POST:
|
||||||
|
new_data = request.POST.copy()
|
||||||
|
|
||||||
|
if opts.has_field_type(models.FileField):
|
||||||
|
new_data.update(request.FILES)
|
||||||
|
|
||||||
|
errors = manipulator.get_validation_errors(new_data)
|
||||||
|
manipulator.do_html2python(new_data)
|
||||||
|
|
||||||
|
if not errors:
|
||||||
|
new_object = manipulator.save(new_data)
|
||||||
|
pk_value = new_object._get_pk_val()
|
||||||
|
|
||||||
|
# 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(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message)
|
||||||
|
|
||||||
|
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
||||||
|
if request.POST.has_key("_continue"):
|
||||||
|
request.user.message_set.create(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.message_set.create(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.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
||||||
|
return HttpResponseRedirect("../add/")
|
||||||
|
else:
|
||||||
|
request.user.message_set.create(message=msg)
|
||||||
|
return HttpResponseRedirect("../")
|
||||||
|
else:
|
||||||
|
# Populate new_data with a "flattened" version of the current data.
|
||||||
|
new_data = manipulator.flatten_data()
|
||||||
|
|
||||||
|
# TODO: do this in flatten_data...
|
||||||
|
# If the object has ordered objects on its admin page, get the existing
|
||||||
|
# order and flatten it into a comma-separated list of IDs.
|
||||||
|
id_order_list = []
|
||||||
|
for rel_obj in opts.get_ordered_objects():
|
||||||
|
id_order_list.extend(getattr(manipulator.original_object, 'get_%s_order' % rel_obj.object_name.lower())())
|
||||||
|
if id_order_list:
|
||||||
|
new_data['order_'] = ','.join(map(str, id_order_list))
|
||||||
|
errors = {}
|
||||||
|
|
||||||
|
# Populate the FormWrapper.
|
||||||
|
form = oldforms.FormWrapper(manipulator, new_data, errors)
|
||||||
|
form.original = manipulator.original_object
|
||||||
|
form.order_objects = []
|
||||||
|
|
||||||
|
# TODO: Should be done in flatten_data / FormWrapper construction
|
||||||
|
for related in opts.get_followed_related_objects():
|
||||||
|
wrt = related.opts.order_with_respect_to
|
||||||
|
if wrt and wrt.rel and wrt.rel.to == opts:
|
||||||
|
func = getattr(manipulator.original_object, 'get_%s_list' %
|
||||||
|
related.get_accessor_name())
|
||||||
|
orig_list = func()
|
||||||
|
form.order_objects.extend(orig_list)
|
||||||
|
|
||||||
|
c = template.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'),
|
||||||
|
})
|
||||||
|
return render_change_form(model, manipulator, c, change=True)
|
||||||
|
|
||||||
|
def change_list_view(self, request):
|
||||||
|
"The 'change list' admin view for this model."
|
||||||
|
from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
|
||||||
|
opts = self.model._meta
|
||||||
|
app_label = opts.app_label
|
||||||
|
if not self.has_change_permission(request, None):
|
||||||
|
raise PermissionDenied
|
||||||
|
try:
|
||||||
|
cl = ChangeList(request, self.model)
|
||||||
|
except IncorrectLookupParameters:
|
||||||
|
# Wacky lookup parameters were given, so redirect to the main
|
||||||
|
# changelist page, without parameters, and pass an 'invalid=1'
|
||||||
|
# parameter via the query string. If wacky parameters were given and
|
||||||
|
# the 'invalid=1' parameter was already in the query string, something
|
||||||
|
# is screwed up with the database, so display an error page.
|
||||||
|
if ERROR_FLAG in request.GET.keys():
|
||||||
|
return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
|
||||||
|
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
|
||||||
|
c = template.RequestContext(request, {
|
||||||
|
'title': cl.title,
|
||||||
|
'is_popup': cl.is_popup,
|
||||||
|
'cl': cl,
|
||||||
|
})
|
||||||
|
c.update({'has_add_permission': c['perms'][app_label][opts.get_add_permission()]}),
|
||||||
|
return render_to_response(['admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
|
||||||
|
'admin/%s/change_list.html' % app_label,
|
||||||
|
'admin/change_list.html'], context_instance=c)
|
||||||
|
|
||||||
|
def delete_view(self, request, object_id):
|
||||||
|
"The 'delete' admin view for this model."
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.admin.models import LogEntry, DELETION
|
||||||
|
opts = self.model._meta
|
||||||
|
app_label = opts.app_label
|
||||||
|
if not self.has_delete_permission(request, object_id):
|
||||||
|
raise PermissionDenied
|
||||||
|
obj = get_object_or_404(self.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, ContentType.objects.get_for_model(self.model).id, object_id, obj_display, DELETION)
|
||||||
|
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
|
||||||
|
return HttpResponseRedirect("../../")
|
||||||
|
extra_context = {
|
||||||
|
"title": _("Are you sure?"),
|
||||||
|
"object_name": opts.verbose_name,
|
||||||
|
"object": obj,
|
||||||
|
"deleted_objects": deleted_objects,
|
||||||
|
"perms_lacking": perms_needed,
|
||||||
|
"opts": opts,
|
||||||
|
}
|
||||||
|
return render_to_response(["admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower() ),
|
||||||
|
"admin/%s/delete_confirmation.html" % app_label ,
|
||||||
|
"admin/delete_confirmation.html"], extra_context, context_instance=template.RequestContext(request))
|
||||||
|
|
||||||
|
def history_view(self, request, object_id):
|
||||||
|
"The 'history' admin view for this model."
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.admin.models import LogEntry
|
||||||
|
model = self.model
|
||||||
|
opts = model._meta
|
||||||
|
action_list = LogEntry.objects.filter(object_id=object_id,
|
||||||
|
content_type__id__exact=ContentType.objects.get_for_model(model).id).select_related().order_by('action_time')
|
||||||
|
# If no history was found, see whether this object even exists.
|
||||||
|
obj = get_object_or_404(model, pk=object_id)
|
||||||
|
extra_context = {
|
||||||
|
'title': _('Change history: %s') % obj,
|
||||||
|
'action_list': action_list,
|
||||||
|
'module_name': capfirst(opts.verbose_name_plural),
|
||||||
|
'object': obj,
|
||||||
|
}
|
||||||
|
template_list = [
|
||||||
|
"admin/%s/%s/object_history.html" % (opts.app_label, opts.object_name.lower()),
|
||||||
|
"admin/%s/object_history.html" % opts.app_label,
|
||||||
|
"admin/object_history.html"
|
||||||
|
]
|
||||||
|
return render_to_response(template_list, extra_context, context_instance=template.RequestContext(request))
|
@ -1,26 +1,18 @@
|
|||||||
from django import oldforms, template
|
from django import template
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.admin.filterspecs import FilterSpec
|
from django.contrib.admin.filterspecs import FilterSpec
|
||||||
|
from django.contrib.admin.options import ModelAdmin, IncorrectLookupParameters
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.paginator import ObjectPaginator, InvalidPage
|
from django.core.paginator import ObjectPaginator, InvalidPage
|
||||||
from django.shortcuts import get_object_or_404, render_to_response
|
from django.shortcuts import get_object_or_404, render_to_response
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.query import handle_legacy_orderlist, QuerySet
|
from django.db.models.query import handle_legacy_orderlist, QuerySet
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
from django.http import Http404
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.text import capfirst, get_text_list
|
from django.utils.text import capfirst
|
||||||
import operator
|
import operator
|
||||||
import sets
|
|
||||||
|
|
||||||
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
|
|
||||||
if not LogEntry._meta.installed:
|
|
||||||
raise ImproperlyConfigured, "You'll need to put 'django.contrib.admin' in your INSTALLED_APPS setting before you can use the admin application."
|
|
||||||
|
|
||||||
if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
|
|
||||||
raise ImproperlyConfigured, "You'll need to put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting before you can use the admin application."
|
|
||||||
|
|
||||||
# The system will display a "Show all" link on the change list only if the
|
# The system will display a "Show all" link on the change list only if the
|
||||||
# total result count is less than or equal to this setting.
|
# total result count is less than or equal to this setting.
|
||||||
@ -40,9 +32,6 @@ EMPTY_CHANGELIST_VALUE = '(None)'
|
|||||||
|
|
||||||
use_raw_id_admin = lambda field: isinstance(field.rel, (models.ManyToOneRel, models.ManyToManyRel)) and field.rel.raw_id_admin
|
use_raw_id_admin = lambda field: isinstance(field.rel, (models.ManyToOneRel, models.ManyToManyRel)) and field.rel.raw_id_admin
|
||||||
|
|
||||||
class IncorrectLookupParameters(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def quote(s):
|
def quote(s):
|
||||||
"""
|
"""
|
||||||
Ensure that primary key values do not confuse the admin URLs by escaping
|
Ensure that primary key values do not confuse the admin URLs by escaping
|
||||||
@ -59,26 +48,6 @@ def quote(s):
|
|||||||
res[i] = '_%02X' % ord(c)
|
res[i] = '_%02X' % ord(c)
|
||||||
return ''.join(res)
|
return ''.join(res)
|
||||||
|
|
||||||
def unquote(s):
|
|
||||||
"""
|
|
||||||
Undo the effects of quote(). Based heavily on urllib.unquote().
|
|
||||||
"""
|
|
||||||
mychr = chr
|
|
||||||
myatoi = int
|
|
||||||
list = s.split('_')
|
|
||||||
res = [list[0]]
|
|
||||||
myappend = res.append
|
|
||||||
del list[0]
|
|
||||||
for item in list:
|
|
||||||
if item[1:2]:
|
|
||||||
try:
|
|
||||||
myappend(mychr(myatoi(item[:2], 16)) + item[2:])
|
|
||||||
except ValueError:
|
|
||||||
myappend('_' + item)
|
|
||||||
else:
|
|
||||||
myappend('_' + item)
|
|
||||||
return "".join(res)
|
|
||||||
|
|
||||||
def get_javascript_imports(opts, auto_populated_fields, field_sets):
|
def get_javascript_imports(opts, auto_populated_fields, field_sets):
|
||||||
# Put in any necessary JavaScript imports.
|
# Put in any necessary JavaScript imports.
|
||||||
js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
|
js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
|
||||||
@ -112,301 +81,10 @@ def model_admin_view(request, app_label, model_name, rest_of_url):
|
|||||||
raise Http404("App %r, model %r, not found" % (app_label, model_name))
|
raise Http404("App %r, model %r, not found" % (app_label, model_name))
|
||||||
if not model._meta.admin:
|
if not model._meta.admin:
|
||||||
raise Http404("This object has no admin interface.")
|
raise Http404("This object has no admin interface.")
|
||||||
mav = ModelAdminView(model)
|
mav = ModelAdmin(model)
|
||||||
return mav(request, rest_of_url)
|
return mav(request, rest_of_url)
|
||||||
model_admin_view = staff_member_required(never_cache(model_admin_view))
|
model_admin_view = staff_member_required(never_cache(model_admin_view))
|
||||||
|
|
||||||
class ModelAdminView(object):
|
|
||||||
"Class that encapsulates all admin views for a given model."
|
|
||||||
def __init__(self, model):
|
|
||||||
self.model = model
|
|
||||||
self.opts = model._meta
|
|
||||||
|
|
||||||
def __call__(self, request, url):
|
|
||||||
if url is None:
|
|
||||||
return self.change_list_view(request)
|
|
||||||
elif url.endswith('add'):
|
|
||||||
return self.add_view(request)
|
|
||||||
elif url.endswith('history'):
|
|
||||||
return self.history_view(request, unquote(url[:-8]))
|
|
||||||
elif url.endswith('delete'):
|
|
||||||
return self.delete_view(request, unquote(url[:-7]))
|
|
||||||
else:
|
|
||||||
return self.change_view(request, unquote(url))
|
|
||||||
|
|
||||||
def has_add_permission(self, request):
|
|
||||||
"Returns True if the given request has permission to add an object."
|
|
||||||
opts = self.opts
|
|
||||||
return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
|
|
||||||
|
|
||||||
def has_change_permission(self, request, object_id):
|
|
||||||
"""
|
|
||||||
Returns True if the given request has permission to change the object
|
|
||||||
with the given object_id.
|
|
||||||
"""
|
|
||||||
opts = self.opts
|
|
||||||
return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
|
|
||||||
|
|
||||||
def has_delete_permission(self, request, object_id):
|
|
||||||
"""
|
|
||||||
Returns True if the given request has permission to change the object
|
|
||||||
with the given object_id.
|
|
||||||
"""
|
|
||||||
opts = self.opts
|
|
||||||
return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())
|
|
||||||
|
|
||||||
def add_view(self, request, show_delete=False, form_url='', post_url=None, post_url_continue='../%s/', object_id_override=None):
|
|
||||||
"The 'add' admin view for this model."
|
|
||||||
model = self.model
|
|
||||||
opts = model._meta
|
|
||||||
app_label = opts.app_label
|
|
||||||
|
|
||||||
if not self.has_add_permission(request):
|
|
||||||
raise PermissionDenied
|
|
||||||
|
|
||||||
if post_url is None:
|
|
||||||
if self.has_change_permission(request, None):
|
|
||||||
# redirect to list view
|
|
||||||
post_url = '../'
|
|
||||||
else:
|
|
||||||
# Object list will give 'Permission Denied', so go back to admin home
|
|
||||||
post_url = '../../../'
|
|
||||||
|
|
||||||
manipulator = model.AddManipulator()
|
|
||||||
if request.POST:
|
|
||||||
new_data = request.POST.copy()
|
|
||||||
|
|
||||||
if opts.has_field_type(models.FileField):
|
|
||||||
new_data.update(request.FILES)
|
|
||||||
|
|
||||||
errors = manipulator.get_validation_errors(new_data)
|
|
||||||
manipulator.do_html2python(new_data)
|
|
||||||
|
|
||||||
if not errors:
|
|
||||||
new_object = manipulator.save(new_data)
|
|
||||||
pk_value = new_object._get_pk_val()
|
|
||||||
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION)
|
|
||||||
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
|
||||||
# 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.message_set.create(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"):
|
|
||||||
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
|
|
||||||
pk_value = '"%s"' % pk_value.replace('"', '\\"')
|
|
||||||
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
|
|
||||||
(pk_value, str(new_object).replace('"', '\\"')))
|
|
||||||
elif request.POST.has_key("_addanother"):
|
|
||||||
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
|
||||||
return HttpResponseRedirect(request.path)
|
|
||||||
else:
|
|
||||||
request.user.message_set.create(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 = oldforms.FormWrapper(manipulator, new_data, errors)
|
|
||||||
|
|
||||||
c = template.RequestContext(request, {
|
|
||||||
'title': _('Add %s') % opts.verbose_name,
|
|
||||||
'form': form,
|
|
||||||
'is_popup': request.REQUEST.has_key('_popup'),
|
|
||||||
'show_delete': show_delete,
|
|
||||||
})
|
|
||||||
|
|
||||||
if object_id_override is not None:
|
|
||||||
c['object_id'] = object_id_override
|
|
||||||
|
|
||||||
return render_change_form(model, manipulator, c, add=True)
|
|
||||||
|
|
||||||
def change_view(self, request, object_id):
|
|
||||||
"The 'change' admin view for this model."
|
|
||||||
model = self.model
|
|
||||||
opts = model._meta
|
|
||||||
app_label = opts.app_label
|
|
||||||
|
|
||||||
if not self.has_change_permission(request, object_id):
|
|
||||||
raise PermissionDenied
|
|
||||||
|
|
||||||
if request.POST and request.POST.has_key("_saveasnew"):
|
|
||||||
return self.add_view(request, form_url='../../add/')
|
|
||||||
|
|
||||||
try:
|
|
||||||
manipulator = model.ChangeManipulator(object_id)
|
|
||||||
except model.DoesNotExist:
|
|
||||||
raise Http404('%s object with primary key %r does not exist' % (model_name, escape(object_id)))
|
|
||||||
|
|
||||||
if request.POST:
|
|
||||||
new_data = request.POST.copy()
|
|
||||||
|
|
||||||
if opts.has_field_type(models.FileField):
|
|
||||||
new_data.update(request.FILES)
|
|
||||||
|
|
||||||
errors = manipulator.get_validation_errors(new_data)
|
|
||||||
manipulator.do_html2python(new_data)
|
|
||||||
|
|
||||||
if not errors:
|
|
||||||
new_object = manipulator.save(new_data)
|
|
||||||
pk_value = new_object._get_pk_val()
|
|
||||||
|
|
||||||
# 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(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message)
|
|
||||||
|
|
||||||
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
|
|
||||||
if request.POST.has_key("_continue"):
|
|
||||||
request.user.message_set.create(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.message_set.create(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.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
|
|
||||||
return HttpResponseRedirect("../add/")
|
|
||||||
else:
|
|
||||||
request.user.message_set.create(message=msg)
|
|
||||||
return HttpResponseRedirect("../")
|
|
||||||
else:
|
|
||||||
# Populate new_data with a "flattened" version of the current data.
|
|
||||||
new_data = manipulator.flatten_data()
|
|
||||||
|
|
||||||
# TODO: do this in flatten_data...
|
|
||||||
# If the object has ordered objects on its admin page, get the existing
|
|
||||||
# order and flatten it into a comma-separated list of IDs.
|
|
||||||
id_order_list = []
|
|
||||||
for rel_obj in opts.get_ordered_objects():
|
|
||||||
id_order_list.extend(getattr(manipulator.original_object, 'get_%s_order' % rel_obj.object_name.lower())())
|
|
||||||
if id_order_list:
|
|
||||||
new_data['order_'] = ','.join(map(str, id_order_list))
|
|
||||||
errors = {}
|
|
||||||
|
|
||||||
# Populate the FormWrapper.
|
|
||||||
form = oldforms.FormWrapper(manipulator, new_data, errors)
|
|
||||||
form.original = manipulator.original_object
|
|
||||||
form.order_objects = []
|
|
||||||
|
|
||||||
# TODO: Should be done in flatten_data / FormWrapper construction
|
|
||||||
for related in opts.get_followed_related_objects():
|
|
||||||
wrt = related.opts.order_with_respect_to
|
|
||||||
if wrt and wrt.rel and wrt.rel.to == opts:
|
|
||||||
func = getattr(manipulator.original_object, 'get_%s_list' %
|
|
||||||
related.get_accessor_name())
|
|
||||||
orig_list = func()
|
|
||||||
form.order_objects.extend(orig_list)
|
|
||||||
|
|
||||||
c = template.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'),
|
|
||||||
})
|
|
||||||
return render_change_form(model, manipulator, c, change=True)
|
|
||||||
|
|
||||||
def change_list_view(self, request):
|
|
||||||
"The 'change list' admin view for this model."
|
|
||||||
opts = self.model._meta
|
|
||||||
app_label = opts.app_label
|
|
||||||
if not self.has_change_permission(request, None):
|
|
||||||
raise PermissionDenied
|
|
||||||
try:
|
|
||||||
cl = ChangeList(request, self.model)
|
|
||||||
except IncorrectLookupParameters:
|
|
||||||
# Wacky lookup parameters were given, so redirect to the main
|
|
||||||
# changelist page, without parameters, and pass an 'invalid=1'
|
|
||||||
# parameter via the query string. If wacky parameters were given and
|
|
||||||
# the 'invalid=1' parameter was already in the query string, something
|
|
||||||
# is screwed up with the database, so display an error page.
|
|
||||||
if ERROR_FLAG in request.GET.keys():
|
|
||||||
return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
|
|
||||||
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
|
|
||||||
c = template.RequestContext(request, {
|
|
||||||
'title': cl.title,
|
|
||||||
'is_popup': cl.is_popup,
|
|
||||||
'cl': cl,
|
|
||||||
})
|
|
||||||
c.update({'has_add_permission': c['perms'][app_label][opts.get_add_permission()]}),
|
|
||||||
return render_to_response(['admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
|
|
||||||
'admin/%s/change_list.html' % app_label,
|
|
||||||
'admin/change_list.html'], context_instance=c)
|
|
||||||
|
|
||||||
def delete_view(self, request, object_id):
|
|
||||||
"The 'delete' admin view for this model."
|
|
||||||
opts = self.model._meta
|
|
||||||
app_label = opts.app_label
|
|
||||||
if not self.has_delete_permission(request, object_id):
|
|
||||||
raise PermissionDenied
|
|
||||||
obj = get_object_or_404(self.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, ContentType.objects.get_for_model(self.model).id, object_id, obj_display, DELETION)
|
|
||||||
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
|
|
||||||
return HttpResponseRedirect("../../")
|
|
||||||
extra_context = {
|
|
||||||
"title": _("Are you sure?"),
|
|
||||||
"object_name": opts.verbose_name,
|
|
||||||
"object": obj,
|
|
||||||
"deleted_objects": deleted_objects,
|
|
||||||
"perms_lacking": perms_needed,
|
|
||||||
"opts": opts,
|
|
||||||
}
|
|
||||||
return render_to_response(["admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower() ),
|
|
||||||
"admin/%s/delete_confirmation.html" % app_label ,
|
|
||||||
"admin/delete_confirmation.html"], extra_context, context_instance=template.RequestContext(request))
|
|
||||||
|
|
||||||
def history_view(self, request, object_id):
|
|
||||||
"The 'history' admin view for this model."
|
|
||||||
model = self.model
|
|
||||||
opts = model._meta
|
|
||||||
action_list = LogEntry.objects.filter(object_id=object_id,
|
|
||||||
content_type__id__exact=ContentType.objects.get_for_model(model).id).select_related().order_by('action_time')
|
|
||||||
# If no history was found, see whether this object even exists.
|
|
||||||
obj = get_object_or_404(model, pk=object_id)
|
|
||||||
extra_context = {
|
|
||||||
'title': _('Change history: %s') % obj,
|
|
||||||
'action_list': action_list,
|
|
||||||
'module_name': capfirst(opts.verbose_name_plural),
|
|
||||||
'object': obj,
|
|
||||||
}
|
|
||||||
template_list = [
|
|
||||||
"admin/%s/%s/object_history.html" % (opts.app_label, opts.object_name.lower()),
|
|
||||||
"admin/%s/object_history.html" % opts.app_label,
|
|
||||||
"admin/object_history.html"
|
|
||||||
]
|
|
||||||
return render_to_response(template_list, extra_context, context_instance=template.RequestContext(request))
|
|
||||||
|
|
||||||
class AdminBoundField(object):
|
class AdminBoundField(object):
|
||||||
def __init__(self, field, field_mapping, original):
|
def __init__(self, field, field_mapping, original):
|
||||||
self.field = field
|
self.field = field
|
||||||
|
Loading…
x
Reference in New Issue
Block a user