¿Cómo puedo hacer que un modelo sea completamente de solo lectura en la interfaz de administración? Es para una especie 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 parezca un duplicado, esto no es lo que estoy tratando de hacer:
- No estoy buscando campos de solo lectura (incluso hacer que todos los campos sean de solo lectura le permitiría crear nuevos registros)
- No estoy buscando crear un usuario de solo lectura : todos los usuarios deben ser de solo lectura.
django
django-admin
readonly
Steve Bennett
fuente
fuente
has_view_permission
finalmente se implementó en Django 2.1. También vea stackoverflow.com/a/51641149 a continuación.Respuestas:
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_action = "delete_selected" if del_action in actions: del actions[del_action] 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 %}
fuente
Model
, o para elModelAdmin
?ModelAdmin
.El administrador es para editar, no solo para ver (no encontrará un permiso de "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 prohíbe el cambio, ni siquiera podrá 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: tampoco probado, pero acabo de echar 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 () aún puede eliminar objetos de forma masiva. Para evitar esto, proporcione su propio administrador de "objetos" y la subclase correspondiente de QuerySet que no se borra; consulte Anulación de QuerySet.delete () en Django
fuente
Aquí hay dos clases que estoy usando para hacer un modelo y / o solo lectura en línea.
Para el administrador de modelos:
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 líneas:
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
fuente
has_add_permission
inReadOnlyAdmin
toma solo la solicitud como parámetroSi desea que el usuario sepa que no puede editarlo, faltan 2 piezas en la primera solución. ¡Has eliminado la acción de eliminación!
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 simples. Pero NO funciona si tiene un modelo heredado con claves externas. Desafortunadamente, todavía no conozco la solución. Un buen intento es:
Todo el modelo como de solo lectura
Pero tampoco me funciona.
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.
fuente
De hecho, puedes probar esta sencilla solución:
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 "Eliminar seleccionados ..."list_display_links = None
: evita hacer clic en columnas para editar ese objetohas_add_permission()
devolver False evita la creación de nuevos objetos para ese modelofuente
¡Esto se agregó a Django 2.1 que se lanzó el 1/8/18!
ModelAdmin.has_view_permission()
es como los has_delete_permission, has_change_permission y has_add_permission existentes. Puedes leer sobre esto en los documentos aquí.De las notas de la versión:
fuente
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
fuente
Compilar las excelentes respuestas de @darklow y @josir, además de agregar un poco más para eliminar los botones "Guardar" y "Guardar y continuar" conduce 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 like
class MyModelAdmin(ReadOnlyAdmin): pass
Solo probé esto con Django 1.11 / Python 3.
fuente
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
fuente
Con Django 2.2 lo hago así:
@admin.register(MyModel) class MyAdmin(admin.ModelAdmin): readonly_fields = ('all', 'the', 'necessary', 'fields') actions = None # Removes the default delete action in list view def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False
fuente
readonly_fields
yactions
no son necesariascon django 2.2, el administrador de solo lectura puede ser tan simple como:
class ReadOnlyAdminMixin(): def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False class LogEntryAdmin(ReadOnlyAdminMixin, admin.ModelAdmin): list_display = ('id', 'user', 'action_flag', 'content_type', 'object_repr')
fuente
Me encontré con el mismo requisito cuando necesité hacer que todos los campos fueran de solo lectura para ciertos usuarios en django admin terminó aprovechando el módulo de django "django-admin-view-allow" sin ejecutar mi propio código. Si necesita un control más detallado para definir explícitamente qué campos, necesitará ampliar el módulo. Puedes ver el complemento en acción aquí.
fuente
solo lectura => permiso de visualización
pipenv install django-admin-view-permission
6666
ok, diviértete con el permiso de 'vistas'
fuente
He escrito una clase genérica para manejar la vista de solo lectura según los permisos del usuario, incluidas las líneas;)
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 simplemente heredar normalmente nuestras clases en admin.py:
class ContactAdmin(ReadOnlyAdmin): list_display = ("name","email","whatever") readonly_fields = ("updated","created") inlines = ( PhoneInline, ... )
fuente