queryset - Ordenar objetos admin.ModelAdmin en Django Admin
django admin template (12)
Digamos que tengo mi aplicación de pizza con las clases Topping y Pizza y se muestran en Django Admin de esta manera:
PizzaApp
-
Toppings >>>>>>>>>> Add / Change
Pizzas >>>>>>>>>> Add / Change
Pero los quiero así:
PizzaApp
-
Pizzas >>>>>>>>>> Add / Change
Toppings >>>>>>>>>> Add / Change
¿Cómo configuro eso en mi admin.py?
Esto es solo una puñalada salvaje en la oscuridad, pero ¿hay alguna posibilidad de que el orden en el que llamas admin.site.register (<Model class>, <ModelAdmin class>) pueda determinar el orden de visualización? En realidad, dudo que eso funcione porque creo que Django mantiene un registro del Modelo -> objetos ModelAdmin implementados como un diccionario Python estándar, que no mantiene el orden de iteración.
Si eso no se comporta de la manera que desea, siempre puede jugar con la fuente en django / contrib / admin. Si necesita que se mantenga el orden de iteración, puede reemplazar el objeto _registry en la clase AdminSite (en admin / sites.py) con un UserDict o DictMixin que mantenga el orden de inserción de las claves. (Pero por favor, tome este consejo con un grano de sal, ya que nunca he hecho este tipo de cambios yo mismo y solo estoy adivinando cómo Django itera sobre la colección de objetos ModelAdmin. Creo que django / contrib Sin embargo, /admin/sites.py es el lugar para buscar este código, y la clase AdminSite y los métodos register () e index () en particular son los que usted desea.
Obviamente, lo más agradable aquí sería una opción simple para que usted especifique en su propio módulo /admin.py. Estoy seguro de que ese es el tipo de respuesta que espera recibir. Aunque no estoy seguro si esas opciones existen.
Esto está cubierto en la parte inferior de la Parte 2 del Tutorial de Django .
Aquí está la sección relevante:
Personaliza la página de índice de administrador
En una nota similar, es posible que desee personalizar la apariencia de la página de índice de administración de Django.
De forma predeterminada, muestra todas las aplicaciones en INSTALLED_APPS que se han registrado con la aplicación de administración, en orden alfabético. Es posible que desee realizar cambios importantes en el diseño. Después de todo, el índice es probablemente la página más importante del administrador, y debería ser fácil de usar.
La plantilla para personalizar es admin / index.html. (Haga lo mismo que con admin / base_site.html en la sección anterior; cópielo del directorio predeterminado al directorio de plantillas personalizadas). Edite el archivo y verá que usa una variable de plantilla llamada lista_aplicaciones. Esa variable contiene todas las aplicaciones de Django instaladas. En lugar de usar eso, puede codificar los enlaces a las páginas de administración específicas del objeto de la manera que crea que es mejor.
Mi solución fue crear subclases de django.contrib.admin.sites.AdminSite y django.contrib.admin.options.ModelAdmin.
Hice esto para poder mostrar un título más descriptivo para cada aplicación y ordenar el aspecto de los modelos en cada aplicación. Así que tengo un dict en mi settings.py que asigna las etiquetas de la aplicación a los nombres descriptivos y al orden en que deben aparecer, los modelos están ordenados por un campo ordinal que proporciono en cada ModelAdmin cuando los registro en el sitio de administración.
Aunque se alienta a hacer sus propias subclases de AdminSite y ModelAdmin en los documentos, al final mi solución parece un truco feo.
Lo agregué al tracto de Django:
Una solución alternativa que puede probar es ajustar su models.py de la siguiente manera:
class Topping(models.Model):
.
.
.
class Meta:
verbose_name_plural = "2. Toppings"
class Pizza(models.Model):
.
.
.
class Meta:
verbose_name_plural = "1. Pizzas"
No estoy seguro si va en contra de las mejores prácticas de django, pero funciona (probado con el tronco de django).
¡Buena suerte!
PD: lo siento si esta respuesta se publicó demasiado tarde, pero puede ayudar a otros en situaciones similares en el futuro.
Si quiere resolver esto en 10 segundos solo use espacios en verbose_name_plural, por ejemplo:
class Topping(models.Model):
class Meta:
verbose_name_plural = " Toppings" # 2 spaces
class Pizza(models.Model):
class Meta:
verbose_name_plural = " Pizzas" # 1 space
Por supuesto, no es elegante, pero puede funcionar por un tiempo antes de que obtengamos una mejor solución.
También se puede usar un pequeño código recortado, que se denomina ''Solicitud personalizada de índice y administración de índice de Django'' . El fragmento resuelve el problema con solo 3 simples ediciones.
Aquí echa un vistazo a los detalles. http://djangosnippets.org/snippets/2613/
Eventualmente logré hacerlo gracias a este fragmento de Django , solo debes tener en cuenta la configuración ADMIN_REORDER
:
ADMIN_REORDER = (
(''app1'', (''App1Model1'', ''App1Model2'', ''App1Model3'')),
(''app2'', (''App2Model1'', ''App2Model2'')),
)
app1
no debe estar precedido del nombre del proyecto, es decir, use app1
lugar de mysite.app1
.
Si está usando Suit para AdminSite, puede hacer la personalización del menú usando la etiqueta del menú .
Aquí está el fragmento que Emmanuel usó, actualizado para Django 1.8:
En 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 ""
En settings.py:
ADMIN_REORDER = (
(''app1'', (''App1Model1'', ''App1Model2'', ''App1Model3'')),
(''app2'', (''App2Model1'', ''App2Model2'')),
)
(inserte sus propios nombres de aplicaciones aquí. El administrador colocará las aplicaciones o modelos faltantes al final de la lista, siempre y cuando incluya al menos dos modelos en cada aplicación).
En tu copia de 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 %}
Ahora hay un buen paquete de Django para eso:
Estaba buscando una solución simple en la que pudiera ordenar las aplicaciones por su nombre en el panel de administración. Se me ocurrió la siguiente etiqueta de plantilla:
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
Luego, simplemente anule las templates/admin/index.html
y agregue esa etiqueta de plantilla:
{% 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 %}
Luego personalizó APP_ORDER
en settings.py:
APP_ORDER = [
''app1'',
''app2'',
# and so on...
]
Funciona muy bien en Django 1.10