Como substituir e estender os modelos básicos de administração do Django?

125

Como substituir um modelo de administrador (por exemplo, admin / index.html) e ao mesmo tempo estendê-lo (consulte https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -um-admin-template )?

Primeiro - eu sei que essa pergunta já foi feita e respondida antes (consulte Django: Substituindo E estendendo um modelo de aplicativo ), mas como a resposta diz que não é diretamente aplicável se você estiver usando o carregador de modelos app_directories (que é a maioria dos Tempo).

Minha solução atual é fazer cópias e estender a partir delas, em vez de estender diretamente dos modelos de administrador. Isso funciona muito bem, mas é realmente confuso e adiciona trabalho extra quando os modelos de administrador são alterados.

Poderia pensar em uma tag de extensão personalizada para os modelos, mas não quero reinventar a roda se já existir uma solução.

Em uma nota lateral: Alguém sabe se este problema será resolvido pelo próprio Django?

Semmel
fonte
1
Copiar os modelos de administração, estendê-los e substituir / adicionar blocos é o fluxo de trabalho mais eficiente, embora não ideal, considerando o estado atual do Django. Eu não vi qualquer outra maneira de fazer o que você está tentando fazer em três anos de trabalho com ele :)
Brandon
Bem - não sei se isso é bom ou não, mas pelo menos pessoas como você chegaram à mesma conclusão. É bom ouvir isso. :)
Semmel

Respostas:

101

Atualização :

Leia o Docs para sua versão do Django. por exemplo

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

Resposta original de 2011:

Eu tive o mesmo problema há cerca de um ano e meio e encontrei um bom carregador de modelos no djangosnippets.org que facilita isso. Ele permite que você estenda um modelo em um aplicativo específico, permitindo que você crie seu próprio admin / index.html que estende o modelo admin / index.html do aplicativo de administração. Como isso:

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

Eu dei um exemplo completo de como usar esse carregador de modelos em uma postagem do blog no meu site.

E aí cara
fonte
18
Para referência; o fragmento em questão tenha sido convertido para uma aplicação Django, e está disponível em PyPI (pip / easy_install) como django-apptemplates: pypi.python.org/pypi/django-apptemplates
Romløk
9
Apenas para ser 100% explícito: a solução acima não funcionará mais nas versões recentes do Django (pelo menos 1.4), pois uma das funções que o script usa é depreciada. Você pode encontrar a fonte atualizada aqui
OldTinfoil
2
Note que com o Django 1.8 isso ainda funcionará, mas a configuração precisa ser feita de uma maneira especial (veja app_namespace.Loader setup como um exemplo). O django-app-namespace-template-loader também é uma alternativa funcional para django-apptemplatesse ele parar de funcionar um dia.
Peterino 11/11/15
Esta resposta foi muito boa para as versões mais antigas do Django. Mas, a partir de agora, outra resposta de Cheng é mais relevante. stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar
70

Quanto ao Django 1.8 ser a versão atual, não há necessidade de ligar novamente, copiar o admin / templates para a pasta do projeto ou instalar middlewares, conforme sugerido pelas respostas acima. Aqui está o que fazer:

  1. crie a seguinte estrutura em árvore (recomendada pela documentação oficial )

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

Nota : A localização deste arquivo não é importante. Você pode colocá-lo dentro do seu aplicativo e ele ainda funcionará. Desde que sua localização possa ser descoberta pelo django. O que é mais importante é que o nome do arquivo HTML deve ser o mesmo que o nome original do arquivo HTML fornecido pelo django.

  1. Adicione este caminho de modelo às suas configurações.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. Identifique o nome e o bloco que você deseja substituir. Isso é feito olhando para o diretório admin / templates do django. Estou usando o virtualenv, então, para mim, o caminho está aqui:

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

Neste exemplo, desejo modificar o formulário Adicionar novo usuário. O modelo responsável por esta visualização é change_form.html . Abra o change_form.html e localize o {% block%} que deseja estender.

  1. Em seu change_form.html , escreva algo assim:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. Carregue sua página e você verá as alterações

Cheng
fonte
Ainda não é suficiente para estender o modelo principal "index.html", sem copiar todos os blocos. Uma solução é escrever alguns ../para "expandir" o caminho e especificar o caminho original mais exclusivo {% extends "../../admin/templates/admin/index.html" %}. link para resposta
hynekcer 15/06
1
Eu acho que em TEMPLATES devemos usar 'DIRS': [os.path.join (BASE_DIR, 'templates')],
Raul Reyes
Esse é o tipo de thread que ilustra perfeitamente a falha no SO. Uma estrutura é atualizada e a pergunta não é mais relevante, é de fato um impedimento do caminho adequado. Ótima resposta aqui. Crianças RTFM.
Derek Adair
Obrigado por esta resposta. Exceto por "O local deste arquivo não é importante.", Tudo funcionou bem.
Jaswanth Manigundan
54

se você precisar sobrescrever o admin/index.html, poderá definir o parâmetro index_template do AdminSite.

por exemplo

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

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

e coloque seu modelo em <appname>/templates/admin/my_custom_index.html

gengibre
fonte
5
Brilhante! Isso permite que você faça {% extends "admin/index.html" %}my_custom_index.html e faça referência ao modelo de administração do django sem copiá-lo. Obrigado.
Mattmc3
3
O @Semmel deve marcar isso como a resposta correta, já que é a abordagem mais simples que usa recursos internos do django e não requer o uso de carregadores de modelos personalizados.
MrColes
17

Com django1.5 (pelo menos), você pode definir o modelo que deseja usar para um determinadomodeladmin

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

Você pode fazer algo como

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

Por change_form.htmlser um modelo html simples que se estende admin/change_form.html(ou não, se você quiser fazê-lo do zero)

maazza
fonte
9

A resposta de Chengs está correta, mas, de acordo com os documentos do administrador, nem todos os modelos de administrador podem ser substituídos da seguinte maneira: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Modelos que podem ser substituídos por aplicativo ou modelo

Nem todo modelo em contrib / admin / templates / admin pode ser substituído por aplicativo ou por modelo. O seguinte pode:

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

Para os modelos que não podem ser substituídos dessa maneira, você ainda pode substituí-los por todo o projeto. Basta colocar a nova versão no diretório templates / admin . Isso é particularmente útil para criar páginas 404 e 500 personalizadas

Eu tive que sobrescrever o login.html do administrador e, portanto, tive que colocar o modelo sobrescrito nessa estrutura de pastas:

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

(sem a subpasta myapp no ​​admin) Não tenho repugnância suficiente para comentar sobre o post de Cheng, por isso tive que escrever isso como nova resposta.

matyas
fonte
Obrigado pelo feedback hyneker. Espero que minha resposta seja mais clara e mais direta agora.
Matyas
Sim, é útil saber que os modelos podem ser personalizados no nível do projeto, mesmo que alguns deles possam ser alterados opcionalmente no nível do aplicativo.
Hynekcer
5

A melhor maneira de fazer isso é colocar os modelos de administração do Django dentro do seu projeto. Portanto, seus modelos estariam dentro templates/admindos modelos de administração do Django template/django_admin. Em seguida, você pode fazer algo como o seguinte:

templates / admin / change_form.html

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

Your stuff here

Se você está preocupado em manter os modelos de ações atualizados, pode incluí-los com svn externals ou similar.

Chris Pratt
fonte
Usar svn externals é uma ótima idéia. O problema que isso apresenta é que todos os meus tradutores traduzirão todos esses modelos (porque o makemages coletará as strings de tradução de todos os modelos de administração), o que adiciona muito trabalho extra se você estiver trabalhando com vários idiomas. Talvez haja uma maneira de excluir esses modelos de makemessages?
Semmel
Use o --ignoreargumento com makemessages. Veja: docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt
Acho que a outra resposta se encaixa melhor na minha necessidade. Mas gosto da sua solução e acho que é uma boa alternativa se você não quiser mexer com os carregadores de modelos.
Semmel
5

Não consegui encontrar uma única resposta ou uma seção nos documentos oficiais do Django que tinham todas as informações necessárias para substituir / estender os modelos de administrador padrão. Por isso, estou escrevendo essa resposta como um guia completo, esperando que seja útil para outros no futuro.

Assumindo a estrutura padrão do projeto 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/

Aqui está o que você precisa fazer:

  1. Em mysite/admin.py, crie uma subclasse 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()

    Certifique-se de importar custom_admin_siteos admin.pyaplicativos e registrar seus modelos nele para exibi-los em seu site de administração personalizado (se desejar).

  2. Em mysite/apps.py, crie uma subclasse de AdminConfige defina default_sitepara admin.CustomAdminSitea etapa anterior:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. Em mysite/settings.py, substituir django.admin.siteem INSTALLED_APPScom apps.CustomAdminConfig(o administrador personalizado aplicativo de configuração da etapa anterior).

  4. Em mysite/urls.py, substitua admin.site.urlsdo URL do administrador paracustom_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. Crie o modelo que você deseja modificar em seu templatesdiretório, mantendo a estrutura de diretório padrão dos modelos de administração do Django, conforme especificado nos documentos . Por exemplo, se você estava modificando admin/index.html, crie o arquivotemplates/admin/index.html .

    Todos os modelos existentes podem ser modificados dessa maneira, e seus nomes e estruturas podem ser encontrados no código fonte do Django .

  6. Agora você pode substituir o modelo escrevendo-o do zero ou estendendo-o e, em seguida, substituindo / estendendo blocos específicos.

    Por exemplo, se você deseja manter tudo como está, mas deseja substituir o contentbloco (que na página de índice lista os aplicativos e seus modelos registrados), adicione o seguinte a templates/admin/index.html:

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

    Para preservar o conteúdo original de um bloco, adicione {{ block.super }}onde quiser que o conteúdo original seja exibido:

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

    Você também pode adicionar estilos e scripts personalizados, modificando os blocos extrastylee extrahead.

Faheel
fonte
você tem uma fonte ou documentação sobre isso?
Mary
Além das duas referências que adicionei no ponto 5, não, não tenho mais nada.
Faheel
1

Eu concordo com Chris Pratt. Mas acho que é melhor criar o link simbólico para a pasta original do Django, onde os modelos de administração estão:

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

e como você pode ver, depende da versão do python e da pasta onde o Django instalou. Portanto, no futuro ou em um servidor de produção, talvez seja necessário alterar o caminho.

James May
fonte
0

Este site tinha uma solução simples que funcionava com a minha configuração do Django 1.7.

PRIMEIRO: Crie um link simbólico chamado admin_src no diretório / template do seu projeto para os modelos Django instalados. Para mim no Dreamhost usando um virtualenv, meus modelos de administração do Django "fonte" estavam em:

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

SEGUNDO: Crie um diretório administrativo em templates /

Portanto, o diretório / modelo do meu projeto agora fica assim:

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

TERCEIRO: No seu novo diretório template / admin /, crie um arquivo base.html com este conteúdo:

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

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

QUARTA: Adicione seu admin favicon-admin.ico na sua pasta estática de img raiz.

Feito. Fácil.

mitchf
fonte
0

para o índice do aplicativo, adicione esta linha a um arquivo py em algum lugar comum, como url.py

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

para índice de módulo de aplicativo: adicione esta linha ao admin.py

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

para lista de alterações: adicione esta linha à classe admin:

change_list_template = "servers/servers_changelist.html"

para modelo de formulário do módulo de aplicativo: adicione esta linha à sua classe de administrador

change_form_template = "servers/server_changeform.html"

etc. e encontre outros nas mesmas classes de módulos do administrador

Saurabh Chandra Patel
fonte
-1

Você pode usar o django-overextends , que fornece herança circular de modelos para o Django.

Ele vem do Mezzanine CMS, de onde Stephen o extraiu para uma extensão autônoma do Django.

Mais informações que você encontra em "Substituindo modelos extensíveis" (http: /mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) nos documentos do Mezzanine.

Para informações mais aprofundadas, consulte o Stephens Blog "Herança de modelo circular para Django" (http: /blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

E nos Grupos do Google a discussão (https: /groups.google.com/forum / #! Topic / mezzanine-users / sUydcf_IZkQ) que iniciou o desenvolvimento desse recurso.

Nota:

Não tenho reputação de adicionar mais de 2 links. Mas acho que os links fornecem informações interessantes. Então, deixei de fora uma barra após "http (s):". Talvez alguém com melhor reputação possa reparar os links e remover esta nota.

Henri Hulski
fonte
Desde o Django 1.9, este projeto não é relevante, o mantenedor simplesmente não o está anunciando, veja code.djangoproject.com/ticket/15053 e github.com/stephenmcd/django-overextends/pull/37 . Para assumir o controle completo de qual aplicativo um modelo é carregado, há o django-apptemplates e o django-app-namespace-template-loader, que ainda são relevantes se você deseja estender de um aplicativo para outro.
benjaoming 22/07