在django管理员索引页面中定义自定义app_list

时间:2012-01-17 11:20:43

标签: django django-admin

我想在django的管理索引页面中定义一个自定义应用程序列表,因为我希望以特定顺序显示应用程序,而不是默认的字母顺序。通过各种SO帖子进行搜索似乎还不可能在任何明显的地方声明所需的应用程序顺序(例如admin.py,models.py)。

现在,我可以看到django admin的index.html文件包含以下语句:

{% for app in app_list %}
   # do stuff with the app object

所以我想更改它以使用名为my_app_list的自定义列表对象。在python中,我将按以下方式执行此操作:

from django.db.models import get_app
my_app_list = [get_app('myapp1'), get_app('myapp2'), ..., get_app('django.contrib.auth')]
for app in my_app_list
   ...

我的问题是,如何将上面前两行的等效代码编入index.html文件的本地副本?

或者,或者,我应该将哪些python源文件插入到index.html中的变量my_app_list中。

提前致谢。

菲尔

5 个答案:

答案 0 :(得分:8)

子类django.contrib.admin.site.AdminSite()。覆盖.index()方法,并执行以下操作:

class MyAdminSite(django.contrib.admin.site.AdminSite):
    def index(self, request, extra_context=None):
        if extra_context is None:
            extra_context = {}
        extra_context["app_list"] = get_app_list_in_custom_order()
        return super(MyAdminSite, self).index(request, extra_context)

使用my_admin_site = MyAdminSite()实例化此子类的实例,将模型附加到它(使用通常的my_admin_site.register()),并将其附加到URLconf;应该这样做。

(我没有试过这个,我的基础是我对AdminSite源码的阅读。)

答案 1 :(得分:2)

如果您不介意使用django.contrib.admin.site.AdminSite()的子类,正如您需要customize your admin site时所预期的那样,我认为重写“index”和“app_index”方法是可行的。派生类。您可以使用两个词典进行自定义排序,这两个词典在settings.py和模型的注册顺序中存储应用程序声明顺序。 然后重写原始AdminSite().index()app_index()的代码,在app_list中添加自定义订单字段('order'),并按此字段排序'name'。这是代码app_index(),与index()函数类似:

class MyAdminSite(AdminSite):

    def __init__(self, name='admin', app_name='admin'):
        super(MyAdminSite, self).__init__(name, app_name)

        # Model's registration ordering. It's not necessary to
        # categorize by app.
        self._registry_ord = {}

        # App ordering determined by declaration
        self._app_ord = { 'auth' : 0 }
        app_position = 1
        for app in settings.INSTALLED_APPS:
            self._app_ord[app] = app_position
            app_position += 1

    def register(self, model_or_iterable, admin_class=None, **options):
        super(MyAdminSite, self).register(model_or_iterable, admin_class, **options)

        if isinstance(model_or_iterable, ModelBase):
            model_or_iterable = [model_or_iterable]
        for model in model_or_iterable:
            if model in self._registry:
                if self._registry_ord:
                    self._registry_ord[model._meta.object_name] = max(self._registry_ord.values()) + 1 
                else:
                    self._registry_ord[model._meta.object_name] = 1

    @never_cache
    def index(self, request, extra_context=None):
        """
        Displays the main admin index page, which lists all of the installed
        apps that have been registered in this site.
        """
        app_dict = {}
        user = request.user
        for model, model_admin in self._registry.items():
            app_label = model._meta.app_label
            has_module_perms = user.has_module_perms(app_label)

            if has_module_perms:
                perms = model_admin.get_model_perms(request)

                # Check whether user has any perm for this module.
                # If so, add the module to the model_list.
                if True in perms.values():
                    info = (app_label, model._meta.module_name)
                    model_dict = {
                        'name': capfirst(model._meta.verbose_name_plural),
                        'perms': perms,
                        'order': self._registry_ord[model._meta.object_name]
                    }
                    if perms.get('change', False):
                        try:
                            model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info, current_app=self.name)
                        except NoReverseMatch:
                            pass
                    if perms.get('add', False):
                        try:
                            model_dict['add_url'] = reverse('admin:%s_%s_add' % info, current_app=self.name)
                        except NoReverseMatch:
                            pass
                    if app_label in app_dict:
                        app_dict[app_label]['models'].append(model_dict)
                    else:
                        app_dict[app_label] = {
                            'name': app_label.title(),
                            'app_url': reverse('admin:app_list', kwargs={'app_label': app_label}, current_app=self.name),
                            'has_module_perms': has_module_perms,
                            'models': [model_dict],
                            'order': self._app_ord[app_label],
                        }

        # Sort the apps alphabetically.
        app_list = app_dict.values()
        app_list.sort(key=lambda x: x['order'])

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

        context = {
            'title': _('Site administration'),
            'app_list': app_list,
        }
        context.update(extra_context or {})
        return TemplateResponse(request, [
            self.index_template or 'admin/index.html',
        ], context, current_app=self.name)

如果您使用自定义AdminSite并且想要包含Auth模型,则可能需要在代码中的某处(我在特定应用中将其设置为extend user information

from django.contrib.auth.models import User, Group
from myproject import admin

admin.site.register(User)
admin.site.register(Group)

答案 2 :(得分:0)

执行@AdminKG之后所说的将index.html文件复制到您需要在admin目录中创建的templates目录的根目录setting.py目录app_list

如果您有.index()的明确排序逻辑,则可以在AdminSite的子类的index.html方法中实现它。否则,您需要在def index(self, request, extra_context=None): context = { 'app1':get_app('myappname'), 'app2': get_app('mysecondappname'), # ... } context.update(extra_context or {}) context_instance = template.RequestContext(request, current_app=self.name) return render_to_response(self.index_template or 'admin/terminal_index.html', context, context_instance=context_instance ) 上对应用列表进行硬编码。

要访问模板中的某些内容,只需将其放在您的上下文中,就像这样:

index.htm

现在可以在{{1}}

上使用应用对象了

答案 3 :(得分:0)

由于您担心订单,因此您可以找到有用的解决方案 基本上,我创建了一个过滤器,它将app_list的所需元素移动到开头。

@register.filter
def put_it_first(value, arg):
    '''The filter shifts specified items in app_list to the top,
    the syntax is: LIST_TO_PROCESS|put_it_first:"1st_item[;2nd_item...]"
    '''
    def _cust_sort(x):
        try:
            return arg.index(x['name'].lower())
        except ValueError:
            return dist
    arg = arg.split(';')
    arg = map(unicode.lower, arg)
    dist = len(arg) + 1
    value.sort(key=_cust_sort)
    return value

但是,如果您需要删除一些可以使用的元素:

@register.filter
def remove_some(value, arg):
    '''The filter removes specified items from app_list,
    the syntax is: LIST_TO_PROCESS|remove_some:"1st_item[;2nd_item...]"
    '''
    arg = arg.split(';')
    arg = map(unicode.lower, arg)
    return [v for v in value if v['name'].lower() not in arg]

过滤器可以链接,因此您可以同时使用这两种过滤器 过滤函数的编写方式不会使它们加速恶魔,但是这个模板的定义并不常见。

答案 4 :(得分:0)

app_list = admin.site.get_app_list(context['request'])

在app_list上应用任何种类