Jak mogę sprawić, by model był całkowicie tylko do odczytu w interfejsie administratora? Jest to rodzaj tabeli dziennika, w której używam funkcji administratora do wyszukiwania, sortowania, filtrowania itp., Ale nie ma potrzeby modyfikowania dziennika.
W przypadku, gdy wygląda to na duplikat, nie próbuję tego zrobić:
- Nie szukam pól tylko do odczytu (nawet ustawienie każdego pola jako tylko do odczytu pozwoliłoby na tworzenie nowych rekordów)
- Nie chcę tworzyć użytkownika tylko do odczytu : każdy użytkownik powinien być tylko do odczytu.
django
django-admin
readonly
Steve Bennett
źródło
źródło
has_view_permission
został ostatecznie zaimplementowany w Django 2.1. Zobacz także stackoverflow.com/a/51641149 poniżej.Odpowiedzi:
Zobacz 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
szablony / 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 %}
szablony / admin / view.html (dla 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 %}
źródło
Model
, czy dlaModelAdmin
?ModelAdmin
.Administrator służy do edycji, a nie tylko do przeglądania (nie znajdziesz uprawnienia do przeglądania). Aby osiągnąć to, co chcesz, musisz zabronić dodawania, usuwania i ustawiać wszystkie pola jako tylko do odczytu:
class MyAdmin(ModelAdmin): def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False
(jeśli zabronisz zmiany, nie zobaczysz nawet obiektów)
W przypadku niektórych nieprzetestowanych kodów, które próbują zautomatyzować ustawianie wszystkich pól tylko do odczytu, moja odpowiedź na cały model jest tylko do odczytu
EDYCJA: również nieprzetestowane, ale właśnie rzuciłem okiem na mój LogEntryAdmin i ma
readonly_fields = MyModel._meta.get_all_field_names()
Nie wiem, czy to zadziała we wszystkich przypadkach.
EDYCJA: QuerySet.delete () może nadal masowo usuwać obiekty. Aby obejść ten problem, zapewnij własnego menedżera "obiektów" i odpowiednią podklasę QuerySet, która nie usuwa - zobacz Przesłanianie QuerySet.delete () w Django
źródło
Oto dwie klasy, których używam do tworzenia modelu i / lub jego wbudowane tylko do odczytu.
Dla administratora modelu:
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
W przypadku inline:
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
źródło
has_add_permission
wReadOnlyAdmin
przyjmuje tylko żądanie jako parametrJeśli chcesz, aby użytkownik uświadomił sobie, że nie może go edytować, w pierwszym rozwiązaniu brakuje 2 elementów. Usunąłeś akcję usuwania!
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
Po drugie: rozwiązanie tylko do odczytu działa dobrze na zwykłych modelach. Ale to NIE działa, jeśli masz odziedziczony model z obcymi kluczami. Niestety nie znam jeszcze rozwiązania tego problemu. Dobra próba to:
Cały model tylko do odczytu
Ale dla mnie to też nie działa.
I ostatnia uwaga, jeśli chcesz pomyśleć o szerokim rozwiązaniu, musisz wymusić, że każdy wiersz w wierszu również musi być tylko do odczytu.
źródło
Właściwie możesz wypróbować to proste rozwiązanie:
class ReadOnlyModelAdmin(admin.ModelAdmin): actions = None list_display_links = None # more stuff here def has_add_permission(self, request): return False
actions = None
: unika wyświetlania menu z opcją „Usuń wybrane ...”list_display_links = None
: unika klikania kolumn w celu edycji tego obiektuhas_add_permission()
zwracanie wartości False pozwala uniknąć tworzenia nowych obiektów dla tego modeluźródło
To zostało dodane do Django 2.1, które zostało wydane 18.08.18!
ModelAdmin.has_view_permission()
jest taki sam, jak istniejące has_delete_permission, has_change_permission i has_add_permission. Możesz o tym przeczytać w dokumentach tutajZ informacji o wydaniu:
źródło
Jeśli zaakceptowana odpowiedź nie działa dla Ciebie, spróbuj tego:
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
źródło
Kompilowanie doskonałych odpowiedzi @darklow i @josir oraz dodanie nieco więcej w celu usunięcia przycisków „Zapisz” i „Zapisz i kontynuuj” prowadzi do (w składni Pythona 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
a potem używasz like
class MyModelAdmin(ReadOnlyAdmin): pass
Próbowałem tego tylko z Django 1.11 / Python 3.
źródło
Zaakceptowana odpowiedź powinna działać, ale zachowa to również kolejność wyświetlania pól tylko do odczytu. Dzięki temu rozwiązaniu nie musisz też na stałe kodować modelu.
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
źródło
Z Django 2.2 robię to tak:
@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
źródło
readonly_fields
iactions
nie są koniecznez django 2.2 administrator tylko do odczytu może być tak prosty, jak:
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')
źródło
Napotkałem ten sam wymóg, gdy musiałem uczynić wszystkie pola tylko do odczytu dla niektórych użytkowników w administratorze django, co skończyło się wykorzystaniem modułu django "django-admin-uprawnienia-widok" bez zmiany własnego kodu. Jeśli potrzebujesz dokładniejszej kontroli, aby wyraźnie określić, które pola, musisz rozszerzyć moduł. Możesz sprawdzić, jak działa wtyczka tutaj
źródło
tylko do odczytu => uprawnienia do przeglądania
pipenv install django-admin-view-permission
6666
ok. baw się dobrze za zgodą „widoki”
źródło
Napisałem ogólną klasę do obsługi widoku ReadOnly w zależności od uprawnień użytkownika, w tym inline;)
W 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
W 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 )
Następnie możemy normalnie dziedziczyć nasze klasy w admin.py:
class ContactAdmin(ReadOnlyAdmin): list_display = ("name","email","whatever") readonly_fields = ("updated","created") inlines = ( PhoneInline, ... )
źródło