Определение пользовательского списка приложений на странице индекса администратора django
Я хотел бы указать список настраиваемых приложений, который будет использоваться на странице индекса администратора 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
...
Тогда мой вопрос: как мне закодировать эквивалент первых 2 строк выше в моей локальной копии файла index.html?
Или, в качестве альтернативы, какой исходный файл python должен вставлять эти строки так, чтобы переменная my_app_list была доступна в index.html.
Спасибо заранее.
Фил
Ответы
Ответ 1
Подкласс 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.)
Ответ 2
Если вы не возражаете использовать подкласс django.contrib.admin.site.AdminSite()
, как и ожидалось в случаях, когда вам нужно настроить свой сайт администратора, Я думаю, что это приемлемая идея, переписывающая методы "index" и "app_index" в производном классе. Вы можете сделать заказ, используя два словаря, которые сохраняют порядок объявления объявлений в settings.py и порядок регистрации моделей.
Затем перепишите код оригинала AdminSite().index()
и app_index()
, добавив пользовательские поля порядка ('order'
) в app_list и упорядочивая это поле, несмотря на 'name'
. Это код, исключая app_index()
, который похож на функцию index()
:
class MyAdminSite(AdminSite):
def __init__(self, name='admin', app_name='admin'):
super(MyAdminSite, self).__init__(name, app_name)
# Model registration ordering. It 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-модели, вам, вероятно, понадобится это, где-то в вашем коде (я сделал это в определенном приложении для расширить пользователя информация:
from django.contrib.auth.models import User, Group
from myproject import admin
admin.site.register(User)
admin.site.register(Group)
Ответ 3
После выполнения того, что @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
Ответ 4
Поскольку вы беспокоитесь о заказе, вы можете найти мое решение полезным.
В принципе, я создал фильтр, который перемещает нужные элементы 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]
Фильтры могут быть скованы цепью, поэтому вы можете использовать оба одновременно.
Функции фильтрации не записываются так, чтобы они ускоряли демоны, но этот шаблон не слишком часто отображается по определению.
Ответ 5
app_list = admin.site.get_app_list(context['request'])
применить любой вид на app_list