Django yönetici arayüzünde salt okunur modeller?


86

Yönetici arayüzünde bir modeli tamamen salt okunur hale nasıl getirebilirim? Arama, sıralama, filtreleme vb. İçin yönetici özelliklerini kullandığım bir tür günlük tablosu içindir, ancak günlüğü değiştirmeye gerek yoktur.

Bunun bir kopya gibi görünmesi durumunda, yapmaya çalıştığım şey şu değil :

  • Salt okunur alanlar aramıyorum (her alanı salt okunur yapmak bile yeni kayıtlar oluşturmanıza izin verir)
  • Salt okunur bir kullanıcı oluşturmak istemiyorum : her kullanıcı salt okunur olmalıdır.

2
bu özellik yakında gelecek: github.com/django/django/pull/5297
Bosco

2
has_view_permissionsonunda Django 2.1'de uygulandı. Ayrıca aşağıdaki stackoverflow.com/a/51641149'a bakın.
djvg

Yanıtlar:


21

Bkz. 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

şablonlar / 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 (Grappelli için)

{% 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 %}

Mantıklı gibi. Django'yu kullanmayalı çok uzun zaman oldu, diğer yorumcuların söyleyeceklerini görmek için bekleyebilirim.
Steve Bennett

Bu bir mixin için mi Model, yoksa için ModelAdminmi?
OrangeDog

Bu ModelAdmin.
Pascal Polleunus

Django 1.8 ve sonrası için get_all_field_names kullanımdan kaldırılmıştır. Bunları elde etmenin geriye dönük uyumlu yolu . Onları almanın kısa yolu .
fzzylogic

Has_add_permission
rluts

70

Yönetici sadece görüntülemek için değil, düzenleme içindir (bir "görüntüleme" izni bulamazsınız). İstediğinizi elde etmek için, eklemeyi, silmeyi yasaklamanız ve tüm alanları salt okunur hale getirmeniz gerekir:

class MyAdmin(ModelAdmin):

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

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

(Değiştirmeyi yasaklıyorsanız, nesneleri göremezsiniz bile)

Tüm alanları salt okunur olarak ayarlamayı otomatikleştirmeye çalışan bazı test edilmemiş kodlar için cevabıma bakın. Tüm modeli salt okunur olarak yanıtıma bakın

DÜZENLEME: ayrıca test edilmedi, ancak LogEntryAdmin'ime bir baktım ve

readonly_fields = MyModel._meta.get_all_field_names()

Bunun her durumda işe yarayıp yaramayacağını bilmiyorum.

DÜZENLEME: QuerySet.delete () yine de nesneleri toplu olarak silebilir. Bunu aşmak için kendi "nesneler" yöneticinizi ve silinmeyen ilgili QuerySet alt sınıfını sağlayın - Django'da QuerySet.delete () 'i geçersiz kılma konusuna bakın


2
Not: ve evet, diğer yanıtta olduğu gibi, gitmenin yolu muhtemelen bu üç şeyi bir ReadOnlyAdmin sınıfında tanımlamak ve ardından bu davranışa ihtiyaç duyduğunuz her yerde alt sınıflara ayırmaktır. Hatta fantezi olsun ve gruplar / izinleri tanımını izin verebilir edilir (istek erişimi ve bu nedenle geçerli kullanıcı olan) (ve kullanımı get_readonly_fields) düzenlemek için izin ve sonra buna uygun return true.
Danny W. Adair

neredeyse mükemmel. Satırların bir düzenleme sayfasına bağlantı vermemesinin bir yolu olup olmadığını hırsla sorabilir miyim? (yine, herhangi bir satırı yakınlaştırmaya ve herhangi bir şeyi düzenlemeye gerek yoktur)
Steve Bennett

1
ModelAdmin'inizin list_display_links değerini False olarak değerlendiren bir şeye ayarlarsanız (boş bir liste / tuple gibi), ModelAdmin .__ init __ () list_display_links'i tüm sütunlara ayarlar (eylem onay kutusu hariç) - bkz. Options.py. Sanırım bu , bağlantıların olmasını sağlamak için yapıldı . Bu yüzden bir ReadOnlyAdmin'de __init __ () 'i geçersiz kılardım, üst olanı çağırırdım ve list_display_links'i boş bir listeye veya tuple'a ayarlardım. Artık salt okunur değişiklik formlarına bağlantılarınız olmayacağına göre, muhtemelen bunun için bir parametre / sınıf özniteliği oluşturmak en iyisidir - bunun genel olarak istenen davranış olduğunu düşünmezdim. Hth
Danny W. Adair

Modelden ayarlanan salt okunur alanlarla ilgili olarak, formu geçersiz kılar ve başka alanlar eklerseniz bu muhtemelen işe yaramayacaktır ... gerçek form alanlarına dayandırmak muhtemelen daha iyidir.
Danny W. Adair

Bu işe yaramadı: def __init __ (self, * args): super (RegistrationStatusAdmin, self) .__ init __ (* args) self.display_links = []
Steve Bennett

50

İşte bir model yapmak için kullandığım iki sınıf ve / veya satır içi salt okunur.

Model yöneticisi için:

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

Satır içi için:

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

Her iki sınıfı da bir alt sınıfa nasıl uygulayacağınız. Örneğin, bir sınıfta normal alanlarım ve satır içi satırlarım varsa? İkisini de uzatabilir miyim?
Timo

@timo bu sınıfları mixins olarak kullan
MartinM

1
has_add_permissioniçinde ReadOnlyAdminyalnızca parametre olarak istek alır
MartinM

has_change_permission () da geçersiz kılınmalıdır. def has_change_permission (self, request, obj = None):
david euler

13

Kullanıcının onu düzenleyemeyeceğinin farkına varmasını istiyorsanız, ilk çözümde 2 parça eksiktir. Silme eylemini kaldırdınız!

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

İkincisi: salt okunur çözüm, düz modellerde iyi çalışıyor. Ama yok DEĞİL yabancı anahtarlar ile kalıtsal bir model varsa çalışır. Maalesef bunun çözümünü henüz bilmiyorum. İyi bir girişim:

Tüm model salt okunur

Ama benim için de çalışmıyor.

Ve son bir not, geniş bir çözüm üzerinde düşünmek istiyorsanız, her satır içi satırın da salt okunur olması gerektiğini zorlamalısınız.


11

Aslında bu basit çözümü deneyebilirsiniz:

class ReadOnlyModelAdmin(admin.ModelAdmin):
    actions = None
    list_display_links = None
    # more stuff here

    def has_add_permission(self, request):
        return False
  • actions = None: "Seçileni sil ..." seçeneğiyle açılır listenin gösterilmesini önler
  • list_display_links = None: o nesneyi düzenlemek için sütunlara tıklamaktan kaçınır
  • has_add_permission() False döndürmek, o model için yeni nesneler oluşturmaktan kaçınır

1
Bu, alanları görüntülemek için herhangi bir örneği açmayı yasaklar, ancak yalnızca listelemede sorun yoksa, o zaman çalışır.
Sebastián Vansteenkiste

8

Bu, 8/1/18 tarihinde piyasaya sürülen Django 2.1'e eklendi!

ModelAdmin.has_view_permission()tıpkı mevcut has_delete_permission, has_change_permission ve has_add_permission gibidir. Buradaki belgelerde okuyabilirsiniz

Sürüm notlarından:

Bu, kullanıcılara yöneticideki modellere salt okunur erişim izni verir. ModelAdmin.has_view_permission () yenidir. Uygulama, nesneleri düzenlemek için "değiştirme" iznine sahip kullanıcılara izin vermek için "görüntüleme" izni atamaya gerek olmadığından geriye doğru uyumludur.


Süper kullanıcı yine de yönetici arayüzündeki nesneleri değiştirebilir, değil mi?
Flimm

Davranışı süper kullanıcıların erişimine izin vermeyecek şekilde değiştirmek için bu yöntemlerden birini geçersiz kılmadığınız sürece bu doğrudur.
grrrrrr

6

Kabul edilen cevap sizin için işe yaramazsa, şunu deneyin:

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

5

@Darklow ve @josir'in mükemmel yanıtlarını derlemek, ayrıca "Kaydet" ve "Kaydet ve Devam Et" düğmelerini kaldırmak için biraz daha eklemek (Python 3 sözdiziminde):

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

ve sonra beğenirsin

class MyModelAdmin(ReadOnlyAdmin):
    pass

Bunu sadece Django 1.11 / Python 3 ile denedim.


Django'yu kullanmayalı çok uzun zaman oldu. Başka biri bunun için kefil olabilir mi?
Steve Bennett

@SteveBennett ㄹ bu adresler ... Bu cevap su geçirmez olmadığını gereksinimlerine Çok fazla varyasyonu ... orada burada bir açıklama getirmiştir: stackoverflow.com/a/36019597/2586761 ve yorum yaptığınız cevap stackoverflow.com / a / 33543817/2586761 kabul edilen cevaptan daha eksiksiz olarak
ptim

3

Kabul edilen yanıt işe yaramalıdır, ancak bu aynı zamanda salt okunur alanların görüntülenme sırasını da koruyacaktır. Bu çözümle modeli kodlamanız da gerekmez.

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

3

Django 2.2 ile bunu şöyle yapıyorum:

@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

django 2.2 ile readonly_fieldsve actionssatırları gerekli değildir
cheng10

3

django 2.2 ile salt okunur yönetici şu kadar basit olabilir:

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')

1

Django admin'deki belirli kullanıcılar için tüm alanları salt okunur hale getirmem gerektiğinde, kendi kodumu döndürmeden django modülü "django-admin-view-permit" üzerinden yararlanmaya başladığımda aynı gereksinimi karşıladım. Hangi alanları açıkça tanımlamak için daha ayrıntılı kontrole ihtiyacınız varsa, modülü genişletmeniz gerekir. Sen eylem eklentisi kontrol edebilirsiniz burada


0

salt okunur => görüntüleme izni

  1. pipenv install django-admin-view-permission
  2. settings.py'de INSTALLED_APPS'e 'admin_view_permission' ekleyin. şunun gibi: `INSTALLED_APPS = ['admin_view_permission',
  3. python manage.py migrate
  4. python manage.py runserver 6666

ok. 'görünümler' izniyle eğlenin


0

Satır içi dahil Kullanıcı izinlerine bağlı olarak ReadOnly görünümünü işlemek için genel bir sınıf yazdım;)

Models.py'de:

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

Admin.py içinde:

# 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 )

Ardından, admin.py'deki sınıflarımızı normal olarak miras alabiliriz:

class ContactAdmin(ReadOnlyAdmin):
    list_display = ("name","email","whatever")
    readonly_fields = ("updated","created")
    inlines = ( PhoneInline, ... )
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.