django django-admin readonly

¿Modelos de solo lectura en la interfaz de administración de Django?



django-admin readonly (12)

permiso de solo lectura => vistas

  1. pipenv install django-admin-view-permission
  2. agregue ''admin_view_permission'' a INSTALLED_APPS en la configuración.py.me gusta esto: `INSTALLED_APPS = [''admin_view_permission'',
  3. Python manage.py migrate
  4. python manage.py runserver 6666

ok. diviértete con el permiso ''vistas''

¿Cómo puedo hacer que un modelo sea de solo lectura en la interfaz de administración? Es para un tipo de tabla de registro, donde estoy usando las funciones de administración para buscar, ordenar, filtrar, etc., pero no es necesario modificar el registro.

En caso de que esto parezca un duplicado, esto no es lo que estoy tratando de hacer:

  • No estoy buscando campos de solo lectura (incluso hacer que cada campo de solo lectura le permita crear nuevos registros)
  • No busco crear un usuario de solo lectura: cada usuario debe ser de solo lectura.

¡Esto se agregó a Django 2.1 que se lanzó el 8/1/18!

ModelAdmin.has_view_permission() es como el has_delete_permission, has_change_permission y has_add_permission existentes. Puedes leerlo en los documentos here

De las notas de publicación:

Esto permite dar a los usuarios acceso de solo lectura a los modelos en el administrador. ModelAdmin.has_view_permission () es nuevo. La implementación es compatible con versiones anteriores, ya que no es necesario asignar el permiso "ver" para permitir que los usuarios que tienen el permiso "cambiar" puedan editar objetos.


Aquí hay dos clases que estoy usando para hacer un modelo y / o sus inlines son solo de lectura.

Para el modelo de administrador:

from django.contrib import admin class ReadOnlyAdmin(admin.ModelAdmin): readonly_fields = [] def get_readonly_fields(self, request, obj=None): return list(self.readonly_fields) + / [field.name for field in obj._meta.fields] + / [field.name for field in obj._meta.many_to_many] def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False class MyModelAdmin(ReadOnlyAdmin): pass

Para inlines:

class ReadOnlyTabularInline(admin.TabularInline): extra = 0 can_delete = False editable_fields = [] readonly_fields = [] exclude = [] def get_readonly_fields(self, request, obj=None): return list(self.readonly_fields) + / [field.name for field in self.model._meta.fields if field.name not in self.editable_fields and field.name not in self.exclude] def has_add_permission(self, request): return False class MyInline(ReadOnlyTabularInline): pass


El administrador es para editar, no solo para ver (no encontrará un permiso para "ver"). Para lograr lo que desea, tendrá que prohibir agregar, eliminar y hacer que todos los campos sean de solo lectura:

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

(Si prohibes cambiar, ni siquiera podrás ver los objetos)

Para algunos códigos no probados que intentan automatizar la configuración de todos los campos de solo lectura, vea mi respuesta a Todo el modelo como de solo lectura

EDITAR: también no probado, pero solo eché un vistazo a mi LogEntryAdmin y tiene

readonly_fields = MyModel._meta.get_all_field_names()

No sé si eso funcionará en todos los casos.

EDITAR: QuerySet.delete () todavía puede eliminar objetos de forma masiva. Para solucionar esto, proporcione su propio administrador de "objetos" y la correspondiente subclase QuerySet que no se borra. Consulte Anulación de QuerySet.delete () en Django.


En realidad puedes probar esta solución simple:

class ReadOnlyModelAdmin(admin.ModelAdmin): actions = None list_display_links = None # more stuff here def has_add_permission(self, request): return False

  • actions = None : evita mostrar el menú desplegable con la opción "Delete selected ..."
  • list_display_links = None : evita hacer clic en las columnas para editar ese objeto
  • has_add_permission() devolviendo False evita crear nuevos objetos para ese modelo

He escrito una clase genérica para manejar la vista ReadOnly dependiendo de los permisos del usuario, incluidos los inlines;)

En models.py:

class User(AbstractUser): ... def is_readonly(self): if self.is_superuser: return False # make readonly all users not in "admins" group adminGroup = Group.objects.filter(name="admins") if adminGroup in self.groups.all(): return False return True

En admin.py:

# read-only user filter class for ModelAdmin class ReadOnlyAdmin(admin.ModelAdmin): def __init__(self, *args, **kwargs): # keep initial readonly_fields defined in subclass self._init_readonly_fields = self.readonly_fields # keep also inline readonly_fields for inline in self.inlines: inline._init_readonly_fields = inline.readonly_fields super().__init__(*args,**kwargs) # customize change_view to disable edition to readonly_users def change_view( self, request, object_id, form_url='''', extra_context=None ): context = extra_context or {} # find whether it is readonly or not if request.user.is_readonly(): # put all fields in readonly_field list self.readonly_fields = [ field.name for field in self.model._meta.get_fields() if not field.auto_created ] # readonly mode fer all inlines for inline in self.inlines: inline.readonly_fields = [field.name for field in inline.model._meta.get_fields() if not field.auto_created] # remove edition buttons self.save_on_top = False context[''show_save''] = False context[''show_save_and_continue''] = False else: # if not readonly user, reset initial readonly_fields self.readonly_fields = self._init_readonly_fields # same for inlines for inline in self.inlines: inline.readonly_fields = self._init_readonly_fields return super().change_view( request, object_id, form_url, context ) def save_model(self, request, obj, form, change): # disable saving model for readonly users # just in case we have a malicious user... if request.user.is_readonly(): # si és usuari readonly no guardem canvis return False # if not readonly user, save model return super().save_model( request, obj, form, change )

Entonces, podemos heredar normalmente nuestras clases en admin.py:

class ContactAdmin(ReadOnlyAdmin): list_display = ("name","email","whatever") readonly_fields = ("updated","created") inlines = ( PhoneInline, ... )


La compilación de las excelentes respuestas de @darklow y @josir, además de agregar un poco más para eliminar los botones "Guardar" y "Guardar y continuar" lleva a (en la sintaxis de Python 3):

class ReadOnlyAdmin(admin.ModelAdmin): """Provides a read-only view of a model in Django admin.""" readonly_fields = [] def change_view(self, request, object_id, extra_context=None): """ customize add/edit form to remove save / save and continue """ extra_context = extra_context or {} extra_context[''show_save_and_continue''] = False extra_context[''show_save''] = False return super().change_view(request, object_id, extra_context=extra_context) def get_actions(self, request): actions = super().get_actions(request) if ''delete_selected'' in actions: del actions[''delete_selected''] return actions def get_readonly_fields(self, request, obj=None): return list(self.readonly_fields) + / [field.name for field in obj._meta.fields] + / [field.name for field in obj._meta.many_to_many] def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False

y luego usas como

class MyModelAdmin(ReadOnlyAdmin): pass

Solo he probado esto con Django 1.11 / Python 3.


La respuesta aceptada debería funcionar, pero esto también preservará el orden de visualización de los campos de solo lectura. Tampoco tiene que codificar el modelo con esta solución.

class ReadonlyAdmin(admin.ModelAdmin): def __init__(self, model, admin_site): super(ReadonlyAdmin, self).__init__(model, admin_site) self.readonly_fields = [field.name for field in filter(lambda f: not f.auto_created, model._meta.fields)] def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request, obj=None): return False


Me encontré con el mismo requisito cuando tuve que hacer que todos los campos fueran de solo lectura para ciertos usuarios en el administrador de django, terminé aprovechando el módulo de django "django-admin-view-permission" sin pasar mi propio código. Si necesita un control más preciso para definir explícitamente qué campos, entonces necesitará extender el módulo. Puedes ver el plugin en acción here


Si desea que el usuario se dé cuenta de que no puede editarlo, faltan 2 piezas en la primera solución. ¡Has eliminado la acción de borrar!

class MyAdmin(ModelAdmin) def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False def get_actions(self, request): actions = super(MyAdmin, self).get_actions(request) if ''delete_selected'' in actions: del actions[''delete_selected''] return actions

Segundo: la solución de solo lectura funciona bien en modelos planos. Pero NO funciona si tiene un modelo heredado con claves externas. Desafortunadamente, no sé la solución para eso todavía. Un buen intento es:

Modelo completo como solo lectura

Pero tampoco funciona para mí.

Y una nota final, si desea pensar en una solución amplia, debe hacer cumplir que cada línea debe ser de solo lectura también.


Si la respuesta aceptada no funciona para usted, intente esto:

def get_readonly_fields(self, request, obj=None): readonly_fields = [] for field in self.model._meta.fields: readonly_fields.append(field.name) return readonly_fields


Ver https://djangosnippets.org/snippets/10539/

class ReadOnlyAdminMixin(object): """Disables all editing capabilities.""" change_form_template = "admin/view.html" def __init__(self, *args, **kwargs): super(ReadOnlyAdminMixin, self).__init__(*args, **kwargs) self.readonly_fields = self.model._meta.get_all_field_names() def get_actions(self, request): actions = super(ReadOnlyAdminMixin, self).get_actions(request) del actions["delete_selected"] return actions def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def save_model(self, request, obj, form, change): pass def delete_model(self, request, obj): pass def save_related(self, request, form, formsets, change): pass

templates / admin / view.html

{% extends "admin/change_form.html" %} {% load i18n %} {% block submit_buttons_bottom %} <div class="submit-row"> <a href="../">{% blocktrans %}Back to list{% endblocktrans %}</a> </div> {% endblock %}

templates / admin / view.html (para Grappelli)

{% extends "admin/change_form.html" %} {% load i18n %} {% block submit_buttons_bottom %} <footer class="grp-module grp-submit-row grp-fixed-footer"> <header style="display:none"><h1>{% trans "submit options"|capfirst context "heading" %}</h1></header> <ul> <li><a href="../" class="grp-button grp-default">{% blocktrans %}Back to list{% endblocktrans %}</a></li> </ul> </footer> {% endblock %}