diff options
author | substantialnoninfringinguser <substantialnoninfringinguser@gmail.com> | 2009-05-21 19:47:19 +0100 |
---|---|---|
committer | substantialnoninfringinguser <substantialnoninfringinguser@gmail.com> | 2009-05-21 19:47:19 +0100 |
commit | 54a62999c03f5293b42d56f9a99b1c5a3b02fa5f (patch) | |
tree | 8221aee4d3e16f1373c3162cd7c44eebb273345a /feincms/admin/editor.py | |
parent | 99949d466a0bf2667bad10f8c6c2c751036fd858 (diff) | |
download | troggle-54a62999c03f5293b42d56f9a99b1c5a3b02fa5f.tar.gz troggle-54a62999c03f5293b42d56f9a99b1c5a3b02fa5f.tar.bz2 troggle-54a62999c03f5293b42d56f9a99b1c5a3b02fa5f.zip |
[svn] Updates to allow subcave tree with nice admin.
Diffstat (limited to 'feincms/admin/editor.py')
-rw-r--r-- | feincms/admin/editor.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/feincms/admin/editor.py b/feincms/admin/editor.py new file mode 100644 index 0000000..c5c688b --- /dev/null +++ b/feincms/admin/editor.py @@ -0,0 +1,183 @@ +import re + +from django import forms, template +from django.conf import settings +from django.contrib import admin +from django.contrib.admin.options import IncorrectLookupParameters +from django.contrib.admin.util import unquote +from django.core import serializers +from django.core.exceptions import ImproperlyConfigured +from django.db import connection, transaction +from django.forms.formsets import all_valid +from django.forms.models import inlineformset_factory +from django.http import HttpResponseRedirect, HttpResponse +from django.shortcuts import render_to_response +from django.utils import simplejson +from django.utils.encoding import force_unicode +from django.utils.functional import update_wrapper +from django.utils.translation import ugettext_lazy as _ + + + +FEINCMS_ADMIN_MEDIA = getattr(settings, 'FEINCMS_ADMIN_MEDIA', '/media/sys/feincms/') + + +class ItemEditorMixin(object): + """ + This mixin needs an attribute on the ModelAdmin class: + + show_on_top:: + A list of fields which should be displayed at the top of the form. + This does not need to (and should not) include ``template'' + """ + + def change_view(self, request, object_id, extra_context=None): + + if not hasattr(self.model, '_feincms_content_types'): + raise ImproperlyConfigured, 'You need to create at least one content type for the %s model.' % (self.model.__name__) + + class ModelForm(forms.ModelForm): + class Meta: + model = self.model + + class SettingsFieldset(forms.ModelForm): + # This form class is used solely for presentation, the data will be saved + # by the ModelForm above + + class Meta: + model = self.model + exclude = self.show_on_top+('template',) + + inline_formset_types = [( + content_type, + inlineformset_factory(self.model, content_type, extra=1) + ) for content_type in self.model._feincms_content_types] + + opts = self.model._meta + app_label = opts.app_label + obj = self.model._default_manager.get(pk=unquote(object_id)) + + if not self.has_change_permission(request, obj): + raise PermissionDenied + + if request.method == 'POST': + model_form = ModelForm(request.POST, request.FILES, instance=obj) + + inline_formsets = [ + formset_class(request.POST, request.FILES, instance=obj, + prefix=content_type.__name__.lower()) + for content_type, formset_class in inline_formset_types] + + if model_form.is_valid() and all_valid(inline_formsets): + model_form.save() + for formset in inline_formsets: + formset.save() + return HttpResponseRedirect(".") + + settings_fieldset = SettingsFieldset(request.POST, instance=obj) + settings_fieldset.is_valid() + else: + model_form = ModelForm(instance=obj) + inline_formsets = [ + formset_class(instance=obj, prefix=content_type.__name__.lower()) + for content_type, formset_class in inline_formset_types] + + settings_fieldset = SettingsFieldset(instance=obj) + + content_types = [] + for content_type in self.model._feincms_content_types: + content_name = content_type._meta.verbose_name + content_types.append((content_name, content_type.__name__.lower())) + + context = { + 'title': _('Change %s') % force_unicode(opts.verbose_name), + 'opts': opts, + 'page': obj, + 'page_form': model_form, + 'inline_formsets': inline_formsets, + 'content_types': content_types, + 'settings_fieldset': settings_fieldset, + 'top_fieldset': [model_form[field] for field in self.show_on_top], + 'FEINCMS_ADMIN_MEDIA': FEINCMS_ADMIN_MEDIA, + } + + return render_to_response([ + 'admin/feincms/%s/%s/item_editor.html' % (app_label, opts.object_name.lower()), + 'admin/feincms/%s/item_editor.html' % app_label, + 'admin/feincms/item_editor.html', + ], context, context_instance=template.RequestContext(request)) + + +class TreeEditorMixin(object): + def changelist_view(self, request, extra_context=None): + # handle AJAX requests + if request.is_ajax(): + cmd = request.POST.get('__cmd') + if cmd=='save_tree': + return self._save_tree(request) + elif cmd=='delete_item': + return self._delete_item(request) + + return HttpResponse('Oops. AJAX request not understood.') + + 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, self.list_display, + self.list_display_links, self.list_filter, self.date_hierarchy, + self.search_fields, self.list_select_related, self.list_per_page, + self.list_editable, self) + 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') + + context = { + 'FEINCMS_ADMIN_MEDIA': FEINCMS_ADMIN_MEDIA, + 'title': cl.title, + 'is_popup': cl.is_popup, + 'cl': cl, + 'has_add_permission': self.has_add_permission(request), + 'root_path': self.admin_site.root_path, + 'app_label': app_label, + 'object_list': self.model._tree_manager.all(), + } + context.update(extra_context or {}) + return render_to_response([ + 'admin/feincms/%s/%s/tree_editor.html' % (app_label, opts.object_name.lower()), + 'admin/feincms/%s/tree_editor.html' % app_label, + 'admin/feincms/tree_editor.html', + ], context, context_instance=template.RequestContext(request)) + + def _save_tree(self, request): + pagetree = simplejson.loads(request.POST['tree']) + # 0 = tree_id, 1 = parent_id, 2 = left, 3 = right, 4 = level, 5 = item_id + sql = "UPDATE %s SET %s=%%s, %s_id=%%s, %s=%%s, %s=%%s, %s=%%s WHERE %s=%%s" % ( + self.model._meta.db_table, + self.model._meta.tree_id_attr, + self.model._meta.parent_attr, + self.model._meta.left_attr, + self.model._meta.right_attr, + self.model._meta.level_attr, + self.model._meta.pk.column) + + connection.cursor().executemany(sql, pagetree) + transaction.commit_unless_managed() + + return HttpResponse("OK", mimetype="text/plain") + + def _delete_item(self, request): + page_id = request.POST['item_id'] + obj = self.model._default_manager.get(pk=unquote(page_id)) + obj.delete() + return HttpResponse("OK", mimetype="text/plain") + |