2012-01-17 15 views
10

Me gustaría definir una lista de aplicaciones personalizada para usar en la página de índice de administración de django porque quiero que las aplicaciones se muestren en un orden específico, en lugar del orden alfabético predeterminado. Al navegar por varias publicaciones de SO, parece que aún no es posible declarar el orden de aplicación deseado en ninguno de los lugares obvios (por ejemplo, admin.py, models.py).Definición de una lista de aplicaciones personalizada en la página de índice de administración de django

Ahora, puedo ver que el archivo index.html de la administración de Django contiene la siguiente declaración:

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

así que me gustaría cambiar esta opción para utilizar un objeto de lista personalizada llamada, por ejemplo, my_app_list. En Python que lo haría esta lo largo de las siguientes líneas:

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 
    ... 

Mi pregunta entonces es, ¿cómo codificar el equivalente de las 2 primeras líneas de arriba en mi copia local del archivo index.html?

O, como alternativa, en qué archivo de origen python debería insertar esas líneas para que la variable my_app_list esté disponible en index.html.

Gracias de antemano.

Phil

+0

Esto funcionó bien para mí => http://djangosnippets.org/snippets/2613/ – Serafeim

+0

@Serafeim Gracias por esto. ¡Lo probaré una vez que haya resuelto los diversos problemas de Python/Django de 32 bits frente a los de 64 bits que han surgido como resultado de la actualización de nuestro servidor! – Phil

Respuesta

8

Subclase django.contrib.admin.site.AdminSite(). Reemplazar el método .index(), y hacer algo como esto:

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) 

se crea una instancia de esta subclase con my_admin_site = MyAdminSite(), adjuntar sus modelos a ella (con la habitual my_admin_site.register()), y adjuntarlo a la URLconf; Deberias hacer eso.

(no he probado esto, yo estoy basando esto en mi lectura de la fuente AdminSite.)

+0

Gracias por esta sugerencia, no he tenido la oportunidad de probarlo todavía. Informaré cuando lo haya hecho. Aunque parece una opción viable. – Phil

+1

el fragmento de código que ha sugerido tiene sentido, pero no está claro dónde debería residir. Comencé a colocarlo dentro del módulo admin.py para una de mis aplicaciones, pero me di cuenta de que no tiene sentido porque es una pieza de código de todo el sitio, y no específica de una aplicación en particular. Además, no estaba seguro de cómo o por qué uno modificaría el URLconf para usar este código ya que no he cambiado las URL. – Phil

+0

Finalmente me puse a prueba con este método. Lamentablemente no pude hacer que funcione. En primer lugar, la función get_app() devuelve un objeto de módulo, en lugar del objeto dict esperado por index.html (¡debería haber leído la fuente!). En segundo lugar, al instanciar una subclase de AdminSite y registrar sus propias aplicaciones, parece que pierde visibilidad de otras aplicaciones (como Auth) que están registradas contra el objeto de sitio de administración predeterminado. Por lo tanto, no pude encontrar una manera de configurar las cosas de modo que tanto las aplicaciones predeterminadas como sus propias aplicaciones aparezcan juntas en la vista de índice de administración. – Phil

0

Después de hacer lo @AdminKG dijo copiar el archivo index.html a la raíz del directorio admin que necesita para crear dentro del directorio templates que declaró en usted setting.py.

si tiene una lógica de ordenación clara para app_list puede implementarla en el método .index() de su subclase AdminSite. De lo contrario, necesitará codificar la lista de aplicaciones en index.html.

Para acceder a algo en su plantilla de acaba de tenerlo en su contexto, algo así:

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 
    ) 

Ahora apps de objetos están disponibles para utilizar en su index.htm

+0

"De lo contrario, necesitará codificar la lista de aplicaciones en index.html". De hecho, esa es la naturaleza misma de mi pregunta. ¿Cómo obtengo, en mi archivo index.html local, un identificador para un objeto de la aplicación dado que solo sé su nombre? Puedo usar la función get_app ('myappname') en el código python. ¿Hay una función equivalente en el lenguaje de plantillas de django? Tal vez estoy ladrando completamente el árbol equivocado! – Phil

+0

@Phil Actualicé la respuesta – tikider

2

Si no le importa usar una subclase de django.contrib.admin.site.AdminSite(), como se espera en los casos en que necesita customize your admin site, creo que es una idea factible reescribir los métodos "index" y "app_index" en la clase derivada. Puede hacer pedidos personalizados utilizando dos diccionarios que almacenan el orden de declaración de la aplicación en settings.py y el orden de registro de los modelos. A continuación, vuelva a escribir el código del AdminSite().index() original y app_index(), agregue un orden personalizado de campos ('order') en la lista_de_aplicaciones y ordene por este campo a pesar de 'name'.Este es el código, excluyendo app_index(), que es similar a index() función:

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) 

Si utiliza AdminSite costumbre y desea incluir modelos Auth es probable que tenga esto, en algún lugar de su código (lo hice en una específica aplicación para extend user information:.

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

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

Puesto que usted está preocupado acerca de la orden, usted puede encontrar mi solución útil
Básicamente, he creado un filtro, que mueve los elementos deseados de app_list al principio

.
@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 

Sin embargo, si es necesario eliminar algunos elementos que puede utilizar:

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

Los filtros pueden ser encadenados, para que pueda utilizar ambos al mismo tiempo.
Las funciones de filtrado no están escritas de la manera que los haría acelerar demonios, pero esta plantilla no se representa con demasiada frecuencia por definición.

Cuestiones relacionadas