【问题标题】:In django-admin, how can I set filter_horizontal as the default?在 django-admin 中,如何将 filter_horizo​​ntal 设置为默认值?
【发布时间】:2012-01-31 14:24:12
【问题描述】:

django-admin 中ManyToManyFields 的默认小部件很难使用。我可以在各个字段上设置filter_horizontal 并获得更好的小部件。

如何将filter_horizontal 设置为所有ManyToManyFields 的默认值?

(当然,我也会对filter_vertical 感到满意。)

我四处寻找解决方案,但在 Google 或 SO 上没有找到任何东西。我可以考虑如何通过一些元编程来做到这一点,但如果有人已经这样做了,或者如果它在 Django 的某个地方,我很想听听。

【问题讨论】:

    标签: python django django-admin python-2.6 django-1.3


    【解决方案1】:

    修改预先存在的代码中定义的类的最佳方法是使用mixin。需要修改ModelAdmin类的formfield_for_manytomany方法;方法是defined in BaseModelAdmin

    在 Django 服务器启动时保证运行的模块中添加以下代码 [您自己的应用之一的models.py]:

    from django.contrib.admin.options import ModelAdmin
    from django.contrib.admin import widgets
    class CustomModelAdmin:
        def formfield_for_manytomany(self, db_field, request=None, **kwargs):
            """
            Get a form Field for a ManyToManyField.
            """
            # If it uses an intermediary model that isn't auto created, don't show
            # a field in admin.
            if not db_field.rel.through._meta.auto_created:
                return None
            db = kwargs.get('using')
    
            if db_field.name in self.raw_id_fields:
                kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db)
                kwargs['help_text'] = ''
            else:
                kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, False) # change second argument to True for filter_vertical
    
            return db_field.formfield(**kwargs)
    
    ModelAdmin.__bases__ = (CustomModelAdmin,) + ModelAdmin.__bases__
    

    注意事项(2019 年 8 月 27 日):

    我完全了解子类化/继承的工作原理,这是解决此类问题的最佳实践。但是,正如我在下面的 cmets 中重申的那样,子类化 不会解决 OP 的问题,如所述,即。使filter_horizontalfilter_vertical 默认。通过子类化,您不仅需要为所有模型注册子类,还必须取消注册在内置 Django 应用程序和已安装的第三方应用程序中注册的每个 ModelAdmin 子类,然后注册新的 ModelAdmin 子类。因此,例如对于 Django 的内置用户模型...

    admin.site.unregister(User)
    class CustomModelAdmin(admin.ModelAdmin):
        """ Add your changes here """
    admin.site.register(User, CustomModelAdmin)
    

    ...然后为您安装的所有 Django 应用程序和第三方应用程序重复类似的代码。我认为这不是 OP 想要的,因此是我的答案。

    【讨论】:

    • 为什么不直接用单继承呢?或者实际上是多重继承,而不是像__bases__这样的神奇属性?
    • 请解释您的意思,或通过发布答案提出您自己的解决方案。我自己对这个问题的理解是,OP 希望在所有 ManyToManyFields 上使用 filter_horizontal,而不必为每个具有此类字段的模型创建 ModelAdmin 子类。
    • 我评论的哪一部分不清楚?唯一不清楚的是为什么您建议对库类进行猴子修补而不是使用继承。
    • 当然可以使用继承,但这意味着使用ManyTOManyField 为每个模型子类化(SomeOtherClass, ModelAdmin)(CustomModelAdminClass),并为每个模型使用admin.site.register 注册。除非我不明白这个问题,否则 OP 会尽量避免这种情况,只是使用不同的小部件作为默认小部件。
    • 嘿。对于上述问题,@SimonKagwi 是对的——如果我可以将它设置在一个地方,那是首选。但是我不知道我是否喜欢搞乱__bases__ 的想法——一个“干净”的解决方案(例如settings 中的东西)会更好。如果这种解决方案不存在,我更喜欢上面的__bases__ 魔术的许多register 调用。就像我在问题中所说的那样:我已经可以通过元编程来做到这一点,所以我希望听到一个更简单的解决方案。 @Marcin,您将如何解决这个问题?我很想看看你的解决方案。
    【解决方案2】:

    仍然有点 hacky,但比其他答案更好,这会在 Django 升级期间造成各种痛苦。从这里继承(不要猴子补丁):

    class BaseAdmin(models.Admin):
        def formfield_for_manytomany(self, db_field, request=None, **kwargs):
            """
            Get a form Field for a ManyToManyField. Tweak so filter_horizontal 
            control used by default. If raw_id or autocomplete are specified
            will take precedence over this.
            """
            filter_horizontal_original = self.filter_horizontal
            self.filter_horizontal = (db_field.name,)
            form_field = super().formfield_for_manytomany(db_field, request=None, **kwargs)
            self.filter_horizontal = filter_horizontal_original
            return form_field
    
    
    @admin.register(AcmeModel)
    class AcmeModelAdmin(BaseAdmin):
        # Sub-classes can still specify raw_id, autocomplete, etc.
        # That will override our filter_horizontal defaulting.
        pass
    

    由于某种原因,在__init__ 中设置filter_horizontal 不起作用,并且没有要覆盖的get_filter_horizontal

    如上所述,避免猴子补丁并仅从BaseClass 继承。当您在 6 个月后返回此内容并且在继承层次结构中找不到此内容时,您,尤其是您的同事将不胜感激。

    【讨论】:

      猜你喜欢
      • 2019-08-15
      • 2015-09-08
      • 1970-01-01
      • 2011-07-17
      • 2013-01-28
      • 2013-02-28
      • 2014-05-23
      • 2013-08-12
      • 2016-05-04
      相关资源
      最近更新 更多