theme template personalizar password bootstrap actions python django django-admin modeladmin

python - template - django-admin command



¿Deshabilitar el enlace para editar el objeto en el administrador de django(solo en la lista de visualización)? (9)

Como usuario, omat, mencionado en un comentario anterior, cualquier intento de simplemente eliminar los enlaces no impide que los usuarios sigan accediendo manualmente a la página de cambios. Sin embargo, eso también es bastante fácil de remediar:

class MyModelAdmin(admin.ModelAdmin) # Other stuff here def change_view(self, request, obj=None): from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect return HttpResponseRedirect(reverse(''admin:myapp_mymodel_changelist''))

En el administrador de Django, quiero desactivar los enlaces provistos en la página "seleccionar elemento para cambiar" para que los usuarios no puedan ir a ningún lado a editar el artículo. (Voy a limitar lo que los usuarios pueden hacer con esta lista a un conjunto de acciones desplegables, sin edición real de campos).

Veo que Django tiene la capacidad de elegir qué campos mostrar el enlace , sin embargo, no puedo ver cómo no puedo tener ninguno de ellos.

class HitAdmin(admin.ModelAdmin): list_display = (''user'',''ip'',''user_agent'',''hitcount'') search_fields = (''ip'',''user_agent'') date_hierarchy = ''created'' list_display_links = [] # doesn''t work, goes to default

¿Alguna idea de cómo obtener mi lista de objetos sin ningún enlace para editar?


En Django 1.7 y posterior, puedes hacer

class HitAdmin(admin.ModelAdmin): list_display_links = None


En tu conjunto de administrador modelo:

list_display_links = (None,)

Deberias hacer eso. (Funciona en 1.1.1 de todos modos)

Enlace a documentos: list_display_links


Hacer esto correctamente requiere dos pasos:

  • Oculte el enlace de edición, de modo que nadie se tropiece con la página de detalles (cambio de vista) por error.
  • Modifique la vista de cambio para redirigir a la vista de lista.

La segunda parte es importante: si no haces esto, las personas aún podrán acceder a la vista de cambio ingresando una URL directamente (que presumiblemente no deseas). Esto está estrechamente relacionado con lo que OWASP llama una "referencia insegura de objeto directo" .

Como parte de esta respuesta, construiré una clase ReadOnlyMixin que se puede usar para proporcionar toda la funcionalidad que se muestra.

Ocultar el enlace de edición

Django 1.7 lo hace realmente fácil: acaba de establecer list_display_links a None .

class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2 list_display_links = None

Django 1.6 (y presumiblemente antes) no lo hacen tan simple. Muchas respuestas a esta pregunta han sugerido invalidar __init__ para establecer list_display_links después de que se haya construido el objeto, pero esto dificulta la reutilización (solo podemos anular el constructor una vez).

Creo que una mejor opción es anular el método get_list_display_links de Django de la siguiente manera:

def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). We override Django''s default implementation to specify no links unless these are explicitly set. """ if self.list_display_links or not list_display: return self.list_display_links else: return (None,)

Esto hace que nuestra mezcla sea fácil de usar: oculta el enlace de edición de forma predeterminada, pero nos permite agregarlo de nuevo si es necesario para una vista de administrador en particular.

Redirigir a la vista de lista

Podemos cambiar el comportamiento de la página de detalles (cambiar la vista) anulando el método change_view . Aquí hay una extensión de la técnica sugerida por Chris Pratt que encuentra automáticamente la página correcta:

enable_change_view = False def change_view(self, request, object_id, form_url='''', extra_context=None): """ The ''change'' admin view for this model. We override this to redirect back to the changelist unless the view is specifically enabled by the "enable_change_view" property. """ if self.enable_change_view: return super(ReportMixin, self).change_view( request, object_id, form_url, extra_context ) else: from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect opts = self.model._meta url = reverse(''admin:{app}_{model}_changelist''.format( app=opts.app_label, model=opts.model_name, )) return HttpResponseRedirect(url)

De nuevo, esto es personalizable: al alternar enable_change_view a True , puede volver a activar la página de detalles.

Eliminar el botón "Agregar elemento"

Finalmente, es posible que desee sobrescribir los siguientes métodos para evitar que las personas agreguen o eliminen nuevos elementos.

def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False

Estos cambios:

  • desactivar el botón "Agregar elemento "
  • evitar que las personas agreguen elementos directamente añadiendo /add a la URL
  • evitar la eliminación masiva

Finalmente, puede eliminar la acción "Eliminar elementos seleccionados" modificando el parámetro de actions .

Poniendolo todo junto

Aquí está el mixin completo:

from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2 actions = None enable_change_view = False def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). We override Django''s default implementation to specify no links unless these are explicitly set. """ if self.list_display_links or not list_display: return self.list_display_links else: return (None,) def change_view(self, request, object_id, form_url='''', extra_context=None): """ The ''change'' admin view for this model. We override this to redirect back to the changelist unless the view is specifically enabled by the "enable_change_view" property. """ if self.enable_change_view: return super(ReportMixin, self).change_view( request, object_id, form_url, extra_context ) else: opts = self.model._meta url = reverse(''admin:{app}_{model}_changelist''.format( app=opts.app_label, model=opts.model_name, )) return HttpResponseRedirect(url) def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False


No hay una forma compatible para hacer esto.

Al mirar el código, parece que establece automáticamente ModelAdmin.list_display_links en el primer elemento si no lo configura en nada. Así que la manera más fácil podría ser anular el método __init__ en su subclase ModelAdmin para ModelAdmin ese atributo en la inicialización:

class HitAdmin(admin.ModelAdmin): list_display = (''user'',''ip'',''user_agent'',''hitcount'') search_fields = (''ip'',''user_agent'') date_hierarchy = ''created'' def __init__(self, *args, **kwargs): super(HitAdmin, self).__init__(*args, **kwargs) self.list_display_links = []

Esto parece funcionar, después de una prueba muy superficial. No puedo garantizar que no rompa nada en otro lugar, o que no se romperá por cambios futuros en Django.

Editar después de comentar :

No es necesario parchar la fuente, esto funcionaría:

def __init__(self, *args, **kwargs): if self.list_display_links: unset_list_display = True else: unset_list_display = False super(HitAdmin, self).__init__(*args, **kwargs) if unset_list_display: self.list_display_links = []

Pero dudo mucho que cualquier parche sea aceptado en Django, ya que esto rompe algo que el código explícitamente hace en este momento.


Solo para las notas, puedes modificar changelist_view:

class SomeAdmin(admin.ModelAdmin): def changelist_view(self, request, extra_context=None): self.list_display_links = (None, ) return super(SomeAdmin, self).changelist_view(request, extra_context=None)

Esto funciona bien para mi.


También podría ser ridículamente hacky al respecto (si no quería preocuparse por anular init ) y proporcionar un valor para el primer elemento que básicamente se ve así:

</a>My non-linked value<a>

Lo sé, lo sé, no es muy bonito, pero tal vez con menos ansiedad por romper algo en otro lado, ya que lo único que estamos haciendo es cambiar el marcado.

Aquí hay un código de muestra sobre cómo funciona esto:

class HitAdmin(admin.ModelAdmin): list_display = (''user_no_link'',''ip'',''user_agent'',''hitcount'') def user_no_link(self, obj): return u''</a>%s<a>'' % obj user_no_link.allow_tags = True user_no_link.short_description = "user"

Nota al margen: también puede mejorar la legibilidad de la salida (ya que no desea que sea un enlace) devolviendo return u''%s'' % obj.get_full_name() que podría ser un poco ordenado según su caso de uso.


Yo quería un visor de registro solo como una lista.

Lo tengo trabajando así:

class LogEntryAdmin(ModelAdmin): actions = None list_display = ( ''action_time'', ''user'', ''content_type'', ''object_repr'', ''change_message'') search_fields = [''=user__username'', ] fieldsets = [ (None, {''fields'':()}), ] def __init__(self, *args, **kwargs): super(LogEntryAdmin, self).__init__(*args, **kwargs) self.list_display_links = (None, )

Es una especie de mezcla entre ambas respuestas.

Si solo hace self.list_display_links = () , mostrará el enlace, De todos modos, porque el código de template-tag plantilla (templatetags / admin_list.py) comprueba nuevamente para ver si la lista está vacía.


con django 1.6.2 puedes hacer esto:

class MyAdmin(admin.ModelAdmin): def get_list_display_links(self, request, list_display): return []

ocultará todos los enlaces generados automáticamente.