如何在Django-admin表中关闭列排序或指定WHICH列是可排序的?

时间:2013-06-21 21:10:15

标签: django django-admin

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

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

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

5 个答案:

答案 0 :(得分:2)

我通过将list_display元组中的字段名称替换为我在模型上实现的方法的名称来完成此操作。例如,要禁用"标题"您的模型上的字段,而不是在" 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"

这应该会产生一个带有"标题"的管理员。列正常,但不再可排序。

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

答案 1 :(得分:2)

我做了monkeypatch以始终禁用列排序。

# 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

但是你可以根据自己的需要做一个自定义的monkeypatch。

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

答案 2 :(得分:1)

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

您可以使用自定义ChangeList在后端关闭它,并覆盖get_ordering_field方法,为您不想排序的字段返回None。我还没有通过测试,但看起来这会让管理员忽视它们,如果请求对该字段的排序结束。然后,您可以覆盖呈现表头的change_list_results.html模板,或者使用一些JS来删除CSS / Javascript部分。

或者,您可以在模型或管理类上创建方法,这些方法会影响您不想排序的列,不会设置其admin_order_field值,并且只使用list_display中的方法。这并不需要更改内置管理员,但这有点荒谬。

答案 3 :(得分:1)

我为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 :(得分:1)

对于那些来这里查找除上述规定之外的其他解决方案的人,如果您的Admin Model Class具有ModelAdminadmin.ModelAdmin的子类,则可以引用一个子类变量可以过滤掉或指示可以选择对字段进行排序的字段。

这里是documentation link.

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

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

如果要禁用某些列的排序,请将sortable_by设置为要排序的list_display子集的集合(例如list,tuple或set)。空集合将禁用对所有列的排序。
如果需要动态指定此列表,请改用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:]

输出 为了清楚起见。 Demo