class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: css = {} js = [] form = PageAdminForm # the fieldsets config here is used for the add_view, it has no effect # for the change_view which is completely customized anyway unknown_fields = ['template_key', 'parent', 'override_url', 'redirect_to'] fieldset_insertion_index = 2 fieldsets = [ (None, { 'fields': [ ('title', 'slug'), ('active', 'in_navigation'), ], }), (_('Other options'), { 'classes': ['collapse',], 'fields': unknown_fields, }), # <-- insertion point, extensions appear here, see insertion_index above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] list_display = ['short_title', 'is_visible_admin', 'in_navigation_toggle', 'template'] list_filter = ['active', 'in_navigation', 'template_key', 'parent'] search_fields = ['title', 'slug'] prepopulated_fields = { 'slug': ('title',), } raw_id_fields = ['parent'] radio_fields = {'template_key': admin.HORIZONTAL} @classmethod def add_extension_options(cls, *f): if isinstance(f[-1], dict): # called with a fieldset cls.fieldsets.insert(cls.fieldset_insertion_index, f) f[1]['classes'] = list(f[1].get('classes', [])) f[1]['classes'].append('collapse') else: # assume called with "other" fields cls.fieldsets[1][1]['fields'].extend(f) def __init__(self, *args, **kwargs): ensure_completely_loaded() if len(Page._feincms_templates) > 4 and 'template_key' in self.radio_fields: del(self.radio_fields['template_key']) super(PageAdmin, self).__init__(*args, **kwargs) # The use of fieldsets makes only fields explicitly listed in there # actually appear in the admin form. However, extensions should not be # aware that there is a fieldsets structure and even less modify it; # we therefore enumerate all of the model's field and forcibly add them # to the last section in the admin. That way, nobody is left behind. from django.contrib.admin.util import flatten_fieldsets present_fields = flatten_fieldsets(self.fieldsets) for f in self.model._meta.fields: if not f.name.startswith('_') and not f.name in ('id', 'lft', 'rght', 'tree_id', 'level') and \ not f.auto_created and not f.name in present_fields and f.editable: self.unknown_fields.append(f.name) if not f.editable: self.readonly_fields.append(f.name) in_navigation_toggle = tree_editor.ajax_editable_boolean('in_navigation', _('in navigation')) def _actions_column(self, page): editable = getattr(page, 'feincms_editable', True) preview_url = "../../r/%s/%s/" % ( ContentType.objects.get_for_model(self.model).id, page.id) actions = super(PageAdmin, self)._actions_column(page) if editable: actions.insert(0, u'<a href="add/?parent=%s" title="%s"><img src="%sfeincms/img/icon_addlink.gif" alt="%s"></a>' % ( page.pk, _('Add child page'), django_settings.STATIC_URL, _('Add child page'))) actions.insert(0, u'<a href="%s" title="%s"><img src="%sfeincms/img/selector-search.gif" alt="%s" /></a>' % ( preview_url, _('View on site'), django_settings.STATIC_URL, _('View on site'))) return actions def add_view(self, request, **kwargs): # Preserve GET parameters kwargs['form_url'] = request.get_full_path() return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) if 'parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302): # Preserve GET parameters if we are about to add another page response['Location'] += '?parent=%s' % request.GET['parent'] if 'translation_of' in request.GET: # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): # Short-circuit processing -- don't copy any contents if # newly added object already has some return response try: original = self.model._tree_manager.get(pk=request.GET.get('translation_of')) original = original.original_translation obj.copy_content_from(original) obj.save() self.message_user(request, _('The content from the original translation has been copied to the newly created page.')) except (AttributeError, self.model.DoesNotExist): pass return response def _refresh_changelist_caches(self, *args, **kwargs): self._visible_pages = list(self.model.objects.active().values_list('id', flat=True)) def change_view(self, request, object_id, **kwargs): try: return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: from django.contrib import messages messages.add_message(request, messages.ERROR, _("You don't have the necessary permissions to edit this object")) return HttpResponseRedirect(reverse('admin:page_page_changelist')) def is_visible_admin(self, page): """ Instead of just showing an on/off boolean, also indicate whether this page is not visible because of publishing dates or inherited status. """ if not hasattr(self, "_visible_pages"): self._visible_pages = list() # Sanity check in case this is not already defined if page.parent_id and not page.parent_id in self._visible_pages: # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) if page.active and not page.id in self._visible_pages: # is active but should not be shown, so visibility limited by extension: show a "not active" return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) return tree_editor.ajax_editable_boolean_cell(page, 'active') is_visible_admin.allow_tags = True is_visible_admin.short_description = _('is active') is_visible_admin.editable_boolean_field = 'active' # active toggle needs more sophisticated result function def is_visible_recursive(self, page): retval = [] for c in page.get_descendants(include_self=True): retval.append(self.is_visible_admin(c)) return retval is_visible_admin.editable_boolean_result = is_visible_recursive
class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: css = {} js = [] form = PageAdminForm fieldset_insertion_index = 2 fieldsets = [ (None, { "fields": [("title", "slug"), ("active", "in_navigation")] }), ( _("Other options"), { "classes": ["collapse"], "fields": ["template_key", "parent", "override_url", "redirect_to"], }, ), # <-- insertion point, extensions appear here, see insertion_index # above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] list_display = [ "short_title", "is_visible_admin", "in_navigation_toggle", "template", ] list_filter = ["active", "in_navigation", "template_key", "parent"] search_fields = ["title", "slug"] prepopulated_fields = {"slug": ("title", )} raw_id_fields = ["parent"] radio_fields = {"template_key": admin.HORIZONTAL} @classmethod def add_extension_options(cls, *f): if isinstance(f[-1], dict): # called with a fieldset cls.fieldsets.insert(cls.fieldset_insertion_index, f) f[1]["classes"] = list(f[1].get("classes", [])) f[1]["classes"].append("collapse") else: # assume called with "other" fields cls.fieldsets[1][1]["fields"].extend(f) def __init__(self, model, admin_site): ensure_completely_loaded() if len(model._feincms_templates ) > 4 and "template_key" in self.radio_fields: del self.radio_fields["template_key"] super(PageAdmin, self).__init__(model, admin_site) in_navigation_toggle = tree_editor.ajax_editable_boolean( "in_navigation", _("in navigation")) def get_readonly_fields(self, request, obj=None): readonly = super(PageAdmin, self).get_readonly_fields(request, obj=obj) if (not settings.FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED and obj and obj.template and obj.template.singleton): return tuple(readonly) + ("template_key", ) return readonly def get_form(self, *args, **kwargs): form = super(PageAdmin, self).get_form(*args, **kwargs) return partial(form, modeladmin=self) def _actions_column(self, page): addable = getattr(page, "feincms_addable", True) preview_url = "../../r/%s/%s/" % ( ContentType.objects.get_for_model(self.model).id, page.id, ) actions = super(PageAdmin, self)._actions_column(page) if addable and not page.template.enforce_leaf: actions.insert( 0, '<a href="add/?parent=%s" title="%s">' '<img src="%s" alt="%s" />' "</a>" % ( page.pk, _("Add child page"), static("feincms/img/icon_addlink.gif"), _("Add child page"), ), ) actions.insert( 0, '<a href="%s" title="%s">' '<img src="%s" alt="%s" />' "</a>" % ( preview_url, _("View on site"), static("feincms/img/selector-search.gif"), _("View on site"), ), ) return actions def add_view(self, request, **kwargs): kwargs["form_url"] = request.get_full_path() # Preserve GET parameters if "translation_of" in request.GET and "language" in request.GET: try: original = self.model._tree_manager.get( pk=request.GET.get("translation_of")) except (AttributeError, self.model.DoesNotExist): pass else: language_code = request.GET["language"] language = dict(django_settings.LANGUAGES).get( language_code, "") kwargs["extra_context"] = { "adding_translation": True, "title": _('Add %(language)s translation of "%(page)s"') % { "language": language, "page": original }, "language_name": language, "translation_of": original, } return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) if ("parent" in request.GET and "_addanother" in request.POST and response.status_code in (301, 302)): # Preserve GET parameters if we are about to add another page response["Location"] += "?parent=%s" % request.GET["parent"] if ("translation_of" in request.GET and "_copy_content_from_original" in request.POST): # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): # Short-circuit processing -- don't copy any contents if # newly added object already has some return response try: original = self.model._tree_manager.get( pk=request.GET.get("translation_of")) original = original.original_translation obj.copy_content_from(original) obj.save() self.message_user( request, _("The content from the original translation has been copied" " to the newly created page."), ) except (AttributeError, self.model.DoesNotExist): pass return response def change_view(self, request, object_id, **kwargs): try: return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: messages.add_message( request, messages.ERROR, _("You don't have the necessary permissions to edit this" " object"), ) return HttpResponseRedirect(reverse("admin:page_page_changelist")) def has_delete_permission(self, request, obj=None): if (not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED and obj and obj.template.singleton): return False return super(PageAdmin, self).has_delete_permission(request, obj=obj) def changelist_view(self, request, *args, **kwargs): _local.visible_pages = list(self.model.objects.active().values_list( "id", flat=True)) return super(PageAdmin, self).changelist_view(request, *args, **kwargs) def is_visible_admin(self, page): """ Instead of just showing an on/off boolean, also indicate whether this page is not visible because of publishing dates or inherited status. """ if page.parent_id and page.parent_id not in _local.visible_pages: # parent page's invisibility is inherited if page.id in _local.visible_pages: _local.visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell(page, "active", override=False, text=_("inherited")) if page.active and page.id not in _local.visible_pages: # is active but should not be shown, so visibility limited by # extension: show a "not active" return tree_editor.ajax_editable_boolean_cell(page, "active", override=False, text=_("extensions")) return tree_editor.ajax_editable_boolean_cell(page, "active") is_visible_admin.short_description = _("is active") is_visible_admin.editable_boolean_field = "active" # active toggle needs more sophisticated result function def is_visible_recursive(self, page): # Have to refresh visible_pages here, because TreeEditor.toggle_boolean # will have changed the value when inside this code path. _local.visible_pages = list(self.model.objects.active().values_list( "id", flat=True)) return [ self.is_visible_admin(c) for c in page.get_descendants(include_self=True) ] is_visible_admin.editable_boolean_result = is_visible_recursive
def handle_modeladmin(self, modeladmin): setattr(type(modeladmin), 'in_footer_toggle', tree_editor.ajax_editable_boolean('in_footer', _('in footer'))) modeladmin.list_display.insert(3, 'in_footer_toggle')
def register(cls, admin_cls): cls.add_to_class('in_footer', models.BooleanField(_('In footer'), default=False, help_text=_('This displays the page in the footer navigation.'))) setattr(admin_cls, 'in_footer_toggle', tree_editor.ajax_editable_boolean('in_footer', _('in footer'))) admin_cls.list_display.insert(3, 'in_footer_toggle')
from feincms.module.page.admin import PageAdmin from feincms.module.page.models import Page from guardian.admin import GuardedModelAdmin from django.utils.translation import ugettext_lazy as _ from django.contrib import admin PageAdmin.__bases__ = (GuardedModelAdmin,) + PageAdmin.__bases__ PageAdmin.fieldsets[0][1]["fields"][1] += ( "require_login","require_permission", "only_public") PageAdmin.change_form_template = "admin/page_editor.html" from feincms.admin import tree_editor PageAdmin.list_display[3:0] = ["require_login_toggle", "only_public_toggle"] PageAdmin.list_filter.insert(2, "require_login") PageAdmin.require_login_toggle = tree_editor.ajax_editable_boolean('require_login', _('require login')) PageAdmin.only_public_toggle = tree_editor.ajax_editable_boolean('only_public', _('only public')) admin.site.unregister(Page) admin.site.register(Page, PageAdmin)
class PageAdmin(item_editor.ItemEditor, tree_editor.TreeEditor): class Media: css = {} js = [] form = PageAdminForm fieldset_insertion_index = 2 fieldsets = [ (None, { 'fields': [ ('title', 'slug'), ('active', 'in_navigation'), ], }), (_('Other options'), { 'classes': ['collapse'], 'fields': ['template_key', 'parent', 'override_url', 'redirect_to'], }), # <-- insertion point, extensions appear here, see insertion_index # above item_editor.FEINCMS_CONTENT_FIELDSET, ] readonly_fields = [] list_display = [ 'short_title', 'is_visible_admin', 'in_navigation_toggle', 'template' ] list_filter = ['active', 'in_navigation', 'template_key', 'parent'] search_fields = ['title', 'slug'] prepopulated_fields = {'slug': ('title', )} raw_id_fields = ['parent'] radio_fields = {'template_key': admin.HORIZONTAL} @classmethod def add_extension_options(cls, *f): if isinstance(f[-1], dict): # called with a fieldset cls.fieldsets.insert(cls.fieldset_insertion_index, f) f[1]['classes'] = list(f[1].get('classes', [])) f[1]['classes'].append('collapse') else: # assume called with "other" fields cls.fieldsets[1][1]['fields'].extend(f) def __init__(self, model, admin_site): ensure_completely_loaded() if len(model._feincms_templates) > 4 and \ 'template_key' in self.radio_fields: del (self.radio_fields['template_key']) super(PageAdmin, self).__init__(model, admin_site) in_navigation_toggle = tree_editor.ajax_editable_boolean( 'in_navigation', _('in navigation')) def get_readonly_fields(self, request, obj=None): readonly = super(PageAdmin, self).get_readonly_fields(request, obj=obj) if not settings.FEINCMS_SINGLETON_TEMPLATE_CHANGE_ALLOWED: if obj and obj.template and obj.template.singleton: return tuple(readonly) + ('template_key', ) return readonly def get_form(self, *args, **kwargs): form = super(PageAdmin, self).get_form(*args, **kwargs) return curry(form, modeladmin=self) def _actions_column(self, page): addable = getattr(page, 'feincms_addable', True) preview_url = "../../r/%s/%s/" % (ContentType.objects.get_for_model( self.model).id, page.id) actions = super(PageAdmin, self)._actions_column(page) if addable: if not page.template.enforce_leaf: actions.insert( 0, '<a href="add/?parent=%s" title="%s">' '<img src="%s" alt="%s" />' '</a>' % ( page.pk, _('Add child page'), static('feincms/img/icon_addlink.gif'), _('Add child page'), )) actions.insert( 0, '<a href="%s" title="%s">' '<img src="%s" alt="%s" />' '</a>' % ( preview_url, _('View on site'), static('feincms/img/selector-search.gif'), _('View on site'), )) return actions def add_view(self, request, **kwargs): kwargs['form_url'] = request.get_full_path() # Preserve GET parameters if 'translation_of' in request.GET and 'language' in request.GET: try: original = self.model._tree_manager.get( pk=request.GET.get('translation_of')) except (AttributeError, self.model.DoesNotExist): pass else: language_code = request.GET['language'] language = dict(django_settings.LANGUAGES).get( language_code, '') kwargs['extra_context'] = { 'adding_translation': True, 'title': _('Add %(language)s translation of "%(page)s"') % { 'language': language, 'page': original, }, 'language_name': language, 'translation_of': original, } return super(PageAdmin, self).add_view(request, **kwargs) def response_add(self, request, obj, *args, **kwargs): response = super(PageAdmin, self).response_add(request, obj, *args, **kwargs) if ('parent' in request.GET and '_addanother' in request.POST and response.status_code in (301, 302)): # Preserve GET parameters if we are about to add another page response['Location'] += '?parent=%s' % request.GET['parent'] if ('translation_of' in request.GET and '_copy_content_from_original' in request.POST): # Copy all contents for content_type in obj._feincms_content_types: if content_type.objects.filter(parent=obj).exists(): # Short-circuit processing -- don't copy any contents if # newly added object already has some return response try: original = self.model._tree_manager.get( pk=request.GET.get('translation_of')) original = original.original_translation obj.copy_content_from(original) obj.save() self.message_user( request, _('The content from the original translation has been copied' ' to the newly created page.')) except (AttributeError, self.model.DoesNotExist): pass return response def _refresh_changelist_caches(self, *args, **kwargs): self._visible_pages = list(self.model.objects.active().values_list( 'id', flat=True)) def change_view(self, request, object_id, **kwargs): try: return super(PageAdmin, self).change_view(request, object_id, **kwargs) except PermissionDenied: messages.add_message( request, messages.ERROR, _("You don't have the necessary permissions to edit this" " object")) return HttpResponseRedirect(reverse('admin:page_page_changelist')) def has_delete_permission(self, request, obj=None): if not settings.FEINCMS_SINGLETON_TEMPLATE_DELETION_ALLOWED: if obj and obj.template.singleton: return False return super(PageAdmin, self).has_delete_permission(request, obj=obj) def is_visible_admin(self, page): """ Instead of just showing an on/off boolean, also indicate whether this page is not visible because of publishing dates or inherited status. """ if not hasattr(self, "_visible_pages"): # Sanity check in case this is not already defined self._visible_pages = list() if page.parent_id and page.parent_id not in self._visible_pages: # parent page's invisibility is inherited if page.id in self._visible_pages: self._visible_pages.remove(page.id) return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('inherited')) if page.active and page.id not in self._visible_pages: # is active but should not be shown, so visibility limited by # extension: show a "not active" return tree_editor.ajax_editable_boolean_cell(page, 'active', override=False, text=_('extensions')) return tree_editor.ajax_editable_boolean_cell(page, 'active') is_visible_admin.allow_tags = True is_visible_admin.short_description = _('is active') is_visible_admin.editable_boolean_field = 'active' # active toggle needs more sophisticated result function def is_visible_recursive(self, page): retval = [] for c in page.get_descendants(include_self=True): retval.append(self.is_visible_admin(c)) return retval is_visible_admin.editable_boolean_result = is_visible_recursive