Django管理インターフェースのReadonlyモデル?

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

これが重複しているように見える場合は、私がしようとしている not

  • 私はreadonly フィールドを探していません(すべてのフィールドを読み取り専用にしても、新しいレコードを作成することさえできます)。
  • 私は読書専用のユーザーを作成するつもりはない:すべてのユーザーは読書だけでなければならない。
66
すぐにこの機能が提供されるはずです: github.com/django/django/pull/5297
追加された 著者 Bosco,

12 答え

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

class MyAdmin(ModelAdmin):

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

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

(あなたが変更を禁止しても、オブジェクトを見ることさえできません)

For some untested code that tries to automate setting all fields read-only see my answer to Whole model as read-only

編集:また、私のLogEntryAdminを見ていたが、テストされている

readonly_fields = MyModel._meta.get_all_field_names()

すべてのケースでうまくいくかどうかは分かりません。

EDIT: QuerySet.delete() may still bulk delete objects. To get around this, provide your own "objects" manager and corresponding QuerySet subclass which doesn't delete - see Overriding QuerySet.delete() in Django

63
追加された
ほぼ完璧です。編集ページに行がリンクされないようにする方法があれば、貪欲に尋ねることはできますか? (再び、行を拡大する必要はなく、何も編集する必要はありません)
追加された 著者 Steve Bennett ㄹ,
btw、はいreadonly_fields = ...は動作します。
追加された 著者 Steve Bennett ㄹ,
これはうまくいかなかった:def __init __(self、* args):super(RegistrationStatusAdmin、self).__ init __(* args)self.display_links = []
追加された 著者 Steve Bennett ㄹ,
ああ、しかし、 'list_display_links'を使って:)感謝します。
追加された 著者 Steve Bennett ㄹ,
readonly_fieldsメソッドの場合+1。
追加された 著者 jterrace,
確かに、これはおそらくOPが求めている最も近いものですが、ユーザーに読み取り専用アクセスを明示的に与えていないため、これは本当に理想的ではありません。あなたはそれをmodeladminにハードコーディングしていますが、ユーザーには「変更」アクセスを与えますが、これは直感的ではありません。理想的には、ユーザーに明示的な「表示」権限を与えてから、その権限の追加/変更/削除の許可を取り消します。残念なことに、Djangoのコア開発者は、この望ましい解決策には関心がありません。
追加された 著者 Cerin,
P.S .:とはい、他の答えと同じように、おそらくReadOnlyAdminクラスでこれらの3つのものを定義し、そのクラスからサブクラス化すればその動作が必要になるでしょう。 {{i>編集可能ながあるグループ/パーミッションの定義を許可して、それに対応してTrueを返すようにして、リクエストにアクセスできるget_readonly_fields()を使用することもできます。
追加された 著者 Danny W. Adair,
私はあなたがなぜこの答えを下降させるのか分かりません - それはただの混乱を扱っているだけです! Djangoチケット#820は9年前に "wontfix"でオープンしました。私はまだクリーナーReadOnlyModelAdminを考えることができません。 Btwは理想的な方法では明示的にユーザーに "view"権限を与えません。 - 権限を持っていない場合( "変更"アクセス権によって "暗黙の"可能性がある)、ユーザーは現在の管理者そのモデルはそのユーザーの管理画面に表示されません。
追加された 著者 Danny W. Adair,
ええ、Djangoで "表示"権限があった場合、この質問はおそらく起きなかったでしょう。 :-)
追加された 著者 Danny W. Adair,
モデルから設定されているreadonly_fieldsに関しては、フォームをオーバーライドして他のフィールドを追加した場合、これはうまくいかないでしょう。実際のフォームフィールドに基づいているほうがおそらく良いでしょう。
追加された 著者 Danny W. Adair,
ModelAdminのlist_display_linksをFalse(空のリスト/タプルなど)と評価するものに設定した場合、ModelAdmin .__ init __()はlist_display_linksをすべての列に設定します(アクションチェックボックスを除く)。リンクがあることを確認するが完了したと思います。ですから、私はReadOnlyAdminで__init __()をオーバーライドし、親のものを呼び出し、list_display_linksを空のリストまたはタプルに設定します。 readonlyの変更フォームへのリンクがないことを考えれば、これはおそらくパラメータ/クラス属性を作成するのに最適です。一般的に望ましい動作ではないと思います。 Hth
追加された 著者 Danny W. Adair,
どうすればdjangoパネルから設定できますか?コードではない
追加された 著者 Moe Far,
ここで説明した def save_model(..):によって保存された変更が保存されないようにすることができます
追加された 著者 connorbode,

モデルを作るために私が使用している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
40
追加された
1つのサブクラスに両方のクラスを適用する方法。例えば。クラスに通常のフィールドとインラインがある場合は?両方を拡張できますか?
追加された 著者 Timo,
@timoこれらのクラスを使用する mixins
追加された 著者 MartinM,
ReadOnlyAdmin has_add_permission はパラメータとしてリクエストのみを受け取ります
追加された 著者 MartinM,

ユーザーが編集することができないことをユーザーに認識させたい場合は、最初の解決策では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

Second:読み取り専用のソリューションは、普通のモデルでうまく動作します。しかし、外部キーを持つモデルを継承している場合は、 NOT が機能します。残念ながら、私はそれについての解決策はまだ分かりません。良い試みは次のとおりです。

全体モデルを読み取り専用

しかし、私にとってはうまくいかない。

最後に、広い解決策を考える場合は、各インラインを読み込み専用にする必要があります。

12
追加された

See 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">
    {% blocktrans %}Back to list{% endblocktrans %}
  </div>
{% endblock %}

templates/admin/view.html(Grappelli用)

{% extends "admin/change_form.html" %}
{% load i18n %}

{% block submit_buttons_bottom %}
  
{% endblock %}
11
追加された
スジは通ってるようだ。私はDjangoを使用してからずっとずっとずっと待っていました。
追加された 著者 Steve Bennett ㄹ,
これは Model 、または ModelAdmin のミックスインですか?
追加された 著者 OrangeDog,
Django 1.8以降では、get_all_field_namesは非推奨です。 後方互換性のある方法取得するための簡単な方法
追加された 著者 fzzylogic,
これは ModelAdmin のためのものです。
追加された 著者 Pascal Polleunus,

実際には、この簡単なソリューションを試すことができます:

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

    def has_add_permission(self, request):
        return False
  • actions = None: avoids showing the dropdown with the "Delete selected ..." option
  • list_display_links = None: avoids clicking in columns to edit that object
  • has_add_permission() returning False avoids creating new objects for that model
6
追加された

受け入れられた回答がうまくいかない場合は、次のようにしてください:

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
追加された

@darklowと@josirの優れた答えをコンパイルし、 "Save"と "Save and Continue"ボタンをもう少し削除すると、(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で試してみました。

3
追加された
私はDjangoを使用して以来、非常に長い時間が経ちました。誰かがこれを保証することはできますか?
追加された 著者 Steve Bennett ㄹ,
@SteveBennettㄹこの問題に対処するためのさまざまなバリエーションがあります。この答えは水密ではありません。ここで説明することをおすすめします: stackoverflow.com/a/36019597/2586761 stackoverflow.com/a/33543817/2586761にコメントした回答受け入れられた回答よりも完全な
追加された 著者 ptim,

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

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
追加された

I ran into the same requirement when needing to make all fields readonly for certain users in django admin ended up leveraging on django module "django-admin-view-permission" without rolling my own code. If you need more fine grained control to explicitly define which fields then you would need to extend the module. You can check out the plugin in action here

1
追加された

これは8/1/18にリリースされたDjango 2.1に追加されました!

ModelAdmin.has_view_permission() is just like the existing has_delete_permission, has_change_permission and has_add_permission. You can read about it in the docs here

リリースノートから:

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

1
追加された

read-only => views permission

  1. pipenv install django-admin-view-permission
  2. add 'admin_view_permission' to INSTALLED_APPS in the settings.py.like this: `INSTALLED_APPS = [ 'admin_view_permission',
  3. python manage.py migrate
  4. python manage.py runserver 6666

'views'権限でok.haveを楽しむ

0
追加された

私は、インラインを含むユーザ権限に応じてReadOnlyビューを扱う汎用クラスを作成しました;)

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 )

Then, we can just inherit normally our classes admin.py:

class ContactAdmin(ReadOnlyAdmin):
    list_display = ("name","email","whatever")
    readonly_fields = ("updated","created")
    inlines = ( PhoneInline, ... )
0
追加された