在 Django Admin 中排序 admin.ModelAdmin 对象

发布于 2024-07-10 17:58:02 字数 486 浏览 10 评论 0原文

假设我的披萨应用程序包含 Topping 和 Pizza 类,它们在 Django Admin 中显示如下:

PizzaApp
-
Toppings      >>>>>>>>>>      Add / Change

Pizzas        >>>>>>>>>>      Add / Change

但我希望它们像这样:

PizzaApp
-
Pizzas        >>>>>>>>>>      Add / Change

Toppings      >>>>>>>>>>      Add / Change

如何在我的 admin.py 中配置它?

Let's say I have my pizza application with Topping and Pizza classes and they show in Django Admin like this:

PizzaApp
-
Toppings      >>>>>>>>>>      Add / Change

Pizzas        >>>>>>>>>>      Add / Change

But I want them like this:

PizzaApp
-
Pizzas        >>>>>>>>>>      Add / Change

Toppings      >>>>>>>>>>      Add / Change

How do I configure that in my admin.py?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

迎风吟唱 2024-07-17 17:58:02

您可以尝试的解决方法是调整您的 models.py,如下所示:

class Topping(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "2. Toppings"

class Pizza(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "1. Pizzas"

不确定它是否违反 django 的最佳实践,但它有效(使用 django trunk 进行测试)。

祝你好运!

PS:抱歉,如果这个答案发布得太晚了,但它可以帮助其他人在未来类似的情况下。

A workaround that you can try is tweaking your models.py as follows:

class Topping(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "2. Toppings"

class Pizza(models.Model):
    .
    .
    .
    class Meta:
        verbose_name_plural = "1. Pizzas"

Not sure if it is against the django's best practices but it works (tested with django trunk).

Good luck!

PS: sorry if this answer was posted too late but it can help others in future similar situations.

不甘平庸 2024-07-17 17:58:02

如果你想在 10 秒内解决这个问题,只需在 verbose_name_plural 中使用空格,例如:

class Topping(models.Model):
    class Meta:
        verbose_name_plural = "  Toppings" # 2 spaces

class Pizza(models.Model):
    class Meta:
        verbose_name_plural = " Pizzas" # 1 space

当然,它并不优雅,但在我们得到更好的解决方案之前可能会工作一段时间。

If you want to solve this in 10 seconds just use spaces in verbose_name_plural, for example:

class Topping(models.Model):
    class Meta:
        verbose_name_plural = "  Toppings" # 2 spaces

class Pizza(models.Model):
    class Meta:
        verbose_name_plural = " Pizzas" # 1 space

Of course it isn't ellegant but may work for a while before we get a better solution.

魔法唧唧 2024-07-17 17:58:02

多亏了这个 Django 片段,我最终成功做到了这一点,您只需要注意 ADMIN_REORDER< /code> 设置:

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

app1 不得以项目名称为前缀,即使用 app1 而不是 mysite.app1

I eventually managed to do it thanks to this Django snippet, you just need to be aware of the ADMIN_REORDER setting:

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

app1 must not be prefixed with the project name, i.e. use app1 instead of mysite.app1.

孤独患者 2024-07-17 17:58:02

现在有一个很好的 Django 包:

https://pypi.python.org/pypi/django-modeladmin-reorder

There's now a nice Django package for that:

https://pypi.python.org/pypi/django-modeladmin-reorder

邮友 2024-07-17 17:58:02

2018年6月回答

这个答案和Vasil的想法类似,

我试图解决类似的问题,然后我看到了这样的片段

我根据这个剪辑做了一些修改。 代码如下。

# myproject/setting.py
...
# set my ordering list
ADMIN_ORDERING = [
    ('pizza_app', [
        'Pizzas',
        'Toppings'
    ]),
]
# Creating a sort function
def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    for app_name, object_list in ADMIN_ORDERING:
        app = app_dict[app_name]
        app['models'].sort(key=lambda x: object_list.index(x['object_name']))
        yield app


# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin

admin.AdminSite.get_app_list = get_app_list
...

请注意,此排序功能中使用的排序列表包含系统中所有应用程序及其模块的排序。 如果不需要,请根据自己的需求设计排序功能。

在Django 2.0上效果很好

Answer in June 2018

This answer is similar to Vasil's idea

I tried to solve similar problems, and then I saw such the fragment.

I made some modifications based on this clip. The code is as follows.

# myproject/setting.py
...
# set my ordering list
ADMIN_ORDERING = [
    ('pizza_app', [
        'Pizzas',
        'Toppings'
    ]),
]
# Creating a sort function
def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    for app_name, object_list in ADMIN_ORDERING:
        app = app_dict[app_name]
        app['models'].sort(key=lambda x: object_list.index(x['object_name']))
        yield app


# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin

admin.AdminSite.get_app_list = get_app_list
...

Note that the sorting list used in this sorting function contains the sorting of all app and its modules in the system. If you don't need it, please design the sorting function according to your own needs.

It works great on Django 2.0

时光无声 2024-07-17 17:58:02

这实际上在 编写你的第一个 Django 应用程序,第 7 部分。

这是相关部分:

自定义管理索引页面

类似地,您可能想要
定制的外观和感觉
Django 管理索引页面。

默认情况下,它显示所有应用程序
在已安装的 INSTALLED_APPS 中
使用管理应用程序注册,
按字母顺序排列。 你可能想要
做出重大改变
布局。 毕竟索引是
可能是最重要的页面
管理员,应该很容易
使用。

要定制的模板是
管理/index.html。 (与
admin/base_site.html 在前面
部分——从默认复制它
您的自定义模板的目录
目录。)编辑该文件,您将
看到它使用了一个名为的模板变量
应用程序列表。 该变量包含每个
安装了 Django 应用程序。 而不是使用
您可以将链接硬编码到
特定于对象的管理页面
无论您认为哪种方式最好。

This is actually covered at the very bottom of Writing your first Django app, part 7.

Here's the relevant section:

Customize the admin index page

On a similar note, you might want to
customize the look and feel of the
Django admin index page.

By default, it displays all the apps
in INSTALLED_APPS that have been
registered with the admin application,
in alphabetical order. You may want to
make significant changes to the
layout. After all, the index is
probably the most important page of
the admin, and it should be easy to
use.

The template to customize is
admin/index.html. (Do the same as with
admin/base_site.html in the previous
section -- copy it from the default
directory to your custom template
directory.) Edit the file, and you'll
see it uses a template variable called
app_list. That variable contains every
installed Django app. Instead of using
that, you can hard-code links to
object-specific admin pages in
whatever way you think is best.

失眠症患者 2024-07-17 17:58:02

这是 Emmanuel 使用的代码片段,针对 Django 1.8 进行了更新:

在 templatetags/admin_reorder.py 中:

from django import template
from django.conf import settings
from collections import OrderedDict

register = template.Library()

# from http://www.djangosnippets.org/snippets/1937/
def register_render_tag(renderer):
    """
    Decorator that creates a template tag using the given renderer as the 
    render function for the template tag node - the render function takes two 
    arguments - the template context and the tag token
    """
    def tag(parser, token):
        class TagNode(template.Node):
            def render(self, context):
                return renderer(context, token)
        return TagNode()
    for copy_attr in ("__dict__", "__doc__", "__name__"):
        setattr(tag, copy_attr, getattr(renderer, copy_attr))
    return register.tag(tag)

@register_render_tag
def admin_reorder(context, token):
    """
    Called in admin/base_site.html template override and applies custom ordering
    of apps/models defined by settings.ADMIN_REORDER
    """
    # sort key function - use index of item in order if exists, otherwise item
    sort = lambda order, item: (order.index(item), "") if item in order else (
        len(order), item)
    if "app_list" in context:
        # sort the app list
        order = OrderedDict(settings.ADMIN_REORDER)
        context["app_list"].sort(key=lambda app: sort(order.keys(),
            app["app_url"].strip("/").split("/")[-1]))
        for i, app in enumerate(context["app_list"]):
            # sort the model list for each app
            app_name = app["app_url"].strip("/").split("/")[-1]
            if not app_name:
                app_name = app["name"].lower()
            model_order = [m.lower() for m in order.get(app_name, [])]
            context["app_list"][i]["models"].sort(key=lambda model:
            sort(model_order, model["admin_url"].strip("/").split("/")[-1]))
    return ""

在 settings.py 中:(

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

在此处插入您自己的应用程序名称。管理员会将缺少的应用程序或模型放在列表的末尾,只要您在每个应用程序中至少列出两个模型。)

在您的 base_site.html 副本中:

{% extends "admin/base.html" %}
{% load i18n admin_reorder %}

{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}

{% block branding %}
{% admin_reorder %}
<h1 id="site-name">{% trans 'Django administration' %}</h1>
{% endblock %}

{% block nav-global %}{% endblock %}

Here's the snippet Emmanuel used, updated for Django 1.8:

In templatetags/admin_reorder.py:

from django import template
from django.conf import settings
from collections import OrderedDict

register = template.Library()

# from http://www.djangosnippets.org/snippets/1937/
def register_render_tag(renderer):
    """
    Decorator that creates a template tag using the given renderer as the 
    render function for the template tag node - the render function takes two 
    arguments - the template context and the tag token
    """
    def tag(parser, token):
        class TagNode(template.Node):
            def render(self, context):
                return renderer(context, token)
        return TagNode()
    for copy_attr in ("__dict__", "__doc__", "__name__"):
        setattr(tag, copy_attr, getattr(renderer, copy_attr))
    return register.tag(tag)

@register_render_tag
def admin_reorder(context, token):
    """
    Called in admin/base_site.html template override and applies custom ordering
    of apps/models defined by settings.ADMIN_REORDER
    """
    # sort key function - use index of item in order if exists, otherwise item
    sort = lambda order, item: (order.index(item), "") if item in order else (
        len(order), item)
    if "app_list" in context:
        # sort the app list
        order = OrderedDict(settings.ADMIN_REORDER)
        context["app_list"].sort(key=lambda app: sort(order.keys(),
            app["app_url"].strip("/").split("/")[-1]))
        for i, app in enumerate(context["app_list"]):
            # sort the model list for each app
            app_name = app["app_url"].strip("/").split("/")[-1]
            if not app_name:
                app_name = app["name"].lower()
            model_order = [m.lower() for m in order.get(app_name, [])]
            context["app_list"][i]["models"].sort(key=lambda model:
            sort(model_order, model["admin_url"].strip("/").split("/")[-1]))
    return ""

In settings.py:

ADMIN_REORDER = (
    ('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
    ('app2', ('App2Model1', 'App2Model2')),
)

(insert your own app names in here. Admin will place missing apps or models at the end of the list, so long as you list at least two models in each app.)

In your copy of base_site.html:

{% extends "admin/base.html" %}
{% load i18n admin_reorder %}

{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}

{% block branding %}
{% admin_reorder %}
<h1 id="site-name">{% trans 'Django administration' %}</h1>
{% endblock %}

{% block nav-global %}{% endblock %}
七月上 2024-07-17 17:58:02

如果您在 AdminSite 中使用 Suit,您可以使用 菜单标签

If you're using Suit for the AdminSite you can do menu customization using the menu tag.

最近可好 2024-07-17 17:58:02

您可以在管理页面中重新排序和隐藏应用程序和模型。 *我使用Django 4.1.7

例如,app1/models.pyapp2/models.py 中有相同的 3 个模型,如下所示:

# "app1/models.py
# "app2/models.py

from django.db import models

class Model1(models.Model):
    class Meta:
        verbose_name_plural = 'Model1'

class Model2(models.Model):
    class Meta:
        verbose_name_plural = 'Model2'

class Model3(models.Model):
    class Meta:
        verbose_name_plural = 'Model3'

那么,中有相同的 3 个管理员>app1/admin.pyapp2/admin.py 如下所示:

# "app1/admin.py
# "app2/admin.py

from django.contrib import admin
from .models import Model1, Model2, Model3

@admin.register(Model1)
class Model1Admin(admin.ModelAdmin):
    pass

@admin.register(Model2)
class Model2Admin(admin.ModelAdmin):
    pass

@admin.register(Model3)
class Model3Admin(admin.ModelAdmin):
    pass

然后,AUTHENTICATION AND AUTHORIZATION(auth) 等 3 个应用程序会显示在 中>Home 管理页面如下所示:

在此处输入图像描述

现在,设置 ADMIN_ORDERING 并在 中重写的 get_app_list() 中处理它settings.py 如下所示。 *可以查看原文 get_app_list()< /a> in GitHub:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        'Model1', 
        'Model2'
    )),
    ('auth', (
        'User', 
        'Group'
    )),
    ('app1', (
        'Model2', 
        'Model3', 
        'Model1'
    ))
)

from django.contrib import admin

def get_app_list(self, request, app_label=None):
    app_dict = self._build_app_dict(request, app_label)
    
    if not app_dict:
        return
        
    NEW_ADMIN_ORDERING = []
    if app_label:
        for ao in ADMIN_ORDERING:
            if ao[0] == app_label:
                NEW_ADMIN_ORDERING.append(ao)
                break
    
    if not app_label:
        for app_key in list(app_dict.keys()):
            if not any(app_key in ao_app for ao_app in ADMIN_ORDERING):
                app_dict.pop(app_key)
    
    app_list = sorted(
        app_dict.values(), 
        key=lambda x: [ao[0] for ao in ADMIN_ORDERING].index(x['app_label'])
    )
     
    for app, ao in zip(app_list, NEW_ADMIN_ORDERING or ADMIN_ORDERING):
        if app['app_label'] == ao[0]:
            for model in list(app['models']):
                if not model['object_name'] in ao[1]:
                    app['models'].remove(model)
        app['models'].sort(key=lambda x: ao[1].index(x['object_name']))
    return app_list

admin.AdminSite.get_app_list = get_app_list

然后,在 Home 管理页面中更改 3 个应用程序和模型的顺序,如下所示。 *它们的顺序在其他管理页面中也发生了变化,而不仅仅是在 Home 管理页面中:

在此处输入图像描述

接下来,删除 app2 中的 Model1auth本身以及app1中的所有模型来隐藏它们,如下所示:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        # 'Model1', 
        'Model2'
    )),
    # ('auth', (
    #     'User', 
    #     'Group'
    # )),
    ('app1', (
        # 'Model2', 
        # 'Model3', 
        # 'Model1'
    ))
)

# ...

然后,app2中的Model1 code>、auth 本身以及 app1 中的所有模型都隐藏在 Home 管理页面中,如下所示。 *它们还隐藏在其他管理页面中,而不仅仅是在 Home 管理页面中:

< img src="https://i.sstatic.net/jdxkT.png" alt="在此处输入图像描述">

此外,即使不存在的应用程序和模型设置为 ADMIN_ORDERING 如下所示:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        'Model1', 
        'Model2',
        'Model4', # Doesn't exist
        'Model5'  # Doesn't exist
    )),
    ('auth', (
        'Model1', # Doesn't exist
        'User', 
        'Group',
        'Model2'  # Doesn't exist
    )),
    ('app1', ( 
        'Group',  # Doesn't exist
        'Model2', 
        'Model3', 
        'Model1',
        'User'    # Doesn't exist
    )),
    ('app3', ( # Doesn't exist
        'Model1', # Doesn't exist
        'Model2', # Doesn't exist
        'Model3'  # Doesn't exist
    ))
)

# ...

然后,它们将被忽略并且不显示,如下所示。 实际上,如果不存在的应用程序和模型设置为 ADMIN_ORDERING,我想返回错误,但我没有太多时间考虑它:

在此处输入图像描述

You can reorder and hide the apps and models in admin pages. *I use Django 4.1.7.

For example, there are the same 3 models in app1/models.py and app2/models.py as shown below:

# "app1/models.py
# "app2/models.py

from django.db import models

class Model1(models.Model):
    class Meta:
        verbose_name_plural = 'Model1'

class Model2(models.Model):
    class Meta:
        verbose_name_plural = 'Model2'

class Model3(models.Model):
    class Meta:
        verbose_name_plural = 'Model3'

Then, there are the same 3 admins in app1/admin.py and app2/admin.py as shown below:

# "app1/admin.py
# "app2/admin.py

from django.contrib import admin
from .models import Model1, Model2, Model3

@admin.register(Model1)
class Model1Admin(admin.ModelAdmin):
    pass

@admin.register(Model2)
class Model2Admin(admin.ModelAdmin):
    pass

@admin.register(Model3)
class Model3Admin(admin.ModelAdmin):
    pass

Then, 3 apps including AUTHENTICATION AND AUTHORIZATION(auth) are displayed in Home admin page as shown below:

enter image description here

Now, set ADMIN_ORDERING and treat it in overridden get_app_list() in settings.py as shown below. *You can see the original get_app_list() in GitHub:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        'Model1', 
        'Model2'
    )),
    ('auth', (
        'User', 
        'Group'
    )),
    ('app1', (
        'Model2', 
        'Model3', 
        'Model1'
    ))
)

from django.contrib import admin

def get_app_list(self, request, app_label=None):
    app_dict = self._build_app_dict(request, app_label)
    
    if not app_dict:
        return
        
    NEW_ADMIN_ORDERING = []
    if app_label:
        for ao in ADMIN_ORDERING:
            if ao[0] == app_label:
                NEW_ADMIN_ORDERING.append(ao)
                break
    
    if not app_label:
        for app_key in list(app_dict.keys()):
            if not any(app_key in ao_app for ao_app in ADMIN_ORDERING):
                app_dict.pop(app_key)
    
    app_list = sorted(
        app_dict.values(), 
        key=lambda x: [ao[0] for ao in ADMIN_ORDERING].index(x['app_label'])
    )
     
    for app, ao in zip(app_list, NEW_ADMIN_ORDERING or ADMIN_ORDERING):
        if app['app_label'] == ao[0]:
            for model in list(app['models']):
                if not model['object_name'] in ao[1]:
                    app['models'].remove(model)
        app['models'].sort(key=lambda x: ao[1].index(x['object_name']))
    return app_list

admin.AdminSite.get_app_list = get_app_list

Then, the order of 3 apps and the models is changed in Home admin page as shown below. *The order of them is also changed in other admin pages not just in Home admin page:

enter image description here

Next, remove Model1 in app2, auth itself and all models in app1 to hide them as shown below:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        # 'Model1', 
        'Model2'
    )),
    # ('auth', (
    #     'User', 
    #     'Group'
    # )),
    ('app1', (
        # 'Model2', 
        # 'Model3', 
        # 'Model1'
    ))
)

# ...

Then, Model1 in app2, auth itself and all models in app1 are hidden in Home admin page as shown below. *They are also hidden in other admin pages not just in Home admin page:

enter image description here

In addition, even if the apps and models which don't exist are set to ADMIN_ORDERING as shown below:

# "core/settings.py"

ADMIN_ORDERING = (
    ('app2', (
        'Model3', 
        'Model1', 
        'Model2',
        'Model4', # Doesn't exist
        'Model5'  # Doesn't exist
    )),
    ('auth', (
        'Model1', # Doesn't exist
        'User', 
        'Group',
        'Model2'  # Doesn't exist
    )),
    ('app1', ( 
        'Group',  # Doesn't exist
        'Model2', 
        'Model3', 
        'Model1',
        'User'    # Doesn't exist
    )),
    ('app3', ( # Doesn't exist
        'Model1', # Doesn't exist
        'Model2', # Doesn't exist
        'Model3'  # Doesn't exist
    ))
)

# ...

Then, they are ignored and not displayed as shown below. Actually, I wanted to return error if the apps and models which don't exist are set to ADMIN_ORDERING but I don't have much time to think about it:

enter image description here

娇女薄笑 2024-07-17 17:58:02
ADMIN_ORDERING = {
    "PizzaApp": [
        "Pizzas",
        "Toppings",
    ],
}


def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    for app_name, object_list in app_dict.items():
        if app_name in ADMIN_ORDERING:
            app = app_dict[app_name]
            app["models"].sort(
                key=lambda x: ADMIN_ORDERING[app_name].index(x["object_name"])
            )
            app_dict[app_name]
            yield app
        else:
            yield app_dict[app_name]


admin.AdminSite.get_app_list = get_app_list

这个解决方案对我有用,修改了林伟雄的解决方案。

您可以保留默认的身份验证顺序并指定您自己的。

ADMIN_ORDERING = {
    "PizzaApp": [
        "Pizzas",
        "Toppings",
    ],
}


def get_app_list(self, request):
    app_dict = self._build_app_dict(request)
    for app_name, object_list in app_dict.items():
        if app_name in ADMIN_ORDERING:
            app = app_dict[app_name]
            app["models"].sort(
                key=lambda x: ADMIN_ORDERING[app_name].index(x["object_name"])
            )
            app_dict[app_name]
            yield app
        else:
            yield app_dict[app_name]


admin.AdminSite.get_app_list = get_app_list

This solution works for me, modified the one from 林伟雄.

You get to keep the default auth ordering AND specify your own.

始终不够 2024-07-17 17:58:02

我正在寻找一个简单的解决方案,我可以在管理面板中按应用程序的名称对应用程序进行排序。 我想出了以下模板标记:

from django import template
from django.conf import settings
register = template.Library()

@register.filter
def sort_apps(apps):
    apps.sort(
        key = lambda x:
        settings.APP_ORDER.index(x['app_label'])
        if x['app_label'] in settings.APP_ORDER
        else len(apps)
    )
    print [x['app_label'] for x in apps]
    return apps

然后,只需覆盖 templates/admin/index.html 并添加该模板标记:

{% extends "admin/index.html" %}
{% block content %}
{% load i18n static sort_apps %}
<div id="content-main">

{% if app_list %}
    {% for app in app_list|sort_apps %}
        <div class="app-{{ app.app_label }} module">
        <table>
        <caption>
            <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
        </caption>
        {% for model in app.models %}
            <tr class="model-{{ model.object_name|lower }}">
            {% if model.admin_url %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                <th scope="row">{{ model.name }}</th>
            {% endif %}

            {% if model.add_url %}
                <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
            {% else %}
                <td> </td>
            {% endif %}

            {% if model.admin_url %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td> </td>
            {% endif %}
            </tr>
        {% endfor %}
        </table>
        </div>
    {% endfor %}
{% else %}
    <p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}

在 settings.py 中自定义 APP_ORDER

APP_ORDER = [
    'app1',
    'app2',
    # and so on...
]

然后 在 Django 1.10 上运行良好

I was looking for a simple solution where I could order the apps by their name in the admin panel. I came up with the following template tag:

from django import template
from django.conf import settings
register = template.Library()

@register.filter
def sort_apps(apps):
    apps.sort(
        key = lambda x:
        settings.APP_ORDER.index(x['app_label'])
        if x['app_label'] in settings.APP_ORDER
        else len(apps)
    )
    print [x['app_label'] for x in apps]
    return apps

Then, just override templates/admin/index.html and add that template tag:

{% extends "admin/index.html" %}
{% block content %}
{% load i18n static sort_apps %}
<div id="content-main">

{% if app_list %}
    {% for app in app_list|sort_apps %}
        <div class="app-{{ app.app_label }} module">
        <table>
        <caption>
            <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
        </caption>
        {% for model in app.models %}
            <tr class="model-{{ model.object_name|lower }}">
            {% if model.admin_url %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                <th scope="row">{{ model.name }}</th>
            {% endif %}

            {% if model.add_url %}
                <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
            {% else %}
                <td> </td>
            {% endif %}

            {% if model.admin_url %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td> </td>
            {% endif %}
            </tr>
        {% endfor %}
        </table>
        </div>
    {% endfor %}
{% else %}
    <p>{% trans "You don't have permission to edit anything." %}</p>
{% endif %}
</div>
{% endblock %}

Then customized the APP_ORDER in settings.py:

APP_ORDER = [
    'app1',
    'app2',
    # and so on...
]

It works great on Django 1.10

末蓝 2024-07-17 17:58:02

这是一个为您提供更多灵活性的版本,即:

  • 您可以部分定义应用程序排序,将其余部分留给 Django 添加到列表中
  • 您可以在模块上指定顺序,或避免定义它,方法是使用 '*' 代替
  • 您定义的应用程序排序将首先出现,然后附加在其后的所有其余应用程序
  • 要检查应用程序的名称,请查看应用程序目录中的文件 apps.py 并检查 apps.py 的 name 属性。 code>class Config(AppConfi): 或者如果不存在,请使用项目中应用程序的目录名称。

将此代码添加到您的 settings.py 文件中:

# ======[Setting the order in which the apps/modules show up listed on Admin]========
# set my ordering list
ADMIN_ORDERING = [
    ('crm', '*'),
    ('property', '*'),
]


# Creating a sort function
def get_app_list(self, request):
    """
    Returns a sorted list of all the installed apps that have been
    registered in this site.

    Allows for:
        ADMIN_ORDERING = [
            ('app_1', [
                'module_1',
                'module_2'
            ]),
            ('app_2', '*'),
        ]
    """

    app_dict = self._build_app_dict(request)

    # Let's start by sorting the apps alphabetically on a list:
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sorting the models alphabetically within each app.
    for app in app_list:
        if app['app_label'] in [el[0] for el in ADMIN_ORDERING]:
            app_list.remove(app)
        else:
            app['models'].sort(key=lambda x: x['name'])

    # Now we order the app list in our defined way in ADMIN_ORDERING (which could be a subset of all apps).
    my_ordered_apps = []
    if app_dict:
        for app_name, object_list in ADMIN_ORDERING:
            app = app_dict[app_name]
            if object_list == '*':
                app['models'].sort(key=lambda x: x['name'])
            else:
                app['models'].sort(key=lambda x: object_list.index(x['object_name']))
            my_ordered_apps.append(app)

        # Now we combine and arrange the 2 lists together
        my_ordered_apps.extend(app_list)

    return my_ordered_apps

# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin
admin.AdminSite.get_app_list = get_app_list
# =========================================

这只不过是覆盖 Django 在文件 python2.7/site-packages/django/contrib/admin/sites.py 上定义的函数。

class AdminSite(object):get_app_list 方法生成包含项目上所有应用程序的数据结构,包括 Django 的 auth 应用程序,例如:

[
  {
    "app_label": "auth",
    "app_url": "/admin/auth/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/auth/group/add/",
        "admin_url": "/admin/auth/group/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f990>",
        "object_name": "Group",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/auth/user/add/",
        "admin_url": "/admin/auth/user/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f710>",
        "object_name": "User",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "<django.utils.functional.__proxy__ object at 0x108b81850>"
  },
  {
    "app_label": "reservations",
    "app_url": "/admin/reservations/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/reservations/reservationrule/add/",
        "admin_url": "/admin/reservations/reservationrule/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f6d0>",
        "object_name": "ReservationRule",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Availability"
  },
  {
    "app_label": "blog",
    "app_url": "/admin/blog/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/blog/category/add/",
        "admin_url": "/admin/blog/category/",
        "name": "Categories",
        "object_name": "Category",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/post/add/",
        "admin_url": "/admin/blog/post/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f110>",
        "object_name": "Post",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/tag/add/",
        "admin_url": "/admin/blog/tag/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f390>",
        "object_name": "Tag",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Blog"
  },
(...)
]

Here's a version that gives you a bit more flexibility, namely:

  • You can partially define apps ordering, leaving the rest for Django to add to the list
  • You can specify order on modules, or avoid defining it, by using '*' instead
  • Your defined apps ordering will appear first, then all the rest of apps appended after it
  • To check the name of your app, either look at the file apps.py inside the app's directory and check for name property of the class Config(AppConfi): or in case that is not present, use the name of the directory for the app in the project.

Add this code somewhere in your settings.py file:

# ======[Setting the order in which the apps/modules show up listed on Admin]========
# set my ordering list
ADMIN_ORDERING = [
    ('crm', '*'),
    ('property', '*'),
]


# Creating a sort function
def get_app_list(self, request):
    """
    Returns a sorted list of all the installed apps that have been
    registered in this site.

    Allows for:
        ADMIN_ORDERING = [
            ('app_1', [
                'module_1',
                'module_2'
            ]),
            ('app_2', '*'),
        ]
    """

    app_dict = self._build_app_dict(request)

    # Let's start by sorting the apps alphabetically on a list:
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sorting the models alphabetically within each app.
    for app in app_list:
        if app['app_label'] in [el[0] for el in ADMIN_ORDERING]:
            app_list.remove(app)
        else:
            app['models'].sort(key=lambda x: x['name'])

    # Now we order the app list in our defined way in ADMIN_ORDERING (which could be a subset of all apps).
    my_ordered_apps = []
    if app_dict:
        for app_name, object_list in ADMIN_ORDERING:
            app = app_dict[app_name]
            if object_list == '*':
                app['models'].sort(key=lambda x: x['name'])
            else:
                app['models'].sort(key=lambda x: object_list.index(x['object_name']))
            my_ordered_apps.append(app)

        # Now we combine and arrange the 2 lists together
        my_ordered_apps.extend(app_list)

    return my_ordered_apps

# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin
admin.AdminSite.get_app_list = get_app_list
# =========================================

This is nothing more than overwriting the function defined by Django on the file python2.7/site-packages/django/contrib/admin/sites.py.

That get_app_list method of class AdminSite(object): produces a data structure with all apps on the project, including for Django's auth app, such as:

[
  {
    "app_label": "auth",
    "app_url": "/admin/auth/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/auth/group/add/",
        "admin_url": "/admin/auth/group/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f990>",
        "object_name": "Group",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/auth/user/add/",
        "admin_url": "/admin/auth/user/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f710>",
        "object_name": "User",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "<django.utils.functional.__proxy__ object at 0x108b81850>"
  },
  {
    "app_label": "reservations",
    "app_url": "/admin/reservations/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/reservations/reservationrule/add/",
        "admin_url": "/admin/reservations/reservationrule/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f6d0>",
        "object_name": "ReservationRule",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Availability"
  },
  {
    "app_label": "blog",
    "app_url": "/admin/blog/",
    "has_module_perms": "True",
    "models": [
      {
        "add_url": "/admin/blog/category/add/",
        "admin_url": "/admin/blog/category/",
        "name": "Categories",
        "object_name": "Category",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/post/add/",
        "admin_url": "/admin/blog/post/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f110>",
        "object_name": "Post",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      },
      {
        "add_url": "/admin/blog/tag/add/",
        "admin_url": "/admin/blog/tag/",
        "name": "<django.utils.functional.__proxy__ object at 0x11057f390>",
        "object_name": "Tag",
        "perms": {
          "add": "True",
          "change": "True",
          "delete": "True"
        }
      }
    ],
    "name": "Blog"
  },
(...)
]
屌丝范 2024-07-17 17:58:02

这只是在黑暗中进行的疯狂尝试,但是您调用 admin.site.register(,) 的顺序是否有可能确定显示顺序? 实际上,我怀疑这是否有效,因为我相信 Django 维护着模型的注册表 -> ModelAdmin 对象作为标准 Python 字典实现,不维护迭代顺序。

如果这不符合您想要的方式,您可以随时使用 django/contrib/admin 中的源代码。 如果需要维护迭代顺序,可以将 AdminSite 类(在 admin/sites.py 中)中的 _registry 对象替换为维护键插入顺序的 UserDict 或 DictMixin。 (但是请对这个建议持保留态度,因为我自己从未进行过此类更改,我只是对 Django 如何迭代 ModelAdmin 对象集合进行有根据的猜测。我确实认为 django/contrib不过, /admin/sites.py 是查找此代码的地方,而 AdminSite 类以及 register() 和 index() 方法尤其是您想要的。)

显然,这里最好的事情对您来说是一个简单的选择在您自己的 /admin.py 模块中指定。 我确信这就是您希望收到的答案。 不过,我不确定这些选项是否存在。

This is just a wild stab in the dark, but is there any chance that the order in which you call admin.site.register(< Model class >, < ModelAdmin class >) can determine the display order? Actually, I doubt that would work because I believe Django maintains a registry of the Model -> ModelAdmin objects implemented as a standard Python dictionary, which does not maintain iteration ordering.

If that doesn't behave the way you want, you can always play around with the source in django/contrib/admin. If you need the iteration order maintained, you could replace the _registry object in the AdminSite class (in admin/sites.py) with a UserDict or DictMixin that maintains insertion order for the keys. (But please take this advice with a grain of salt, since I've never made these kinds of changes myself and I'm only making an educated guess at how Django iterates over the collection of ModelAdmin objects. I do think that django/contrib/admin/sites.py is the place to look for this code, though, and the AdminSite class and register() and index() methods in particular are what you want.)

Obviously the nicest thing here would be a simple option for you to specify in your own /admin.py module. I'm sure that's the kind of answer you were hoping to receive. I'm not sure if those options exist, though.

陌伤浅笑 2024-07-17 17:58:02

我的解决方案是创建 django.contrib.admin.sites.AdminSite 和 django.contrib.admin.options.ModelAdmin 的子类。

我这样做是为了可以为每个应用程序显示更具描述性的标题,并排序每个应用程序中模型的外观。 因此,我的 settings.py 中有一个字典,它将 app_labels 映射到描述性名称以及它们应出现的顺序,模型按我在管理站点注册时在每个 ModelAdmin 中提供的序数字段进行排序。

尽管文档中鼓励创建您自己的 AdminSite 和 ModelAdmin 子类,但我的解决方案最终看起来像是一个丑陋的黑客。

My solution was to make subclasses of django.contrib.admin.sites.AdminSite and django.contrib.admin.options.ModelAdmin .

I did this so I could display a more descriptive title for each app and order the appearance of models in each app. So I have a dict in my settings.py that maps app_labels to descriptive names and the order in which they should appear, the models are ordered by an ordinal field I provide in each ModelAdmin when I register them with the admin site.

Although making your own subclasses of AdminSite and ModelAdmin is encouraged in the docs, my solution looks like an ugly hack in the end.

你另情深 2024-07-17 17:58:02

将 lib\site-packages\django\contrib\admin\templates\admin\index.html 模板复制到 project1\templates\admin\ 目录,其中 project1< /code> 是您的项目名称。

在复制的文件(即 project1\templates\admin\index.html)中,将行:替换

{% block content %} 
...
{% endblock %}

为:

{% block content %}
<div id="content-main">

{% if app_list %}
    <div class="module">
        <table>
            <caption>App 1</caption>
            <tr>  <th>  <a href="/admin/app1/model1/">Model 1</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="/admin/app1/model2/">Model 2</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="..."                >...</a>      </th>  <td>...</td>                     </tr>
        </table>
    </div>

    <div class="module">
        <table>
            <caption>Authentication and authorization</caption>
            <tr>  <th>  <a href="/admin/auth/user/"  >Users</a>    </th>  <td>List of users</td>           </tr>
            <tr>  <th>  <a href="/admin/auth/group/" >Groups</a>   </th>  <td>List of users' groups</td>   </tr>
        </table>
    </div>
{% else %}
    <p>{% trans "You don't have permission to view or edit anything." %}</p>
{% endif %}

</div>
{% endblock %}  

其中:

  • app1 是带有模型的应用程序的名称,
  • modeliapp1 中第 i 个模型的名称。

如果您在项目中使用模型定义了多个应用程序,则只需在上述 index.html 文件中添加另一个表即可。

因为我们改变了模板,所以我们可以随意改变它的HTML代码。 例如,我们可以添加模型的描述,如上所示。 您还可以恢复添加更改链接 - 我删除了它们,因为我认为它们是多余的。

答案是Dave Kasper 的答案中解决方案的实际演示。

Copy lib\site-packages\django\contrib\admin\templates\admin\index.html template to project1\templates\admin\ directory, where project1 is the name of your project.

In the copied file, i.e. project1\templates\admin\index.html, replace lines:

{% block content %} 
...
{% endblock %}

with:

{% block content %}
<div id="content-main">

{% if app_list %}
    <div class="module">
        <table>
            <caption>App 1</caption>
            <tr>  <th>  <a href="/admin/app1/model1/">Model 1</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="/admin/app1/model2/">Model 2</a>  </th>  <td>Description of model 1</td>  </tr>
            <tr>  <th>  <a href="..."                >...</a>      </th>  <td>...</td>                     </tr>
        </table>
    </div>

    <div class="module">
        <table>
            <caption>Authentication and authorization</caption>
            <tr>  <th>  <a href="/admin/auth/user/"  >Users</a>    </th>  <td>List of users</td>           </tr>
            <tr>  <th>  <a href="/admin/auth/group/" >Groups</a>   </th>  <td>List of users' groups</td>   </tr>
        </table>
    </div>
{% else %}
    <p>{% trans "You don't have permission to view or edit anything." %}</p>
{% endif %}

</div>
{% endblock %}  

where:

  • app1 is the name of your application with models,
  • modeli is the name of i-th model in app1.

If you defined more than one application with models in your project, then simply add another table in the above index.html file.

Because we change the template, we can freely change its HTML code. For example we can add a description of the models as it was shown above. You can also restore Add and Change links - I deleted them since I think they are redundant.

The answer is a practical demonstration of the solution from Dave Kasper's answer.

浅忆流年 2024-07-17 17:58:02

custom_admin.py

from django.contrib.admin import AdminSite


class CustomAdminSite(AdminSite):
    def get_urls(self):
        urls = super(MyAdminSite, self).get_urls()
        return urls

    def get_app_list(self, request):
        app_dict = self._build_app_dict(request)
        ordered_app_list = []

        if app_dict:
            # TODO: change this dict
            admin_ordering = {
                'app1': ('Model1', 'Model2'),
                'app2': ('Model7', 'Model4'),
                'app3': ('Model3',),
            }

            ordered_app_list = []
            for app_key in admin_ordering:
                app = app_dict[app_key]
                app_ordered_models = []
                for model_name in admin_ordering[app_key]:
                    for model in app_dict[app_key]['models']:
                        if model['object_name'] == model_name:
                            app_ordered_models.append(model)
                            break

                app['models'] = app_ordered_models
                ordered_app_list.append(app)

        return ordered_app_list

admin_site = CustomAdminSite()

urls.py

from custom_admin import admin_site

urlpatterns = [
    path('admin/', admin_site.urls),
]

custom_admin.py

from django.contrib.admin import AdminSite


class CustomAdminSite(AdminSite):
    def get_urls(self):
        urls = super(MyAdminSite, self).get_urls()
        return urls

    def get_app_list(self, request):
        app_dict = self._build_app_dict(request)
        ordered_app_list = []

        if app_dict:
            # TODO: change this dict
            admin_ordering = {
                'app1': ('Model1', 'Model2'),
                'app2': ('Model7', 'Model4'),
                'app3': ('Model3',),
            }

            ordered_app_list = []
            for app_key in admin_ordering:
                app = app_dict[app_key]
                app_ordered_models = []
                for model_name in admin_ordering[app_key]:
                    for model in app_dict[app_key]['models']:
                        if model['object_name'] == model_name:
                            app_ordered_models.append(model)
                            break

                app['models'] = app_ordered_models
                ordered_app_list.append(app)

        return ordered_app_list

admin_site = CustomAdminSite()

urls.py

from custom_admin import admin_site

urlpatterns = [
    path('admin/', admin_site.urls),
]
仙气飘飘 2024-07-17 17:58:02

将以下代码添加到您的settings.py:

def get_app_list(self, request):
    """
    Return a sorted list of all the installed apps that have been
    registered on this site.
    """
    ordering = {
        # for superuser
        'Group': 1,
        'User': 2,

        # fist app
        'TopMessage': 101,
        'Slider': 102,
        'ProductCategory': 103,
        'Product': 104,
        'ProductPicture': 105,
        
        # 2nd app
        'ProductReview': 201,
        'Promotion': 202,
        'BestSeller': 203,
    }
    app_dict = self._build_app_dict(request)
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    for app in app_list:
        app['models'].sort(key=lambda x: ordering[x['object_name']])

    return app_list


admin.AdminSite.get_app_list = get_app_list

并对排序字典进行更改以匹配您的应用程序和模型。 就是这样。

我的解决方案的好处是,如果用户是超级用户,它将显示“auth”模型。

Add the below code to your settings.py:

def get_app_list(self, request):
    """
    Return a sorted list of all the installed apps that have been
    registered on this site.
    """
    ordering = {
        # for superuser
        'Group': 1,
        'User': 2,

        # fist app
        'TopMessage': 101,
        'Slider': 102,
        'ProductCategory': 103,
        'Product': 104,
        'ProductPicture': 105,
        
        # 2nd app
        'ProductReview': 201,
        'Promotion': 202,
        'BestSeller': 203,
    }
    app_dict = self._build_app_dict(request)
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    for app in app_list:
        app['models'].sort(key=lambda x: ordering[x['object_name']])

    return app_list


admin.AdminSite.get_app_list = get_app_list

And make changes to the ordering dictionary to match your apps and models. That's it.

The benefit of my solution is that it will show the 'auth' models if the user is a superuser.

桃酥萝莉 2024-07-17 17:58:02

默认情况下,Django 按字母顺序对 admin 中的模型进行排序。 因此,事件管理中模型的顺序是 Epic、EventHero、EventVillain、Event

相反,您希望的顺序是

  • EventHero、EventVillain、Epic,然后是事件。

用于呈现管理索引页面的模板是admin/index.html,视图函数是ModelAdmin.index

def index(self, request, extra_context=None):
"""
Display the main admin index page, which lists all of the installed
apps that have been registered in this site.
"""
app_list = self.get_app_list(request)
context = {
    **self.each_context(request),
    'title': self.index_title,
    'app_list': app_list,
    **(extra_context or {}),
}

request.current_app = self.name

return TemplateResponse(request, self.index_template or
    'admin/index.html', context)

方法 get_app_list,设置模型的顺序。:

def get_app_list(self, request):
"""
Return a sorted list of all the installed apps that have been
registered in this site.
"""
app_dict = self._build_app_dict(request)

# Sort the apps alphabetically.
app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

# Sort the models alphabetically within each app.
for app in app_list:
    app['models'].sort(key=lambda x: x['name'])

return app_list

因此,为了设置顺序,我们将 get_app_list 重写为:

class EventAdminSite(AdminSite):
def get_app_list(self, request):
    """
    Return a sorted list of all the installed apps that have been
    registered in this site.
    """
    ordering = {
        "Event heros": 1,
        "Event villains": 2,
        "Epics": 3,
        "Events": 4
    }
    app_dict = self._build_app_dict(request)
    # a.sort(key=lambda x: b.index(x[0]))
    # Sort the apps alphabetically.
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sort the models alphabetically within each app.
    for app in app_list:
        app['models'].sort(key=lambda x: ordering[x['name']])

    return app_list

代码 app['models'].sort( key=lambda x: ordering[x['name']]) 设置固定顺序。 您的应用程序现在看起来像这样。

输入图片此处描述

查看文档< /a>

Django, by default, orders the models in admin alphabetically. So the order of models in Event admin is Epic, EventHero, EventVillain, Event

Instead you want the order to be

  • EventHero, EventVillain, Epic then event.

The template used to render the admin index page is admin/index.html and the view function is ModelAdmin.index.

def index(self, request, extra_context=None):
"""
Display the main admin index page, which lists all of the installed
apps that have been registered in this site.
"""
app_list = self.get_app_list(request)
context = {
    **self.each_context(request),
    'title': self.index_title,
    'app_list': app_list,
    **(extra_context or {}),
}

request.current_app = self.name

return TemplateResponse(request, self.index_template or
    'admin/index.html', context)

The method get_app_list, set the order of the models.:

def get_app_list(self, request):
"""
Return a sorted list of all the installed apps that have been
registered in this site.
"""
app_dict = self._build_app_dict(request)

# Sort the apps alphabetically.
app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

# Sort the models alphabetically within each app.
for app in app_list:
    app['models'].sort(key=lambda x: x['name'])

return app_list

So to set the order we override get_app_list as:

class EventAdminSite(AdminSite):
def get_app_list(self, request):
    """
    Return a sorted list of all the installed apps that have been
    registered in this site.
    """
    ordering = {
        "Event heros": 1,
        "Event villains": 2,
        "Epics": 3,
        "Events": 4
    }
    app_dict = self._build_app_dict(request)
    # a.sort(key=lambda x: b.index(x[0]))
    # Sort the apps alphabetically.
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sort the models alphabetically within each app.
    for app in app_list:
        app['models'].sort(key=lambda x: ordering[x['name']])

    return app_list

The code app['models'].sort(key=lambda x: ordering[x['name']]) sets the fixed ordering. Your app now looks like this.

enter image description here

Check the Documentation

农村范ル 2024-07-17 17:58:02

Settings.py 文件中设置管理中列出的应用程序/模块的显示顺序

设置我的排序列表

ADMIN_ORDERING = [
    ('Your_App1', '*'),
    ('Your_App2', '*'),
]

在 ADMIN_ORDERING 下面创建排序函数

def get_app_list(self, request):
    """
    You Can Set Manually Ordering For Your Apps And Models   

        ADMIN_ORDERING = [
            ('Your_App1', [
                'module_1',
                'module_2'
            ]),
            ('Your_App2', '*'),
        ]
    """

    app_dict = self._build_app_dict(request)

    # Let's start by sorting the apps alphabetically on a list:
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sorting the models alphabetically within each app.
    for app in app_list:
        if app['app_label'] in [el[0] for el in ADMIN_ORDERING]:
            app_list.remove(app)
        else:
            app['models'].sort(key=lambda x: x['name'])

    # Now we order the app list in our defined way in ADMIN_ORDERING (which could be a subset of all apps).
    my_ordered_apps = []
    if app_dict:
        for app_name, object_list in ADMIN_ORDERING:
            app = app_dict[app_name]
            if object_list == '*':
                app['models'].sort(key=lambda x: x['name'])
            else:
                app['models'].sort(key=lambda x: object_list.index(x['object_name']))
            my_ordered_apps.append(app)

        # Now we combine and arrange the 2 lists together
        my_ordered_apps.extend(app_list)

    return my_ordered_apps

# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin
admin.AdminSite.get_app_list = get_app_list

In Settings.py file setting the order in which the apps/modules show up listed on Admin

set my ordering list

ADMIN_ORDERING = [
    ('Your_App1', '*'),
    ('Your_App2', '*'),
]

Creating a sort function below ADMIN_ORDERING

def get_app_list(self, request):
    """
    You Can Set Manually Ordering For Your Apps And Models   

        ADMIN_ORDERING = [
            ('Your_App1', [
                'module_1',
                'module_2'
            ]),
            ('Your_App2', '*'),
        ]
    """

    app_dict = self._build_app_dict(request)

    # Let's start by sorting the apps alphabetically on a list:
    app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())

    # Sorting the models alphabetically within each app.
    for app in app_list:
        if app['app_label'] in [el[0] for el in ADMIN_ORDERING]:
            app_list.remove(app)
        else:
            app['models'].sort(key=lambda x: x['name'])

    # Now we order the app list in our defined way in ADMIN_ORDERING (which could be a subset of all apps).
    my_ordered_apps = []
    if app_dict:
        for app_name, object_list in ADMIN_ORDERING:
            app = app_dict[app_name]
            if object_list == '*':
                app['models'].sort(key=lambda x: x['name'])
            else:
                app['models'].sort(key=lambda x: object_list.index(x['object_name']))
            my_ordered_apps.append(app)

        # Now we combine and arrange the 2 lists together
        my_ordered_apps.extend(app_list)

    return my_ordered_apps

# Covering django.contrib.admin.AdminSite.get_app_list
from django.contrib import admin
admin.AdminSite.get_app_list = get_app_list
挖鼻大婶 2024-07-17 17:58:02

一种相当简单且自包含的方法可以使用装饰器模式以这种方式重新排列您的应用程序和模块:

# admin.py

from django.contrib import admin

def app_resort(func):                                                                                            
    def inner(*args, **kwargs):                                                                                            
        app_list = func(*args, **kwargs)
        # Useful to discover your app and module list:
        #import pprint                                                                                          
        #pprint.pprint(app_list)

        app_sort_key = 'name'
        app_ordering = {
            "APP_NAME1": 1,
            "APP_NAME2": 2,
            "APP_NAME3": 3,
        }

        resorted_app_list = sorted(app_list, key=lambda x: app_ordering[x[app_sort_key]] if x[app_sort_key] in app_ordering else 1000)

        model_sort_key = 'object_name'
        model_ordering = {
            "Model1": 1,
            "Model2": 2,
            "Model3": 3,
            "Model14": 4,
        }
        for app in resorted_app_list:
            app['models'].sort(key=lambda x: model_ordering[x[model_sort_key]] if x[model_sort_key] in model_ordering else 1000)
        return resorted_app_list
    return inner                                                                                            
                   
admin.site.get_app_list = app_resort(admin.site.get_app_list)

此代码仅在顶部对排序字典中定义的键进行排序,而将所有其他键留在底部。
该方法很干净,但它需要在之前执行 get_app_list...当性能很重要并且您有一个很大的 app_list 时,这可能不是一个好主意。

Quite a simple and self contained approach can be using the decorator pattern to resort your app and modules in this way:

# admin.py

from django.contrib import admin

def app_resort(func):                                                                                            
    def inner(*args, **kwargs):                                                                                            
        app_list = func(*args, **kwargs)
        # Useful to discover your app and module list:
        #import pprint                                                                                          
        #pprint.pprint(app_list)

        app_sort_key = 'name'
        app_ordering = {
            "APP_NAME1": 1,
            "APP_NAME2": 2,
            "APP_NAME3": 3,
        }

        resorted_app_list = sorted(app_list, key=lambda x: app_ordering[x[app_sort_key]] if x[app_sort_key] in app_ordering else 1000)

        model_sort_key = 'object_name'
        model_ordering = {
            "Model1": 1,
            "Model2": 2,
            "Model3": 3,
            "Model14": 4,
        }
        for app in resorted_app_list:
            app['models'].sort(key=lambda x: model_ordering[x[model_sort_key]] if x[model_sort_key] in model_ordering else 1000)
        return resorted_app_list
    return inner                                                                                            
                   
admin.site.get_app_list = app_resort(admin.site.get_app_list)

This code sorts at the top only the defined keys in the ordering dict, leaving at the bottom all the other.
The approach is clean but it requires get_app_list to be executed before... which is probably not a good idea when performance is important and you have a large app_list.

夜空下最亮的亮点 2024-07-17 17:58:02

至少,在 Django 管理面板中有 3 种方法可以进行模型排序:


通过更改模型Meta类中的verbose_name_plural

不错的方法,但您会在管理面板中看到数字

class A(models.Model):
    ...
    class Meta:
        verbose_name_plural = "2. A"

class B(models.Model):
    ...
    class Meta:
        verbose_name_plural = "1. B"

通过使用第三方库django-modeladmin-reorder< /a>


它简单快速,但是不是 django-clean 并且这个库非常旧并且被废弃了


通过覆盖默认管理站点方法get_app_list

django-clean 方法,但需要更多的时间来配置

# First of - override the default admin site
# https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#overriding-default-admin-site
# Note that it is project files, not application files!!!

#myproject/admin.py
from django.contrib import admin

class MyAdminSite(admin.AdminSite):
    ...

#myproject/apps.py
from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = "myproject.admin.MyAdminSite"

#myproject/settings.py
INSTALLED_APPS = [
    ...
    #'django.contrib.admin', remove this!
    'myproject.apps.MyAdminConfig',# replaces 'django.contrib.admin'
    ...
]

# The second step - overriding a method

#myproject/admin.py
from django.contrib import admin
from my_app.models import A, B, C# import your models from application

class MyAdminSite(admin.AdminSite):
    def get_app_list(self, request, app_label=None):
        order = [B, A]# place there your first models in order, remaining ones will be after them
        app_list = admin.AdminSite.get_app_list(self, request)
        for app in app_list:
            if app.get('app_label') == 'my_app':# your app's name in apps.py of application
                app["models"].sort(key=lambda x: order.index(x['model']) if x['model'] in order else len(order))

        return app_lis

At least, there are 3 ways to do model ordering in Django admin panel:


By changing verbose_name_plural in Meta class of model

not bad way, but you will see numbers in admin panel

class A(models.Model):
    ...
    class Meta:
        verbose_name_plural = "2. A"

class B(models.Model):
    ...
    class Meta:
        verbose_name_plural = "1. B"

By using third-party library django-modeladmin-reorder

it is simple and fast, but not django-clean as well as this library is very old and abandoned


By overriding the default admin site method get_app_list

django-clean method, but more time expenses to configure

# First of - override the default admin site
# https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#overriding-default-admin-site
# Note that it is project files, not application files!!!

#myproject/admin.py
from django.contrib import admin

class MyAdminSite(admin.AdminSite):
    ...

#myproject/apps.py
from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = "myproject.admin.MyAdminSite"

#myproject/settings.py
INSTALLED_APPS = [
    ...
    #'django.contrib.admin', remove this!
    'myproject.apps.MyAdminConfig',# replaces 'django.contrib.admin'
    ...
]

# The second step - overriding a method

#myproject/admin.py
from django.contrib import admin
from my_app.models import A, B, C# import your models from application

class MyAdminSite(admin.AdminSite):
    def get_app_list(self, request, app_label=None):
        order = [B, A]# place there your first models in order, remaining ones will be after them
        app_list = admin.AdminSite.get_app_list(self, request)
        for app in app_list:
            if app.get('app_label') == 'my_app':# your app's name in apps.py of application
                app["models"].sort(key=lambda x: order.index(x['model']) if x['model'] in order else len(order))

        return app_lis
香橙ぽ 2024-07-17 17:58:02
  1. 在项目setting.py中设置排序列表在
# set ordering list
# app label, model class name
ADMIN_ORDERING = [
    ('auth', []),
    ('APP', [
        'ModelClassA',
        'ModelClassB',
        'ModelClassC',
    ]),
]

  1. utils.py中定义costom get_app_list函数
def get_app_list(self, request):
    app_dict = self._build_app_dict(request)

    app_dict_copy = copy.deepcopy(app_dict)
    # 先按照配置中自定义的顺序排序
    for app_label, object_list in settings.ADMIN_ORDERING:
        app = app_dict_copy.pop(app_label)
        object_dict = {value: idx for idx, value in enumerate(object_list)}
        app['models'].sort(key=lambda x: object_dict.get(x['object_name'], len(object_list)+1))
        yield app

    # 未在配置中声明的app使用默认排序
    app_list = sorted(app_dict_copy.values(), key=lambda x: x['name'].lower())
    for app in app_list:
        app['models'].sort(key=lambda x: x['name'])
        yield app

  1. 在url.py文件中使用
from django.contrib import admin

from .utils.admin import get_app_list


admin.AdminSite.get_app_list = get_app_list

urlpatterns = [
    path('admin/', admin.site.urls),
    # ...
]
  1. set ordering list in project setting.py
# set ordering list
# app label, model class name
ADMIN_ORDERING = [
    ('auth', []),
    ('APP', [
        'ModelClassA',
        'ModelClassB',
        'ModelClassC',
    ]),
]

  1. define costom get_app_list function in utils.py
def get_app_list(self, request):
    app_dict = self._build_app_dict(request)

    app_dict_copy = copy.deepcopy(app_dict)
    # 先按照配置中自定义的顺序排序
    for app_label, object_list in settings.ADMIN_ORDERING:
        app = app_dict_copy.pop(app_label)
        object_dict = {value: idx for idx, value in enumerate(object_list)}
        app['models'].sort(key=lambda x: object_dict.get(x['object_name'], len(object_list)+1))
        yield app

    # 未在配置中声明的app使用默认排序
    app_list = sorted(app_dict_copy.values(), key=lambda x: x['name'].lower())
    for app in app_list:
        app['models'].sort(key=lambda x: x['name'])
        yield app

  1. use in url.py file
from django.contrib import admin

from .utils.admin import get_app_list


admin.AdminSite.get_app_list = get_app_list

urlpatterns = [
    path('admin/', admin.site.urls),
    # ...
]
故笙诉离歌 2024-07-17 17:58:02

这在 Django 4.1 中变得容易多了 :

AdminSite.get_app_list() 方法现在允许更改管理索引页面上应用和模型的顺序。

您可以子类化并重写 此方法 更改返回的应用程序/模型列表的顺序。

This has become a lot easier in Django 4.1:

The AdminSite.get_app_list() method now allows changing the order of apps and models on the admin index page.

You can subclass and override this method to change the order the returned list of apps/models.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文