Comment remplacer et étendre les modèles d'administration de base de Django?

126

Comment remplacer un modèle d'administrateur (par exemple, admin / index.html) tout en l'étendant (voir https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -un-modèle-d'administration )?

Premièrement - je sais que cette question a déjà été posée et répondue (voir Django: Remplacer ET étendre un modèle d'application ) mais comme la réponse l'indique, elle n'est pas directement applicable si vous utilisez le chargeur de modèle app_directories (qui est la plupart des temps).

Ma solution de contournement actuelle consiste à faire des copies et à les étendre au lieu d'étendre directement à partir des modèles d'administration. Cela fonctionne très bien mais c'est vraiment déroutant et ajoute du travail supplémentaire lorsque les modèles d'administration changent.

Il pourrait penser à une étiquette d'extension personnalisée pour les modèles, mais je ne veux pas réinventer la roue s'il existe déjà une solution.

En passant: est-ce que quelqu'un sait si ce problème sera résolu par Django lui-même?

Semmel
la source
1
Copier les modèles d'administration, les étendre et remplacer / ajouter des blocs est le flux de travail le plus efficace, mais pas optimal étant donné l'état actuel de Django. Je n'ai vu aucune autre façon de faire ce que vous essayez de faire en trois ans de travail avec lui :)
Brandon
Eh bien - je ne sais pas si c'est une bonne chose ou non, mais au moins des gens comme vous sont arrivés à la même conclusion. Ça fait plaisir à entendre. :)
Semmel

Réponses:

101

Mise à jour :

Lisez la documentation de votre version de Django. par exemple

https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-overriding -modèles

Réponse originale de 2011:

J'ai eu le même problème il y a environ un an et demi et j'ai trouvé un bon chargeur de modèle sur djangosnippets.org qui facilite les choses . Il vous permet d'étendre un modèle dans une application spécifique, vous donnant la possibilité de créer votre propre admin / index.html qui étend le modèle admin / index.html de l'application d'administration. Comme ça:

{% extends "admin:admin/index.html" %}

{% block sidebar %}
    {{block.super}}
    <div>
        <h1>Extra links</h1>
        <a href="https://stackoverflow.com/admin/extra/">My extra link</a>
    </div>
{% endblock %}

J'ai donné un exemple complet sur la façon d'utiliser ce chargeur de modèles dans un article de blog sur mon site Web.

heyman
la source
18
Pour référence; l'extrait de code en question a été converti en une application django et est disponible dans PyPi (pip / easy_install) sous le nom de django-apptemplates: pypi.python.org/pypi/django-apptemplates
Romløk
9
Pour être explicite à 100%: la solution ci-dessus NE FONCTIONNE PLUS pour les versions récentes de Django (au moins 1.4), car l'une des fonctions utilisées par le script est dépréciée. Vous pouvez trouver la source mise à jour ici
OldTinfoil
2
Notez qu'avec Django 1.8, cela fonctionnera toujours, mais la configuration doit être faite d'une manière spéciale (voir la configuration de app_namespace.Loader comme exemple). django-app-namespace-template-loader est également une alternative de travail pour savoir django-apptemplatess'il peut cesser de fonctionner un jour.
Peterino du
Cette réponse était très bonne pour les anciennes versions de Django. Mais à partir de maintenant, une autre réponse de Cheng est plus pertinente. stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar
70

Quant à Django 1.8 étant la version actuelle, il n'est pas nécessaire de créer un lien symbolique, de copier l'admin / templates dans votre dossier de projet ou d'installer des middlewares comme suggéré par les réponses ci-dessus. Voici ce qu'il faut faire:

  1. créer l'arborescence suivante (recommandée par la documentation officielle )

    your_project
         |-- your_project/
         |-- myapp/
         |-- templates/
              |-- admin/
                  |-- myapp/
                      |-- change_form.html  <- do not misspell this

Remarque : l'emplacement de ce fichier n'est pas important. Vous pouvez le mettre dans votre application et cela fonctionnera toujours. Tant que son emplacement peut être découvert par django. Ce qui est plus important, c'est que le nom du fichier HTML doit être le même que le nom du fichier HTML d'origine fourni par django.

  1. Ajoutez ce chemin de modèle à votre settings.py :

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- add this line
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
  2. Identifiez le nom et le bloc que vous souhaitez remplacer. Ceci est fait en regardant dans le répertoire admin / templates de django. J'utilise virtualenv, donc pour moi, le chemin est ici:

    ~/.virtualenvs/edge/lib/python2.7/site-packages/django/contrib/admin/templates/admin

Dans cet exemple, je souhaite modifier le formulaire d'ajout d'un nouvel utilisateur. Le modèle responsable de cette vue est change_form.html . Ouvrez le fichier change_form.html et recherchez le {% block%} que vous souhaitez étendre.

  1. Dans votre change_form.html , écrivez quelque chose comme ceci:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. Chargez votre page et vous devriez voir les changements

Cheng
la source
Ce n'est toujours pas suffisant pour étendre le modèle principal "index.html", sans copier tous les blocs. Une solution consiste à en écrire ../sur le chemin "exetends" et à spécifier le chemin d'origine plus unique {% extends "../../admin/templates/admin/index.html" %}. lien vers la réponse
hynekcer
1
Je pense que dans TEMPLATES, nous devrions utiliser 'DIRS': [os.path.join (BASE_DIR, 'templates')],
Raul Reyes
C'est le type de fil qui illustre parfaitement la faille du SO. Un cadre se met à jour et la question n'est plus d'actualité, c'est en fait un élément dissuasif de la bonne voie. Excellente réponse ici. Enfants RTFM.
Derek Adair
Merci pour cette réponse. Sauf pour "L'emplacement de ce fichier n'est pas important.", Tout a très bien fonctionné.
Jaswanth Manigundan
54

si vous devez remplacer le admin/index.html, vous pouvez définir le paramètre index_template du AdminSite.

par exemple

# urls.py
...
from django.contrib import admin

admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()

et placez votre modèle dans <appname>/templates/admin/my_custom_index.html

gingembre
la source
5
Brillant! Faire cela vous permet de faire ensuite à {% extends "admin/index.html" %}partir de my_custom_index.html et d'avoir cette référence le modèle d'administrateur django sans le copier. Je vous remercie.
mattmc3
3
@Semmel devrait marquer cela comme la bonne réponse, car c'est l'approche la plus simple qui utilise les fonctionnalités intégrées de django et ne nécessite pas l'utilisation de chargeurs de modèles personnalisés.
MrColes
17

Avec django1.5 (au moins), vous pouvez définir le modèle que vous souhaitez utiliser pour unmodeladmin

voir https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#custom-template-options

Vous pouvez faire quelque chose comme

class Myadmin(admin.ModelAdmin):
    change_form_template = 'change_form.htm'

En change_form.htmlétant un simple modèle html s'étendant admin/change_form.html(ou pas si vous voulez le faire à partir de zéro)

maazza
la source
9

La réponse de Chengs est correcte, mais selon la documentation de l'administrateur, tous les modèles d'administration ne peuvent pas être écrasés de cette façon: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Modèles qui peuvent être remplacés par application ou modèle

Tous les modèles de contrib / admin / templates / admin ne peuvent pas être remplacés par application ou par modèle. Les éléments suivants peuvent:

app_index.html
change_form.html
change_list.html
delete_confirmation.html
object_history.html

Pour les modèles qui ne peuvent pas être remplacés de cette manière, vous pouvez toujours les remplacer pour l'ensemble de votre projet. Placez simplement la nouvelle version dans votre répertoire templates / admin . Ceci est particulièrement utile pour créer des pages 404 et 500 personnalisées

J'ai dû écraser le login.html de l'administrateur et donc mettre le modèle écrasé dans cette structure de dossiers:

your_project
 |-- your_project/
 |-- myapp/
 |-- templates/
      |-- admin/
          |-- login.html  <- do not misspell this

(sans le sous-dossier myapp dans l'admin) Je n'ai pas assez de réputation pour commenter le post de Cheng, c'est pourquoi j'ai dû écrire ceci comme nouvelle réponse.

matyas
la source
Merci pour les commentaires hyneker J'espère que ma réponse est plus claire et plus directe maintenant.
matyas
Oui, il est utile de savoir que les modèles peuvent être personnalisés au niveau du projet même si certains d'entre eux peuvent éventuellement être modifiés au niveau de l'application.
hynekcer
5

La meilleure façon de le faire est de mettre les modèles d'administration Django dans votre projet. Ainsi, vos modèles seraient en place templates/adminalors que les modèles d'administration Django en stock seraient par exemple template/django_admin. Ensuite, vous pouvez faire quelque chose comme ce qui suit:

templates / admin / change_form.html

{% extends 'django_admin/change_form.html' %}

Your stuff here

Si vous souhaitez garder les modèles de stock à jour, vous pouvez les inclure avec svn externals ou similaire.

Chris Pratt
la source
Utiliser svn externals est une excellente idée. Le problème que cela introduit est que tous mes traducteurs vont traduire tous ces modèles (car makemessages collectera les chaînes de traduction de tous les modèles d'administration), ce qui ajoute beaucoup de travail supplémentaire si vous travaillez avec plusieurs langues. Peut-être existe-t-il un moyen d'exclure ces modèles de makemessages?
Semmel
Utilisez l' --ignoreargument avec makemessages. Voir: docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt
Je pense que l'autre réponse correspond mieux à mon besoin. Mais j'aime votre solution et je pense que c'est une bonne alternative si vous ne voulez pas vous embêter avec vos chargeurs de modèles.
Semmel du
5

Je n'ai pas trouvé une seule réponse ou une section dans la documentation officielle de Django qui contenait toutes les informations dont j'avais besoin pour remplacer / étendre les modèles d'administrateur par défaut, j'écris donc cette réponse comme un guide complet, en espérant que ce serait utile pour d’autres à l’avenir.

En supposant la structure de projet Django standard:

mysite-container/         # project container directory
    manage.py
    mysite/               # project package
        __init__.py
        admin.py
        apps.py
        settings.py
        urls.py
        wsgi.py
    app1/
    app2/
    ...
    static/
    templates/

Voici ce que vous devez faire:

  1. Dans mysite/admin.py, créez une sous-classe de AdminSite:

    from django.contrib.admin import AdminSite
    
    
    class CustomAdminSite(AdminSite):
        # set values for `site_header`, `site_title`, `index_title` etc.
        site_header = 'Custom Admin Site'
        ...
    
        # extend / override admin views, such as `index()`
        def index(self, request, extra_context=None):
            extra_context = extra_context or {}
    
            # do whatever you want to do and save the values in `extra_context`
            extra_context['world'] = 'Earth'
    
            return super(CustomAdminSite, self).index(request, extra_context)
    
    
    custom_admin_site = CustomAdminSite()

    Assurez-vous d'importer custom_admin_sitedans le admin.pyde vos applications et d'enregistrer vos modèles dessus pour les afficher sur votre site d'administration personnalisé (si vous le souhaitez).

  2. Dans mysite/apps.py, créez une sous-classe de AdminConfiget définissez sur default_siteà admin.CustomAdminSitepartir de l'étape précédente:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. En mysite/settings.py, remplacer django.admin.sitedans INSTALLED_APPSavec apps.CustomAdminConfig(votre config app admin personnalisé à partir de l'étape précédente).

  4. Dans mysite/urls.py, remplacez admin.site.urlsde l'URL d'administration parcustom_admin_site.urls

    from .admin import custom_admin_site
    
    
    urlpatterns = [
        ...
        path('admin/', custom_admin_site.urls),
        # for Django 1.x versions: url(r'^admin/', include(custom_admin_site.urls)),
        ...
    ]
  5. Créez le modèle que vous souhaitez modifier dans votre templatesrépertoire, en conservant la structure de répertoire par défaut des modèles d'administration Django comme spécifié dans la documentation . Par exemple, si vous modifiez admin/index.html, créez le fichier templates/admin/index.html.

    Tous les modèles existants peuvent être modifiés de cette manière, et leurs noms et structures peuvent être trouvés dans le code source de Django .

  6. Vous pouvez maintenant remplacer le modèle en l'écrivant à partir de zéro ou l'étendre, puis remplacer / étendre des blocs spécifiques.

    Par exemple, si vous vouliez tout conserver tel contentquel, mais que vous vouliez remplacer le bloc (qui sur la page d'index répertorie les applications et leurs modèles que vous avez enregistrés), ajoutez ce qui suit à templates/admin/index.html:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
    {% endblock %}

    Pour conserver le contenu original d'un bloc, ajoutez {{ block.super }}là où vous voulez que le contenu original soit affiché:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
      {{ block.super }}
    {% endblock %}

    Vous pouvez également ajouter des styles et des scripts personnalisés en modifiant les blocs extrastyleet extrahead.

Faheel
la source
avez-vous une source ou une documentation à ce sujet?
Mary
Hormis les deux références que j'ai ajoutées au point 5, non, je n'ai rien d'autre.
Faheel le
1

Je suis d'accord avec Chris Pratt. Mais je pense qu'il est préférable de créer le lien symbolique vers le dossier Django d'origine où se trouvent les modèles d'administration:

ln -s /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/ templates/django_admin

et comme vous pouvez le voir, cela dépend de la version de python et du dossier dans lequel Django est installé. Ainsi, à l'avenir ou sur un serveur de production, vous devrez peut-être modifier le chemin.

James May
la source
0

Ce site avait une solution simple qui fonctionnait avec ma configuration Django 1.7.

PREMIER: Créez un lien symbolique nommé admin_src dans le répertoire template / de votre projet vers vos templates Django installés. Pour moi sur Dreamhost utilisant un virtualenv, mes modèles d'administration Django «source» étaient dans:

~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/admin/templates/admin

DEUXIÈME: Créez un répertoire d' administration dans les modèles /

Le template / répertoire de mon projet ressemblait maintenant à ceci:

/templates/
   admin
   admin_src -> [to django source]
   base.html
   index.html
   sitemap.xml
   etc...

TROISIEME: Dans votre nouveau répertoire template / admin /, créez un fichier base.html avec ce contenu:

{% extends "admin_src/base.html" %}

{% block extrahead %}
<link rel='shortcut icon' href='{{ STATIC_URL }}img/favicon-admin.ico' />
{% endblock %}

QUATRIÈME: Ajoutez votre admin favicon-admin.ico dans votre dossier racine statique img.

Terminé. Facile.

mitchf
la source
0

pour l'index d'application, ajoutez cette ligne à un fichier py commun comme url.py

admin.site.index_template = 'admin/custom_index.html'

pour l'index du module d'application: ajoutez cette ligne à admin.py

admin.AdminSite.app_index_template = "servers/servers-home.html"

pour la liste des modifications: ajoutez cette ligne à la classe d'administration:

change_list_template = "servers/servers_changelist.html"

pour le modèle de formulaire de module d'application: ajoutez cette ligne à votre classe d'administration

change_form_template = "servers/server_changeform.html"

etc. et en trouver d'autres dans les mêmes classes de module d'administration

Saurabh Chandra Patel
la source
-1

Vous pouvez utiliser django-overextends , qui fournit un héritage de modèle circulaire pour Django.

Il provient du CMS Mezzanine , d'où Stephen l'a extrait dans une extension Django autonome.

Vous trouverez plus d'informations dans "Overriding vs Extending Templates" (http: /mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) dans la documentation Mezzanine.

Pour en savoir plus, consultez le blog Stephens "L'héritage de modèle circulaire pour Django" (http: /blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

Et dans Google Groupes la discussion (https: /groups.google.com/forum / #! Topic / mezzanine-users / sUydcf_IZkQ) qui a démarré le développement de cette fonctionnalité.

Remarque:

Je n'ai pas la réputation d'ajouter plus de 2 liens. Mais je pense que les liens fournissent des informations de base intéressantes. J'ai donc laissé une barre oblique après "http (s):". Peut-être que quelqu'un de meilleure réputation pourra réparer les liens et supprimer cette note.

Henri Hulski
la source
Depuis Django 1.9, ce projet n'est plus pertinent, le mainteneur ne le publie tout simplement pas, voir code.djangoproject.com/ticket/15053 et github.com/stephenmcd/django-overextends/pull/37 . Pour prendre le contrôle complet de l'application à partir de laquelle un modèle est chargé, il existe django-apptemplates et django-app-namespace-template-loader, qui sont tous deux toujours pertinents si vous souhaitez étendre d'une application à une autre.
benjaoming le