Jak zastąpić i rozszerzyć podstawowe szablony administracyjne Django?

127

Jak nadpisać szablon administratora (np. Admin / index.html), jednocześnie go rozszerzając (patrz https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -an-admin-template )?

Po pierwsze - wiem, że to pytanie zostało już zadane i udzielono na nie odpowiedzi (zobacz Django: Przesłanianie ORAZ rozszerzanie szablonu aplikacji ), ale jak mówi odpowiedź, nie ma to bezpośredniego zastosowania, jeśli używasz modułu ładującego szablony app_directories (który jest większością czas).

Moje obecne obejście polega na tworzeniu kopii i rozszerzaniu ich zawartości zamiast rozszerzania bezpośrednio z szablonów administratora. Działa to świetnie, ale jest naprawdę mylące i wymaga dodatkowej pracy, gdy zmieniają się szablony administratora.

Może wymyślić jakiś niestandardowy tag rozszerzenia dla szablonów, ale nie chcę wymyślać koła na nowo, jeśli istnieje już rozwiązanie.

Na marginesie: czy ktoś wie, czy ten problem zostanie rozwiązany przez samo Django?

Semmel
źródło
1
Kopiowanie szablonów administratora, rozszerzanie ich i nadpisywanie / dodawanie bloków jest najbardziej wydajnym, choć nie optymalnym przepływem pracy, biorąc pod uwagę obecny stan Django. Nie widziałem innego sposobu, aby zrobić to, co próbujesz zrobić przez trzy lata pracy z tym :)
Brandon.
Cóż - nie wiem, czy to dobrze, czy nie, ale przynajmniej ludzie tacy jak ty doszli do tego samego wniosku. Dobrze to słyszeć. :)
Semmel

Odpowiedzi:

101

Aktualizacja :

Przeczytaj dokumentację swojej wersji Django. na przykład

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

Oryginalna odpowiedź z 2011 r .:

Miałem ten sam problem około półtora roku temu i znalazłem na djangosnippets.org niezły program ładujący szablony, który to ułatwia. Pozwala na rozszerzenie szablonu w określonej aplikacji, dając możliwość tworzenia własnego admin / index.html, który rozszerza szablon admin / index.html z aplikacji administratora. Lubię to:

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

Podałem pełny przykład, jak używać tego modułu ładującego szablony w poście na moim blogu .

Cześć, stary
źródło
18
Na przykład; fragment, o którym mowa, został przekonwertowany na aplikację django i jest dostępny w PyPi (pip / easy_install) jako django-apptemplates: pypi.python.org/pypi/django-apptemplates
Romløk
9
Żeby być w 100% jednoznacznym: powyższe rozwiązanie NIE BĘDZIE JUŻ DZIAŁAŁO dla ostatnich wersji Django (co najmniej 1.4), ponieważ jedna z funkcji, z których korzysta skrypt, jest amortyzowana. Zaktualizowane źródło można znaleźć tutaj
OldTinfoil
2
Zauważ, że z Django 1.8 to nadal będzie działać, ale konfiguracja musi być przeprowadzona w specjalny sposób (patrz konfiguracja app_namespace.Loader jako przykład). Program ładujący django-app-namespace-template-loader jest również działającą alternatywą, django-apptemplatesjeśli pewnego dnia przestanie działać.
Peterino,
Ta odpowiedź była bardzo dobra dla starszych wersji Django. Ale na razie inna odpowiedź Chenga jest bardziej odpowiednia. stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar
70

Ponieważ Django 1.8 jest obecną wersją, nie ma potrzeby tworzenia linków symbolicznych, kopiowania admin / templates do folderu projektu lub instalowania oprogramowania pośredniego, jak sugerują powyższe odpowiedzi. Oto co należy zrobić:

  1. utwórz następującą strukturę drzewa (zalecane przez oficjalną dokumentację )

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

Uwaga : lokalizacja tego pliku nie jest ważna. Możesz umieścić go w swojej aplikacji i nadal będzie działać. O ile django może odkryć jego lokalizację. Co ważniejsze, nazwa pliku HTML musi być taka sama, jak oryginalna nazwa pliku HTML dostarczona przez django.

  1. Dodaj tę ścieżkę szablonu do swojego 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. Zidentyfikuj nazwę i blok, który chcesz zastąpić. Odbywa się to poprzez zaglądanie do katalogu admin / templates django. Używam virtualenv, więc dla mnie ścieżka jest tutaj:

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

W tym przykładzie chcę zmodyfikować formularz dodawania nowego użytkownika. Szablon responsiblve dla tego widoku to change_form.html . Otwórz change_form.html i znajdź {% block%}, który chcesz rozszerzyć.

  1. W swoim change_form.html napisz coś takiego:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. Załaduj swoją stronę i powinieneś zobaczyć zmiany

Cheng
źródło
To wciąż za mało do rozszerzenia głównego szablonu „index.html” bez kopiowania wszystkich bloków. Rozwiązaniem jest zapisanie niektórych ../ścieżek „exetends” i określenie bardziej unikalnej ścieżki oryginalnej {% extends "../../admin/templates/admin/index.html" %}. link do odpowiedzi
hynekcer
1
Myślę, że w TEMPLATES powinniśmy używać „DIRS”: [os.path.join (BASE_DIR, 'templates')],
Raul Reyes,
To rodzaj nici, który doskonale ilustruje wadę SO. Ramy są aktualizowane, a pytanie nie jest już aktualne, w rzeczywistości odstrasza od właściwej ścieżki. Świetna odpowiedź tutaj. RTFM kids.
Derek Adair
Dzięki za tę odpowiedź. Z wyjątkiem „Lokalizacja tego pliku nie jest ważna”, wszystko działało świetnie.
Jaswanth Manigundan
54

jeśli chcesz nadpisać admin/index.html, możesz ustawić parametr index_template plikuAdminSite .

na przykład

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

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

i umieść szablon w <appname>/templates/admin/my_custom_index.html

imbir
źródło
5
Znakomity! Dzięki temu możesz zrobić to {% extends "admin/index.html" %}z my_custom_index.html i odwołać się do szablonu administratora django bez kopiowania go. Dziękuję Ci.
mattmc3
3
@Semmel powinien oznaczyć to jako poprawną odpowiedź, ponieważ jest to najprostsze podejście, które wykorzystuje wbudowane funkcje django i nie wymaga używania niestandardowych programów ładujących szablony.
MrColes,
17

Za pomocą django(przynajmniej) 1.5 możesz zdefiniować szablon, którego chcesz użyć dla konkretnegomodeladmin

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

Możesz zrobić coś takiego

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

Z change_form.htmlbycia prosty szablon html rozszerzenie admin/change_form.html(lub nie, jeśli chcesz to zrobić od podstaw)

maazza
źródło
9

Odpowiedź Chengsa jest poprawna, jednak zgodnie z dokumentacją administracyjną nie każdy szablon administratora można nadpisać w ten sposób: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Szablony, które mogą zostać zastąpione przez aplikację lub model

Nie każdy szablon w contrib / admin / templates / admin może zostać zastąpiony przez aplikację lub model. Następujące mogą:

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

W przypadku szablonów, których nie można zastąpić w ten sposób, nadal można je zastąpić w całym projekcie. Po prostu umieść nową wersję w katalogu szablonów / administratora . Jest to szczególnie przydatne do tworzenia niestandardowych stron 404 i 500

Musiałem nadpisać login.html administratora i dlatego musiałem umieścić nadpisany szablon w tej strukturze folderów:

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

(bez podfolderu myapp w panelu administracyjnym) Nie mam wystarczającej reputacji, aby komentować post Chenga, dlatego musiałem napisać to jako nową odpowiedź.

matyas
źródło
Dziękuję za opinię hyneker. Mam nadzieję, że moja odpowiedź jest teraz jaśniejsza i bardziej trafna.
matyas
Tak, warto wiedzieć, że szablony można dostosowywać na poziomie projektu, nawet jeśli niektóre z nich można opcjonalnie zmienić na poziomie aplikacji.
hynekcer
5

Najlepszym sposobem na to jest umieszczenie szablonów administratora Django wewnątrz projektu. Więc twoje szablony będą dostępne, templates/adminpodczas gdy standardowe szablony administracyjne Django będą na przykład template/django_admin. Następnie możesz wykonać następujące czynności:

szablony / admin / change_form.html

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

Your stuff here

Jeśli martwisz się o aktualizowanie szablonów magazynowych, możesz dołączyć je do zewnętrznych elementów svn lub podobnych.

Chris Pratt
źródło
Używanie zewnętrznych elementów svn to świetny pomysł. Problem, który to wprowadza, polega na tym, że wszyscy moi tłumacze będą tłumaczyć wszystkie te szablony (ponieważ makemessages będzie zbierać ciągi tłumaczeń ze wszystkich szablonów administratora), co dodaje dużo dodatkowej pracy, jeśli pracujesz z wieloma językami. Może istnieje sposób na wykluczenie tych szablonów z makemessages?
Semmel,
Użyj --ignoreargumentu z makemessages. Zobacz: docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt.
Myślę, że druga odpowiedź lepiej pasuje do moich potrzeb. Ale podoba mi się twoje rozwiązanie i uważam, że to dobra alternatywa, jeśli nie chcesz bawić się programami ładującymi szablony.
Semmel,
5

Nie mogłem znaleźć ani jednej odpowiedzi ani sekcji w oficjalnych dokumentach Django, które zawierałyby wszystkie informacje potrzebne do zastąpienia / rozszerzenia domyślnych szablonów administratora, więc piszę tę odpowiedź jako kompletny przewodnik, mając nadzieję, że będzie to pomocne dla innych w przyszłości.

Zakładając standardową strukturę projektu 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/

Oto, co musisz zrobić:

  1. W programie mysite/admin.pyutwórz podklasę 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()

    Upewnij się, że import custom_admin_sitew admin.pyswoich aplikacjach i zarejestrować swoje modele na nim, aby wyświetlić je na swojej niestandardowej stronie administratora (jeśli chcesz).

  2. W programie mysite/apps.pyutwórz podklasę AdminConfigi ustaw default_sitena admin.CustomAdminSitez poprzedniego kroku:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. W mysite/settings.pywymienić django.admin.sitew INSTALLED_APPSprzy apps.CustomAdminConfig(niestandardowego administratora app config z poprzedniego etapu).

  4. W mysite/urls.py, zamień admin.site.urlsadres URL administratora nacustom_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. Utwórz szablon, który chcesz zmodyfikować w swoim templateskatalogu, zachowując domyślną strukturę katalogów szablonów administratora Django, jak określono w dokumentacji . Na przykład, jeśli modyfikowałeś admin/index.html, utwórz plik templates/admin/index.html.

    W ten sposób można modyfikować wszystkie istniejące szablony, a ich nazwy i struktury można znaleźć w kodzie źródłowym Django .

  6. Teraz możesz albo nadpisać szablon, pisząc go od zera, albo rozszerzyć go, a następnie nadpisać / rozszerzyć określone bloki.

    Na przykład, jeśli chcesz zachować wszystko tak, jak jest, ale chcesz przesłonić contentblok (który na stronie indeksu zawiera listę zarejestrowanych aplikacji i ich modeli), dodaj do templates/admin/index.html:

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

    Aby zachować oryginalną zawartość bloku, dodaj w {{ block.super }}dowolnym miejscu, w którym ma być wyświetlana oryginalna zawartość:

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

    Możesz także dodać własne style i skrypty, modyfikując bloki extrastylei extrahead.

Faheel
źródło
czy masz źródło lub dokumentację na ten temat?
Mary
Oprócz dwóch odniesień, które dodałem w punkcie 5, nie, nie mam nic innego.
Faheel
1

Zgadzam się z Chrisem Prattem. Ale myślę, że lepiej jest utworzyć dowiązanie symboliczne do oryginalnego folderu Django, w którym szablony administratora są umieszczane w:

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

i jak widać, zależy to od wersji Pythona i folderu, w którym zainstalowano Django. Dlatego w przyszłości lub na serwerze produkcyjnym może być konieczna zmiana ścieżki.

James May
źródło
0

Ta strona miała proste rozwiązanie, które działało z moją konfiguracją Django 1.7.

PO PIERWSZE: Utwórz dowiązanie symboliczne o nazwie admin_src w katalogu / szablonie projektu do zainstalowanych szablonów Django. Dla mnie na Dreamhost przy użyciu virtualenv moje „źródłowe” szablony administracyjne Django były w:

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

PO DRUGIE: Utwórz katalog administratora w szablonach /

Więc szablon / katalog mojego projektu wyglądał teraz następująco:

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

TRZECIE: W swoim nowym katalogu / admin / stwórz plik base.html z następującą zawartością:

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

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

CZWARTE: Dodaj administratora favicon-admin.ico do statycznego folderu głównego img.

Gotowe. Łatwo.

mitchf
źródło
0

dla indeksu aplikacji dodaj tę linię do jakiegoś wspólnego pliku py, takiego jak url.py

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

dla indeksu modułu aplikacji: dodaj tę linię do admin.py

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

dla listy zmian: dodaj tę linię do klasy administratora:

change_list_template = "servers/servers_changelist.html"

dla szablonu formularza modułu aplikacji: dodaj ten wiersz do klasy administratora

change_form_template = "servers/server_changeform.html"

itp. i znajdź inne w tych samych klasach modułów administratora

Saurabh Chandra Patel
źródło
-1

Możesz użyć django-overextends , który zapewnia cykliczne dziedziczenie szablonów dla Django.

Pochodzi z Mezzanine CMS, skąd Stephen wyodrębnił go do samodzielnego rozszerzenia Django.

Więcej informacji można znaleźć w temacie „Szablony zastępujące a rozszerzające” (http: /mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) w dokumentacji Mezzanine.

Bardziej szczegółowe informacje można znaleźć na blogu Stephens „Circular Template Inheritance for Django” (http: /blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

A w Grupach dyskusyjnych Google dyskusja (https: /groups.google.com/forum / #! Topic / mezzanine-users / sUydcf_IZkQ), która zapoczątkowała rozwój tej funkcji.

Uwaga:

Nie mam reputacji, aby dodać więcej niż 2 linki. Myślę jednak, że linki zawierają interesujące informacje ogólne. Pominąłem więc ukośnik po „http (s):”. Może ktoś o lepszej reputacji może naprawić linki i usunąć tę notatkę.

Henri Hulski
źródło
Od Django 1.9 ten projekt nie był istotny, opiekun po prostu go nie reklamuje, zobacz code.djangoproject.com/ticket/15053 i github.com/stephenmcd/django-overextends/pull/37 . Aby przejąć pełną kontrolę nad tym, z której aplikacji jest ładowany szablon, istnieją django-apptemplates i django-app-namespace-template-loader, które są nadal istotne, jeśli chcesz rozszerzyć z jednej aplikacji do drugiej.
benjaoming