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?

31
demandé sur Ben James 2008-12-29 20:25:50

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.

11
répondu Dave Kasper 2008-12-29 18:41:12

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.

28
répondu Roberto 2011-03-17 21:56:30

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.

18
répondu Emmanuel 2012-03-08 20:38:20

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.

16
répondu ptronico 2011-10-19 18:33:53

Il y a maintenant un joli paquet Django pour ça:

Https://pypi.python.org/pypi/django-modeladmin-reorder

13
répondu Jdruiter 2015-09-14 19:56:47

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 %}
5
répondu Rick Westera 2015-05-15 02:37:34

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/

3
répondu Fatih 2012-01-18 14:04:15

Je l'ai ajouté au trac de Django:

Http://code.djangoproject.com/ticket/9928

2
répondu Rui Ferreira 2009-12-06 23:13:56

Si vous utilisez Suit pour L'AdminSite, vous pouvez personnaliser le menu en utilisant la balise .

2
répondu melbic 2013-11-06 13:12:55

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

2
répondu 林伟雄 2018-06-19 18:20:42

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>&nbsp;</td>
            {% endif %}

            {% if model.admin_url %}
                <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
            {% else %}
                <td>&nbsp;</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

1
répondu Jamie Counsell 2016-12-04 19:35:15

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.

0
répondu Jeff 2008-12-29 18:17:19

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.

0
répondu Vasil 2009-07-16 23:48:17