Administrador de Django, ocultar un modelo

85

En la página raíz del sitio de administración donde aparecen los modelos registrados, quiero ocultar varios modelos que están registrados para el administrador de Django.

Si los anulo directamente, no puedo agregar nuevos registros ya que el símbolo de agregar nuevo "+" desaparece.

¿Cómo se puede hacer esto?

Hellnar
fuente

Respuestas:

123

Basado en la respuesta de x0nix, hice algunos experimentos. Parece que devolver un dict vacío get_model_permsexcluye el modelo de index.html, al mismo tiempo que le permite editar instancias directamente.

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        """
        Return empty perms dict thus hiding the model from admin index.
        """
        return {}

admin.site.register(MyModel, MyModelAdmin)
Shaunsephton
fuente
Convenido. Solo que eso es un problema cuando no quiero cambiar el código. Lo que quiero decir es que tengo una aplicación base que quiero mantener limpia de las dependencias de otras aplicaciones. Mantengo estas dependencias en una aplicación derivada específica del proyecto. Ahora quiero que la interfaz de administración solo muestre la aplicación derivada, no la aplicación base. Django requiere que la aplicación base esté listada en settings / INSTALLED_APPS para que la aplicación derivada funcione. Obviamente, la aplicación base no debería mostrarse, pero al mismo tiempo no quiero mantenerla sin modificar y reutilizable . Vea [aquí] ( Stack Exchange / questions / 13923968 /).
Sven
6
Un camino más corto:get_model_perms = lambda self, req: {}
Tigran Saluev
2
¿Qué pasa si quiero ocultar un modelo de un determinado userAdmin?
Alireza Sanaee
1
Tenga cuidado con esta solución: aunque el enlace desaparezca, el usuario puede saltar al objeto en sí de esta manera: / admin / main / comment / 2333 / change /
goodgrief
32

Para Django 1.8 y superior

Desde Django 1.8, ModelAdmintiene un nuevo método llamado has_module_permission()que es responsable de mostrar un modelo en el índice de administración.

Para ocultar un modelo del índice de administración, simplemente cree este método en su ModelAdminclase y regrese False. Ejemplo:

class MyModelAdmin(admin.ModelAdmin):
    ...
    def has_module_permission(self, request):
        return False
xyres
fuente
Desafortunadamente, has_module_permissionafecta a toda la aplicación y no solo a un modelo. Entonces, agregar esto a un modelo en la aplicación provoca un 403 Prohibido en la lista de modelos de la aplicación (/ admin / app_label /). Consulte django / contrib / admin / sites.py .
Fabian
1
@Fabian Creo que eso es un error. Pregunté esto en el canal IRC de Django, y algunas personas están de acuerdo en que este comportamiento no es deseado.
xyres
@Fabian Suponiendo que la página de índice de administración todavía se vincula a / admin / , es posible evitar ese error con algo como return request.path!='/admin/'. Desafortunadamente, eso vuelve a habilitar esos modelos en la lista de modelos de la aplicación.
ecp
Había abierto un ticket aquí para este error. Esto se ha solucionado aquí . Debería incluirse en la próxima versión, con suerte.
xyres
En Django 1.11, el enlace profundo todavía funciona, pero la entidad no aparece en la pantalla de administración principal
Csaba Toth
22

Tengo el mismo problema, aquí lo que se me ocurrió.

Como en la solución anterior, copie index.html de django a su /admin/index.html y modifíquelo así:

{% for model in app.models %}
    {% if not model.perms.list_hide %}
    <tr>
    ...
    </tr>
    {% endif %}
{% endfor %}

Y crea la subclase ModelAdmin:

class HiddenModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, *args, **kwargs):
        perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
        perms['list_hide'] = True
        return perms

Ahora, cualquier modelo registrado con la subclase HiddenModelAdmin no aparecerá en la lista de administración, pero estará disponible a través del símbolo "más" en detalle:

class MyModelAdmin(HiddenModelAdmin):
    ...

admin.site.register(MyModel, MyModelAdmin)
x0nix
fuente
1

Solución fea: anule la plantilla de índice de administración, es decir, copie index.html de django a su /admin/index.html y agregue algo como esto:

{% for for model in app.models %}
    {% ifnotequal model.name "NameOfModelToHide" %}
    ...
alex vasi
fuente
1

Esta es una construcción alternativa en la respuesta de x0nix superior, y solo si está contento de ocultar las filas con jquery.

Copiar pegando de la otra respuesta la parte que reutilicé

class HiddenModelAdmin(admin.ModelAdmin):
def get_model_perms(self, *args, **kwargs):
    perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
    perms['list_hide'] = True
    return perms

class MyModelAdmin(HiddenModelAdmin):
...

admin.site.register(MyModel, MyModelAdmin)

Entonces instala django-jquery y luego agregue el siguiente bloque en su /admin/index.htmlplantilla:

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

{% block extrahead %}
    <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.js"></script>
    {% if app_list %}
      <script type="text/javascript">
        $(function(){
          {% for app in app_list %}
            {% for model in app.models %}
                {% if model.perms.list_hide %}
                    $('div.app-{{ app.app_label }}').find('tr.model-{{ model.object_name|lower }}').hide();
                {% endif %}
            {% endfor %}
          {% endfor %}
        });
     </script>
   {% endif %}
{% endblock %}

No es necesario copiar y pegar toda la plantilla, solo extiéndala y anule el extraheadbloque. Necesitará django-apptemplates para que funcione lo anterior.

Panos
fuente
0

Django 1.2 tiene nuevas declaraciones if, lo que significa que la función deseada solo se puede obtener sobrescribiendo admin / index.html

{% if model.name not in "Name of hidden model; Name of other hidden model" %}
    ...
{% endif %}

Esta es una mala solución, porque no le importan los administradores en varios idiomas. Por supuesto, puede agregar los nombres de los modelos en todos los idiomas admitidos. Es una buena solución porque no sobrescribe más de un aspecto de las funciones centrales de Django.

Pero antes de cambiar nada, creo que la gente debería pensar en esto ...

Básicamente, el problema está relacionado con tener modelos que uno no desea usar para más que agregar una opción a un menú desplegable de vez en cuando. Se podría solucionar eficazmente creando un conjunto de permisos para usuarios "no tan avanzados" que entran en pánico cuando hay demasiados modelos. En caso de que se requieran cambios en los modelos particulares, uno puede simplemente iniciar sesión con la "cuenta avanzada".

benjaoming
fuente
0

Tenía muchos administradores de modelos para registrar y ocultar, si desea una solución más DRY, esto funcionó para mí (Django 1.10, Python 3.5)

# admin.py

def register_hidden_models(*model_names):
    for m in model_names:
        ma = type(
            str(m)+'Admin',
            (admin.ModelAdmin,),
            {
                'get_model_perms': lambda self, request: {}
            })
        admin.site.register(m, ma)

register_hidden_models(MyModel1, MyModel2, MyModel3)

Supongo que podría convertirlo en una clase de utilidad si desea reutilizarlo en todas las aplicaciones.

murraybiscuit
fuente
0

A partir de Django 1.8.18 , has_module_permission()todavía tiene problemas. Entonces, en nuestro caso usamos también el get_model_perms(). Del mismo modo, necesitamos ocultar el modelo solo para un usuario específico, pero superuserdebería poder acceder a su entrada de índice.

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        if not request.user.is_superuser:
            return {}
        return super(MyModelAdmin, self).get_model_perms(request)

admin.site.register(MyModel, MyModelAdmin)
Ranel Padon
fuente