如何在Django FeinCMS项目中继承我的ModelAdmins?

时间:2015-08-17 09:19:47

标签: python django django-admin feincms django-modeladmin

我有许多模型从feincms.models.Base延伸,并使用管理网站中的FeinCMS项目编辑器(即他们都使用feincms.admin.item_editor.ItemEditor作为ModelAdmin)。

模型有一些共享功能,我希望能够在共享的ModelAdmin类中定义,然后我可以为每个模型扩展。

问题是,这导致FeinCMS扩展无效 意外结果,例如重复标签,其中扩展程序不止一次向ModelAdmin添加内容。

有没有办法在不搞乱扩展的情况下做到这一点?

1 个答案:

答案 0 :(得分:1)

这是可能的,但您必须采用稍微不同的语法。首先,解释。

ModelAdmins的直接继承被破坏的原因是FeinCMS扩展操作ModelAdmin类的方式存在两个问题:

  1. 首先,附加到ModelAdmin的所有列表或词典(例如SharedModelAdmin.list_display)都通过引用传递,因此在多个ModelAdmin之间共享。这意味着扩展可以最终在同一个列表上执行两次操作(即使它附加到不同的ModelAdmin)。
  2. admin.py我们在级别定义ModelAdmin的设置时,FeinCMS会操纵ModelAdmin的实例
  3. 因此,为了使其正常工作,我们可以使用以下mixin:

    class Faked(object):
        "A fake class to use to stand in for True in ExtendableModelAdminMixin."
        pass
    
    
    class ExtendableModelAdminMixin(object):
        """ModelAdmin mixin to allow ModelAdmins to be extended (i.e.
    subclassed) without messing
        up the Feincms extension registering mechanism.
    
        Technical note: the reason we do this is because otherwise references
        get preserved across different ModelAdmins, which means the ModelAdmins
        fail Django's checks.
        The straightforward declarative syntax of ModelAdmins sets
        attributes at the class level, but FeinCMS's
        initialize_extensions() method overrides them on the
        instance level.  So in our mixin we do a deepcopy of any
        instance level attributes before initializing the extensions.
        """
        def __init__(self, *args, **kwargs):
            # Set the _extensions_initialized attribute to prevent
            # extensions being initialized just yet
            self._extensions_initialized = Faked
            super(ExtendableModelAdminMixin, self).__init__(*args, **kwargs)
    
            # Before running extensions, copy any lists so we don't
            # preserve references across different ModelAdmin subclasses
            # TODO - include any other ModelAdmin properties that
            # are causing issues.
            for attr_name in ('list_display',
                              'fieldsets',
                              'search_fields', 'list_filter'):
                original = getattr(self, attr_name, [])
                copied_attr = deepcopy(original)
                setattr(self, attr_name, copied_attr)
    
            # Now we're ready to initialize extensions
            del(self._extensions_initialized)
            self.initialize_extensions()
    

    用法:

    class SharedModelAdmin(ExtendableModelAdmin, ItemEditor):
        # Declare some defaults here, as usual
        list_display = ['field_one', 'field_two']
    
    class MyModelAdmin(SharedModelAdmin):
        def __init__(self, *args, **kwargs):
            super(MyModelAdmin, self).__init__(*args, **kwargs)
            # Override things at the instance level
            self.list_display += ['field_three']