web-dev-qa-db-ja.com

Django admin interface?の読み取り専用モデル?

管理インターフェイスでモデルを完全に読み取り専用にするにはどうすればよいですか?これは、管理機能を使用して検索、並べ替え、フィルタリングなどを行う一種のログテーブル用ですが、ログを変更する必要はありません。

これが重複しているように見える場合は、ここにnotがあります:

  • 私は読み取り専用を探していませんフィールド(すべてのフィールドを読み取り専用にしても、新しいレコードを作成できます)
  • 読み取り専用を作成するつもりはありませんser:すべてのユーザーは読み取り専用である必要があります。
75
Steve Bennett

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(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 %}
16

管理者は、表示するだけでなく編集するためのものです(「表示」権限はありません)。目的を達成するには、追加、削除を禁止し、すべてのフィールドを読み取り専用にする必要があります。

class MyAdmin(ModelAdmin):

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

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

(変更を禁止すると、オブジェクトを見ることさえできなくなります)

すべてのフィールドの読み取り専用設定を自動化しようとする未テストのコードについては、 読み取り専用としてのモデル全体

編集:テストもされていませんが、私のLogEntryAdminを見て、

readonly_fields = MyModel._meta.get_all_field_names()

それがすべての場合に機能するかどうかわからない。

編集:QuerySet.delete()はまだオブジェクトを一括削除できます。これを回避するには、独自の「オブジェクト」マネージャーと、削除しない対応するQuerySetサブクラスを提供します- DjangoでQuerySet.delete()をオーバーライドする を参照してください

66
Danny W. Adair

モデルを作成するために使用している、またはインライン読み取り専用の2つのクラスを次に示します。

モデル管理者の場合:

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

インラインの場合:

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
43
darklow

ユーザーが編集できないことを認識したい場合は、最初のソリューションで2つのピースが欠落しています。削除アクションを削除しました!

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

2つ目:読み取り専用ソリューションはプレーンモデルで正常に機能します。ただし、外部キーを持つ継承モデルがある場合、[〜#〜] not [〜#〜]は機能します。残念ながら、その解決策はまだわかりません。良い試みは次のとおりです。

読み取り専用としてのモデル全体

しかし、それは私にとってもうまくいきません。

最後の注意点として、広範なソリューションを検討する場合は、各インラインも読み取り専用にする必要があります。

12
Josir

実際、次の簡単な解決策を試すことができます。

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

    def has_add_permission(self, request):
        return False
_
  • _actions = None_:「選択項目を削除...」オプションでドロップダウンを表示しないようにします
  • _list_display_links = None_:列をクリックしてそのオブジェクトを編集することを避けます
  • has_add_permission() Falseを返すと、そのモデルの新しいオブジェクトの作成が回避されます
7
Iván Zugnoni

これは、18年8月1日にリリースされたDjango 2.1に追加されました!

ModelAdmin.has_view_permission()は、既存のhas_delete_permission、has_change_permission、およびhas_add_permissionと同じです。あなたはドキュメントでそれを読むことができます here

リリースノートから:

これにより、ユーザーに管理者のモデルへの読み取り専用アクセス権を付与できます。 ModelAdmin.has_view_permission()は新しいです。実装には下位互換性があり、「変更」権限を持つユーザーがオブジェクトを編集できるように「表示」権限を割り当てる必要はありません。

5
grrrrrr

受け入れられた答えがうまくいかない場合は、これを試してください:

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
4
Wouter

@darklowと@josirの優れた答えをコンパイルし、さらに「保存」ボタンと「保存して続行」ボタンを削除するためにもう少し追加すると、(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

そして、あなたは

class MyModelAdmin(ReadOnlyAdmin):
    pass

Django 1.11/Python 3。

4
Mark Chackerian

受け入れられた回答は機能するはずですが、これにより、読み取り専用フィールドの表示順序も保持されます。また、このソリューションを使用してモデルをハードコーディングする必要もありません。

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
2

Django adminがDjango module "Django-admin-view-を利用して終了した特定のユーザーのすべてのフィールドを読み取り専用にする必要がある場合、同じ要件に遭遇しました独自のコードをローリングせずに許可」を選択します。どのフィールドを明示的に定義するために、よりきめ細かい制御が必要な場合は、モジュールを拡張する必要があります。プラグインの動作を確認できます here

1
Timothy

読み取り専用=>ビュー許可

  1. pipenv install Django-admin-view-permission
  2. 次のようにsettings.py。のINSTALLED_APPSに「admin_view_permission」を追加します: `INSTALLED_APPS = ['admin_view_permission'、
  3. python manage.py migrate
  4. python manage.py runserver 6666

「ビュー」権限で楽しんでください

0
Xianhong Xu

インラインを含むユーザーのアクセス許可に応じて読み取り専用ビューを処理する汎用クラスを作成しました;)

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

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 )

次に、通常どおりadmin.pyのクラスを継承します。

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