La commande admin.ModelAdmin objets dans Django Admin
Disons que j'ai mon application pizza avec des classes de garniture et de Pizza et qu'elles s'affichent dans Django Admin comme ceci:
PizzaApp
-
Toppings >>>>>>>>>> Add / Change
Pizzas >>>>>>>>>> Add / Change
Mais je les veux comme ceci:
PizzaApp
-
Pizzas >>>>>>>>>> Add / Change
Toppings >>>>>>>>>> Add / Change
Comment puis-je configurer cela dans mon admin.py?
13 réponses
Ceci est en fait couvert tout en bas de Partie 2 du tutoriel Django.
Voici la section pertinente:
Personnaliser la page d'index admin
Sur une note similaire, vous pouvez personnalisez l'apparence et la convivialité du Page d'accueil de Django admin.
Par défaut, il affiche toutes les applications dans INSTALLED_APPS qui ont été enregistré avec l'application admin, dans l'ordre alphabétique. Vous pouvez faire d'importantes des modifications à la disposition. Après tout, l'index est probablement la page la plus importante de l'administrateur, et il devrait être facile de utiliser.
Le modèle à personnaliser est admin / index.HTML. (Faites la même chose avec admin / base_site.html dans le précédent section -- copie par défaut répertoire de votre modèle personnalisé répertoire.) De modifier le fichier, et vous aurez voir il utilise une variable de modèle appelée app_list. Cette variable contient tous les installé Django app. Au lieu d'utiliser cela, vous pouvez coder en dur des liens vers pages d'administration spécifiques à l'objet dans quelle que soit la façon dont vous pensez est le meilleur.
Une solution de contournement que vous pouvez essayer est de peaufiner votre models.py comme suit:
class Topping(models.Model):
.
.
.
class Meta:
verbose_name_plural = "2. Toppings"
class Pizza(models.Model):
.
.
.
class Meta:
verbose_name_plural = "1. Pizzas"
Je ne sais pas si c'est contre les meilleures pratiques de django mais cela fonctionne (testé avec django trunk).
Bonne chance!
PS: désolé si cette réponse a été postée trop tard mais cela peut aider les autres dans des situations similaires futures.
J'ai finalement réussi à le faire grâce à cet extrait Django , il vous suffit d'être conscient du paramètre ADMIN_REORDER
:
ADMIN_REORDER = (
('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
('app2', ('App2Model1', 'App2Model2')),
)
app1
ne doit pas être préfixé par le nom du projet, c'est à dire utiliser app1
au lieu de mysite.app1
.
Si vous voulez résoudre ce problème en 10 secondes, utilisez simplement des espaces dans verbose_name_plural, par exemple:
class Topping(models.Model):
class Meta:
verbose_name_plural = " Toppings" # 2 spaces
class Pizza(models.Model):
class Meta:
verbose_name_plural = " Pizzas" # 1 space
Bien sûr, ce n'est pas ellegant mais peut fonctionner pendant un certain temps avant que nous obtenions une meilleure solution.
Voici L'extrait utilisé par Emmanuel, mis à jour pour Django 1.8:
Dans 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 ""
Dans settings.py:
ADMIN_REORDER = (
('app1', ('App1Model1', 'App1Model2', 'App1Model3')),
('app2', ('App2Model1', 'App2Model2')),
)
(Insérez vos propres noms d'Applications ici. Admin placera les applications ou les modèles manquants à la fin de la liste, tant que vous listez au moins deux modèles dans chaque application.)
Dans votre copie 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 %}
Un petit code snipped, appelé 'Django Admin Index Custom App & Model Ordering' peut également être utilisé. L'extrait résout le problème avec seulement 3 édition simple.
Voici un coup d'oeil aux détails. http://djangosnippets.org/snippets/2613/
Réponse en juin 2018
Cette réponse est similaire à l'idée de Vasil
J'ai essayé de résoudre des problèmes similaires, et puis j'ai vu ces le fragment.
J'ai fait quelques modifications basées sur ce clip. Le code est le suivant.
# 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
...
Notez que la liste tri utilisé dans cette fonction de tri contient le tri de toutes les applications et les modules dans le système. Si vous n'en avez pas besoin, concevez la fonction de tri selon la vôtre besoin.
Cela fonctionne très bien sur Django 2.0
Je cherchais une solution simple où je pourrais commander les applications par leur nom dans le panneau d'admin. Je suis venu avec la balise de modèle suivante:
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
Ensuite, remplacez simplement templates/admin/index.html
et ajoutez cette balise de modèle:
{% 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 %}
Puis personnalisé le APP_ORDER
dans settings.py:
APP_ORDER = [
'app1',
'app2',
# and so on...
]
Cela fonctionne très bien sur Django 1.10
Ceci est juste un coup de couteau sauvage dans l'obscurité, mais y a-t-il une chance que l'ordre dans lequel vous appelez admin.site.registre(, ) peut déterminer l'ordre d'affichage? En fait, je doute que cela fonctionne parce que je crois que Django maintient un registre des objets Model -> ModelAdmin implémentés en tant que dictionnaire Python standard, qui ne maintient pas l'ordre des itérations.
Si cela ne se comporte pas comme vous le souhaitez, vous pouvez toujours jouer avec la source django / contrib / admin. Si vous avez besoin de maintenir l'ordre d'itération, vous pouvez remplacer l'objet _registry dans la classe AdminSite (in admin/sites.py) avec un UserDict ou DictMixin qui maintient l'ordre d'insertion des clés. (Mais veuillez prendre ce conseil avec un grain de sel, car je n'ai jamais fait ce genre de changements moi-même et je ne fais que deviner comment Django itère sur la collection D'objets ModelAdmin. Je pense que django/contrib/admin/sites.py est l'endroit à regarder pour ce code, cependant, et les méthodes AdminSite class et register() et index() en particulier sont ce que vous voulez.)
Évidemment, la chose la plus agréable ici serait une option simple pour vous de spécifier dans votre propre /admin.py module. Je suis sûr que c'est le genre de réponse que vous espérez recevoir. Je ne suis pas sûr si ces options existent, cependant.
Ma solution était de faire des sous-classes de django.contrib.admin.site.AdminSite et django.contrib.admin.option.ModelAdmin .
Je l'ai fait pour pouvoir afficher un titre plus descriptif pour chaque application et ordonner l'apparence des modèles dans chaque application. J'ai donc un dict dans mon settings.py qui mappe app_labels aux noms descriptifs et à l'ordre dans lequel ils doivent apparaître, les modèles sont ordonnés par un champ ordinal que je fournis dans chaque ModelAdmin lorsque je les enregistre avec l'administrateur site.
Bien Que faire vos propres sous-classes D'AdminSite et ModelAdmin soit encouragé dans les documents, ma solution ressemble à un hack laid à la fin.