1

我有许多从 扩展而来的模型feincms.models.Base,并在管理站点中使用 FeinCMS 项目编辑器(即它们都feincms.admin.item_editor.ItemEditor用作它们的ModelAdmin)。

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

问题是,这不能很好地与FeinCMS扩展一起使用,从而导致意外结果,例如重复选项卡,其中扩展将内容ModelAdmin多次添加到 s 中。

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

4

1 回答 1

1

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

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

  1. 首先,附加到ModelAdmin(eg SharedModelAdmin.list_display) 的任何列表或字典都通过引用传递,因此在多个 ModelAdmins 之间共享。这意味着扩展最终可以在同一个列表上执行两次操作(即使它附加到不同的ModelAdmin)。
  2. admin.py我们定义ModelAdmin级别的设置时,FeinCMS 操作 ModelAdmin 的实例

所以,为了让它工作,我们可以使用下面的 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']
于 2015-08-17T09:19:47.030 回答