Come sovrascrivere ed estendere i modelli di amministrazione di Django di base?


126

Come faccio a sovrascrivere un modello di amministrazione (ad esempio admin / index.html) mentre allo stesso tempo lo estendo (vedi https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -un-admin-template )?

Primo: so che questa domanda è stata posta e risposta in precedenza (vedi Django: sovrascrivere ed estendere un modello di app ) ma poiché la risposta dice che non è direttamente applicabile se stai utilizzando il caricatore di modelli app_directories (che è la maggior parte dei tempo).

La mia soluzione alternativa attuale è creare copie ed estenderle invece di estenderle direttamente dai modelli di amministrazione. Funziona benissimo ma è davvero fonte di confusione e aggiunge ulteriore lavoro quando i modelli di amministrazione cambiano.

Potrebbe pensare a qualche tag di estensione personalizzato per i modelli, ma non voglio reinventare la ruota se esiste già una soluzione.

Nota a margine: qualcuno sa se questo problema verrà risolto da Django stesso?


1
Copiare i modelli di amministrazione, estenderli e sovrascrivere / aggiungere blocchi è il flusso di lavoro più efficiente, sebbene non ottimale, dato lo stato attuale di Django. Non ho visto nessun altro modo per fare quello che stai cercando di fare in tre anni di lavoro con esso :)
Brandon

Beh, non so se questa sia una buona cosa o no, ma almeno persone come te sono arrivate alla stessa conclusione. È bello sentire. :)
Semmel

Risposte:


101

Aggiornamento :

Leggi la documentazione per la tua versione di Django. per esempio

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

Risposta originale del 2011:

Ho avuto lo stesso problema circa un anno e mezzo fa e ho trovato un simpatico caricatore di modelli su djangosnippets.org che lo rende facile. Ti consente di estendere un modello in un'app specifica, dandoti la possibilità di creare il tuo admin / index.html che estende il modello admin / index.html dall'app di amministrazione. Come questo:

{% 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 %}

Ho fornito un esempio completo su come utilizzare questo caricatore di modelli in un post del blog sul mio sito web.


18
Per riferimento; lo snippet in questione è stato convertito in un'app django ed è disponibile in PyPi (pip / easy_install) come django-apptemplates: pypi.python.org/pypi/django-apptemplates
Romløk

9
Giusto per essere esplicito al 100%: la soluzione di cui sopra NON FUNZIONERÀ PIÙ per le versioni recenti di Django (almeno 1.4), poiché una delle funzioni utilizzate dallo script è svalutata. Puoi trovare la fonte aggiornata qui
OldTinfoil

2
Nota che con Django 1.8 funzionerà ancora, ma l'installazione deve essere eseguita in un modo speciale (vedi app_namespace.Loader setup come esempio). django-app-namespace-template-loader è anche un'alternativa funzionante a django-apptemplatesse un giorno potrebbe smettere di funzionare.
Peterino

Questa risposta era molto buona per le versioni precedenti di Django. Ma per ora, un'altra risposta di Cheng è più pertinente. stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar

70

Poiché Django 1.8 è la versione corrente, non è necessario creare un collegamento simbolico, copiare admin / modelli nella cartella del progetto o installare middleware come suggerito dalle risposte sopra. Ecco cosa fare:

  1. creare la seguente struttura ad albero (consigliato dalla documentazione ufficiale )

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

Nota : la posizione di questo file non è importante. Puoi inserirlo nella tua app e funzionerà ancora. Finché la sua posizione può essere scoperta da django. La cosa più importante è che il nome del file HTML deve essere lo stesso del nome del file HTML originale fornito da django.

  1. Aggiungi questo percorso del modello al tuo 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. Identifica il nome e il blocco che desideri sostituire. Questo viene fatto esaminando la directory admin / templates di django. Sto usando virtualenv, quindi per me il percorso è qui:

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

In questo esempio, voglio modificare il modulo per l'aggiunta di un nuovo utente. Il modello responsabile per questa visualizzazione è change_form.html . Apri change_form.html e trova il {% block%} che desideri estendere.

  1. Nel tuo change_form.html , scrivi qualcosa come questo:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. Carica la tua pagina e dovresti vedere le modifiche


Non è ancora sufficiente per estendere il template principale "index.html", senza copiare tutti i blocchi. Una soluzione è scriverne alcuni ../nel percorso "exetends" e specificare il percorso originale più univoco {% extends "../../admin/templates/admin/index.html" %}. link alla risposta
hynekcer

1
Penso che in TEMPLATES dovremmo usare 'DIRS': [os.path.join (BASE_DIR, 'templates')],
Raul Reyes

Questo è il tipo di thread che illustra perfettamente il difetto in SO. Un framework si aggiorna e la domanda non è più rilevante, è infatti un deterrente dal percorso corretto. Ottima risposta qui. Ragazzi RTFM.
Derek Adair

Grazie per questa risposta. Ad eccezione di "La posizione di questo file non è importante", tutto ha funzionato alla grande.
Jaswanth Manigundan

54

se è necessario sovrascrivere il admin/index.html, è possibile impostare il parametro index_template del AdminSite.

per esempio

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

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

e inserisci il tuo modello in <appname>/templates/admin/my_custom_index.html


5
Brillante! In questo modo puoi fare {% extends "admin/index.html" %}da my_custom_index.html e avere quel riferimento al modello di amministrazione di django senza copiarlo. Grazie.
mattmc3

3
@Semmel dovrebbe contrassegnarlo come la risposta corretta, poiché è l'approccio più semplice che utilizza le funzionalità di django integrate e non richiede l'utilizzo di caricatori di modelli personalizzati.
MrColes


9

La risposta di Chengs è corretta, tuttavia secondo i documenti di amministrazione non tutti i modelli di amministrazione possono essere sovrascritti in questo modo: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Modelli che possono essere sovrascritti per app o modello

Non tutti i modelli in contrib / admin / templates / admin possono essere sovrascritti per app o per modello. Quanto segue può:

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

Per quei modelli che non possono essere sovrascritti in questo modo, puoi comunque sovrascriverli per l'intero progetto. Basta posizionare la nuova versione nella directory modelli / admin . Ciò è particolarmente utile per creare pagine 404 e 500 personalizzate

Ho dovuto sovrascrivere il login.html dell'amministratore e quindi ho dovuto mettere il modello sovrascritto in questa struttura di cartelle:

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

(senza la sottocartella myapp nell'amministratore) Non ho abbastanza reputazione per commentare il post di Cheng, questo è il motivo per cui ho dovuto scrivere questa come nuova risposta.


Grazie per il feedback hyneker, spero che la mia risposta sia più chiara e più diretta al punto ora.
matyas

Sì, è utile sapere che i modelli possono essere personalizzati a livello di progetto anche se alcuni di essi possono essere modificati opzionalmente a livello di applicazione.
hynekcer

5

Il modo migliore per farlo è inserire i modelli di amministrazione di Django nel tuo progetto. Quindi i tuoi modelli sarebbero presenti templates/adminmentre i modelli di amministrazione Django di serie sarebbero presenti template/django_admin. Quindi, puoi fare qualcosa di simile a quanto segue:

templates / admin / change_form.html

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

Your stuff here

Se sei preoccupato di mantenere aggiornati i modelli stock, puoi includerli con svn externals o simili.


Usare svn externals è un'ottima idea. Il problema che questo introduce è che tutti i miei traduttori tradurranno tutti quei modelli (perché makemessages raccoglierà le stringhe di traduzione da tutti i modelli di amministrazione), il che aggiunge molto lavoro extra se lavori con più lingue. Forse c'è un modo per escludere quei modelli da makemessages?
Semmel

Usa l' --ignoreargomento con makemessages. Vedi: docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt

Penso che l'altra risposta si adatti meglio alle mie esigenze. Ma mi piace la tua soluzione e penso che sia una buona alternativa se non vuoi scherzare con i tuoi caricatori di modelli.
Semmel

5

Non sono riuscito a trovare una singola risposta o una sezione nei documenti ufficiali di Django che contenessero tutte le informazioni di cui avevo bisogno per sovrascrivere / estendere i modelli di amministrazione predefiniti, quindi sto scrivendo questa risposta come guida completa, sperando che sarebbe utile per altri in futuro.

Assumendo la struttura standard del progetto Django:

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/

Ecco cosa devi fare:

  1. In mysite/admin.py, crea una sottoclasse di 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()

    Assicurati di importare custom_admin_sitenella admin.pydelle tue app e registrare i tuoi modelli su di essa per visualizzarli sul tuo sito di amministrazione personalizzato (se lo desideri).

  2. In mysite/apps.py, crea una sottoclasse di AdminConfige imposta default_sitesu admin.CustomAdminSitedal passaggio precedente:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. In mysite/settings.pysostituire django.admin.sitea INSTALLED_APPScon apps.CustomAdminConfig(l'amministratore personalizzato app config dal passaggio precedente).

  4. In mysite/urls.py, sostituisci admin.site.urlsdall'URL dell'amministratore acustom_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. Crea il modello che desideri modificare nella tua templatesdirectory, mantenendo la struttura di directory dei modelli di amministrazione Django predefinita come specificato nei documenti . Ad esempio, se stavi modificando admin/index.html, crea il file templates/admin/index.html.

    Tutti i modelli esistenti possono essere modificati in questo modo e i loro nomi e strutture possono essere trovati nel codice sorgente di Django .

  6. Ora puoi sovrascrivere il modello scrivendolo da zero o estenderlo e quindi sovrascrivere / estendere blocchi specifici.

    Ad esempio, se si desidera mantenere tutto così com'è ma si desidera sovrascrivere il contentblocco (che nella pagina dell'indice elenca le app ei relativi modelli che si sono registrati), aggiungere quanto segue a templates/admin/index.html:

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

    Per preservare il contenuto originale di un blocco, aggiungi {{ block.super }}dove desideri che venga visualizzato il contenuto originale:

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

    Puoi anche aggiungere stili e script personalizzati modificando i blocchi extrastylee extrahead.


hai una fonte o documentazione su questo?
Mary

A parte i due riferimenti che ho aggiunto al punto 5, no, non ho altro.
Faheel

1

Sono d'accordo con Chris Pratt. Ma penso che sia meglio creare il collegamento simbolico alla cartella Django originale in cui si trovano i modelli di amministrazione:

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

e come puoi vedere dipende dalla versione di python e dalla cartella in cui è installato Django. Quindi in futuro o su un server di produzione potrebbe essere necessario modificare il percorso.


0

Questo sito aveva una soluzione semplice che funzionava con la mia configurazione Django 1.7.

PRIMO: crea un collegamento simbolico denominato admin_src nella directory template / del tuo progetto ai modelli Django installati. Per me su Dreamhost usando un virtualenv, i miei modelli di amministrazione Django "sorgente" erano in:

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

SECONDO: Crea un amministratore directory in templates /

Quindi il template / directory del mio progetto ora assomigliava a questo:

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

TERZO: Nella tua nuova directory template / admin / crea un file base.html con questo contenuto:

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

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

IL QUARTO: Aggiungi il tuo admin favicon-admin.ico nella tua cartella img root statica.

Fatto. Facile.


0

per l'indice dell'app aggiungi questa riga a un file py comune come url.py

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

per l'indice del modulo dell'app: aggiungi questa riga a admin.py

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

per l'elenco delle modifiche: aggiungi questa riga alla classe admin:

change_list_template = "servers/servers_changelist.html"

per il modello di modulo del modulo dell'app: aggiungi questa riga alla tua classe amministratore

change_form_template = "servers/server_changeform.html"

ecc. e trova altri nelle stesse classi di moduli dell'amministratore


-1

Puoi usare django-overextends , che fornisce l'ereditarietà del modello circolare per Django.

Proviene dal Mezzanine CMS, da dove Stephen lo ha estratto in un'estensione Django autonoma.

Ulteriori informazioni si trovano in "Overriding vs Extending Templates" (http: /mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) all'interno dei documenti di Mezzanine.

Per approfondimenti, guarda il blog di Stephens "Circular Template Inheritance for Django" (http: /blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

E in Google Gruppi la discussione (https: /groups.google.com/forum / #! Topic / mezzanine-users / sUydcf_IZkQ) che ha avviato lo sviluppo di questa funzione.

Nota:

Non ho la reputazione di aggiungere più di 2 link. Ma penso che i collegamenti forniscano informazioni di base interessanti. Quindi ho appena lasciato una barra dopo "http (s):". Forse qualcuno con una migliore reputazione può riparare i collegamenti e rimuovere questa nota.


A partire da Django 1.9, questo progetto non è stato rilevante, il manutentore semplicemente non lo fa pubblicità, vedere code.djangoproject.com/ticket/15053 e github.com/stephenmcd/django-overextends/pull/37 . Per avere il controllo completo di quale app viene caricato un modello, ci sono django-apptemplates e django-app-namespace-template-loader, che sono entrambi ancora rilevanti se si desidera estendere da un'app all'altra.
Benjaoming il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.