【问题标题】:How can I turn off column sorting in Django-admin tables or specify WHICH columns are sortable?如何关闭 Django-admin 表中的列排序或指定哪些列是可排序的?
【发布时间】:2013-06-21 21:10:14
【问题描述】:

是否有一种简单的方法可以关闭 django 管理中某些/所有列的可排序性和/或指定 哪些 列是可排序的?

我知道我可以通过 javascript 手动禁用排序,但这有点老套,我希望有更好的或内置的方法。

我正在尝试实现管理列表的拖放排序,类似于:http://djangosnippets.org/snippets/2870/,但如果表格按位置列以外的其他方式排序,则拖放排序没有意义。我正在为其执行此操作的表永远不会是一个大表,因此除了位置列之外,用户没有理由需要按其他列进行排序,并且允许它按另一列排序只会增加混乱。

【问题讨论】:

  • 一种 (hacky) 方法是覆盖 change_list 模板并为要从中删除排序的字段禁用 a

标签: django django-admin


【解决方案1】:

如果你的Admin Model ClassModelAdminadmin.ModelAdmin 的子类,来这里寻找其他解决方案的人,可以参考一个子类变量来过滤或指示可以选择哪些字段对列中的数据进行排序。

这是documentation link.

但这是目前的内容。

ModelAdmin.sortable_by
默认情况下,更改列表页面允许按 list_display 中指定的所有模型字段(以及具有 admin_order_field 属性的可调用对象)进行排序。

如果您想禁用某些列的排序,请将 sortable_by 设置为您希望可排序的 list_display 子集的集合(例如列表、元组或集合)。空集合禁用所有列的排序。
如果您需要动态指定此列表,请改为实现 get_sortable_by() 方法。

应用程序

  • 例如,由于各种原因,我们不想为associateId 提供排序。避免对特定字段进行排序。只需排除该字段并重新声明其他字段即可。
class AssociateAttributeFields(ModelAdmin):
    list_display = (
        "associateId",
        "isAllowed",
        "staffRole",
        "dtCreated",
    )
    sortable_by = (
        "isAllowed",
        "staffRole",
        "dtCreated",
    )
    # Can also be the following to avoid being redundant...
    # sortable_by = list_display[1:]

输出 为了清楚起见。

【讨论】:

    【解决方案2】:

    我通过将list_display 元组中的字段名称替换为然后在模型上实现的方法的名称来做到这一点。例如,要禁用模型上“title”字段的排序,而不是在“admin.py”中执行此操作:

    class FooAdmin(admin.ModelAdmin):
        list_display = ('title')
    

    使用这个:

    class FooAdmin(admin.ModelAdmin):
        list_display = ('title_for_admin')
    

    然后在你的“models.py”中:

    class Foo(models.Model):
        title = models.CharField(max_length=255)
    
        def title_for_admin(self):
            return self.title
    
        # To keep 'Title' as the column header in the admin
        title_for_admin.short_description = "Title"
    

    这应该会像正常一样生成一个带有“标题”列的管理员,但它不再是可排序的。

    如果您的模型有很多字段,这对于禁用所有列甚至多列的排序不是一个很好的解决方案,但它适用于禁用对一列或两列的排序。

    【讨论】:

    • 简单的解决方案,无需触及任何更深层的内部结构。不错。
    【解决方案3】:

    我为nttaylor's answer做了一个快捷方式,你可以创建一个这样的装饰器

    from six.moves import reduce
    
    def list_property(field_name, **kwargs):
        def _from_property(obj):
            rv = reduce(getattr, field_name.split("."), obj)
            return rv() if callable(rv) else rv
    
        for key, value in kwargs.items():
            setattr(_from_property, key, value)
        return _from_property
    

    并在您的模型管理员中使用它:

    class MyModelAdmin(admin.ModelAdmin):
        list_display = [list_property("title", short_description=_("..."))]
    

    您可以通过将字段的 verbose_name 分配给装饰属性来使此装饰器更加智能。

    【讨论】:

      【解决方案4】:

      我做了一个猴子补丁来始终禁用列排序。

      # monkeypatch: override the original `result_headers` template function
      from django.contrib.admin.templatetags import admin_list
      from django.contrib.admin.templatetags.admin_list import result_headers
      orig_result_headers = result_headers
      
      def result_headers(cl):
          for header in orig_result_headers(cl):
              header['sortable'] = False
              yield header
      
      admin_list.result_headers = result_headers
      

      但您可以根据自己的需要定制猴子补丁。

      # model admin
      class FooAdmin(admin.ModelAdmin):
          list_display = ('field_a', 'field_b', 'field_c')
          list_display_sortable = ('field_b', 'field_c')
      
      # monkeypatch: override the original `result_headers` template function
      from django.contrib.admin.templatetags import admin_list
      from django.contrib.admin.templatetags.admin_list import result_headers
      orig_result_headers = result_headers
      
      def result_headers(cl):
          sortable_idx = []
          sortable_fields = getattr(cl.model_admin, 'list_display_sortable', ())
          for field_name in cl.list_display:
              sortable_idx.append(field_name in sortable_fields)
          for i, header in enumerate(orig_result_headers(cl)):
              header['sortable'] = sortable_idx[i]
              yield header
      
      admin_list.result_headers = result_headers
      

      使用 Django 1.10 测试

      【讨论】:

      • 太棒了!我用 Django 1.11 对此进行了测试并且工作正常。
      【解决方案5】:

      我认为没有一种优雅的方法可以做到这一点。

      您可以通过使用自定义 ChangeList 并覆盖 get_ordering_field 方法在后端将其关闭,以便为您不希望可排序的字段返回 None。我还没有测试过,但是如果对该字段进行排序的请求最终出现在请求中,这似乎会使管理员忽略它们。然后,您可以覆盖呈现表头的change_list_results.html 模板,或者使用一些 JS 来删除 CSS/Javascript 部分。

      或者,您可以在模型或管理类上创建方法来隐藏您不希望可排序的列,不设置它们的 admin_order_field 值,并仅使用 list_display 中的那些。这不需要更改太多的内置管理员,但这有点荒谬。

      【讨论】:

      • 谢谢彼得。我发现了这个:djangosnippets.org/snippets/2580,这与您的建议相似。但是,所写的 sn-p 不起作用(至少在我使用的 django 版本中不起作用)。您建议覆盖 get_ordering_field() 而不是 get_ordering() 可以解决问题。谢谢!
      • 我仍然需要手动删除样式和 javascript,但至少它可以防止排序。
      • 只是目不转睛,我认为模板编辑会很简单——内置的有一堆'if header.sortable'标签,你可以删除它们中的所有内容。不幸的是,sortable 属性是在模板标签中设置的,如果该字段实际上是一个模型字段,它会短路任何花哨的逻辑,所以你不能轻易告诉它事情不可排序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 2020-04-27
      • 1970-01-01
      • 2017-02-15
      • 2012-10-24
      • 1970-01-01
      • 2013-09-15
      相关资源
      最近更新 更多