4

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

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

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

4

5 回答 5

5

对于那些来这里寻找上述规定之外的其他解决方案的人,如果您Admin Model ClassModelAdminor的子类admin.ModelAdmin,则可以引用一个子类变量来过滤或指示哪些字段可以选择对列中的数据进行排序。

这是文档链接。

但这是到目前为止的内容。

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:]

输出 为清楚起见。 演示

于 2020-09-06T12:59:05.917 回答
4

我通过将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"

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

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

于 2017-02-15T18:18:56.833 回答
2

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

# 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 测试

于 2017-08-17T15:11:32.127 回答
1

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

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

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

于 2013-06-21T21:27:38.693 回答
1

我为nttaylor的回答做了一个快捷方式,你可以像这样创建一个装饰器

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 分配给装饰属性来使此装饰器更加智能。

于 2019-03-20T02:45:55.413 回答