django adminは、objを変更するときはフィールドを読み取り専用にしますが、新しいobjを追加するときは必須です


91

管理者では、オブジェクトを変更するときにフィールドを無効にしたいのですが、新しいオブジェクトを追加するときに必須にします。

これについて行くためのジャンゴの方法は何ですか?

回答:


176

管理者のget_readonly_fieldsメソッドをオーバーライドできます。

class MyModelAdmin(admin.ModelAdmin):

    def get_readonly_fields(self, request, obj=None):
        if obj: # editing an existing object
            return self.readonly_fields + ('field1', 'field2')
        return self.readonly_fields

21
マイナー/メジャー警告:これはインラインでは機能しません。動的な[別のXを追加]ボタンは、読み取り専用フィールドを「(なし)」と表示しますが、期待どおりのフォームフィールドではありません。
セリン2013年

17

変更ビューですべてのフィールドを読み取り専用設定する場合は、管理者のget_readonly_fieldsをオーバーライドします。

def get_readonly_fields(self, request, obj=None):
    if obj: # editing an existing object
        # All model fields as read_only
        return self.readonly_fields + tuple([item.name for item in obj._meta.fields])
    return self.readonly_fields

また、ビューの変更で保存ボタンを非表示にする場合

  1. ビューを変更する

    def change_view(self, request, object_id, form_url='', extra_context=None):
        ''' customize edit form '''
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        extra_context['show_save_and_add_another'] = False # this not works if has_add_permision is True
        return super(TransferAdmin, self).change_view(request, object_id, extra_context=extra_context)
    
  2. ユーザーが編集しようとしている場合は、権限を変更します。

    def has_add_permission(self, request, obj=None):
       # Not too much elegant but works to hide show_save_and_add_another button
        if '/change/' in str(request):
            return False
        return True
    

    このソリューションはDjango1.11でテストされています


完璧です。これはまさに私が必要としていたものです!
wogsland 2018

3

参考:他の誰かが私が遭遇した同じ2つの問題に遭遇した場合:

  1. readonly_fieldsクラス属性は検証からアクセスされるため、クラスの本体で永続的にreadonly_fieldsを宣言する必要があります(django.contrib.admin.validation:validate_base()、line.213 appxを参照)

  2. get_readonly_fields()に渡されるobjが親objであるため、これはInlinesでは機能しません(cssまたはjsを使用した2つのかなりハッキーでセキュリティの低いソリューションがあります)


2
2.ポイント-これは管理者のバグによるものです:#15602すぐには修正されないようです(2年前の最後のアクティビティ)ので、CSS / JSソリューションに任されているようです。
frnhr 2014年

2

Bernhard Vallantの以前の優れた提案に基づくバリエーションであり、基本クラス(存在する場合)によって提供される可能なカスタマイズも保持します。

class MyModelAdmin(BaseModelAdmin):

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = super(MyModelAdmin, self).get_readonly_fields(request, obj)
        if obj: # editing an existing object
            return readonly_fields + ['field1', ..]
        return readonly_fields

2

インラインフォームの状況はDjango2.2.xではまだ修正されていませんが、Johnソリューションは実際にはかなり賢いです。

私の状況に少し調整されたコード:

class NoteListInline(admin.TabularInline):
""" Notes list, readonly """
    model = Note
    verbose_name = _('Note')
    verbose_name_plural = _('Notes')
    extra = 0
    fields = ('note', 'created_at')
    readonly_fields = ('note', 'created_at')

    def has_add_permission(self, request, obj=None):
    """ Only add notes through AddInline """
    return False

class NoteAddInline(admin.StackedInline):
    """ Notes edit field """
    model = Note
    verbose_name = _('Note')
    verbose_name_plural = _('Notes')
    extra = 1
    fields = ('note',)
    can_delete = False

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.none()  # no existing records will appear

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    # ...
    inlines = (NoteListInline, NoteAddInline)
    # ...

0

これを行うには、ModelAdminのformfield_for_foreignkeyメソッドをオーバーライドします。

from django import forms
from django.contrib import admin

from yourproject.yourapp.models import YourModel

class YourModelAdmin(admin.ModelAdmin):

    class Meta:
        model = YourModel

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        # Name of your field here
        if db_field.name == 'add_only':
            if request:
                add_opts = (self._meta.app_label, self._meta.module_name)
                add = u'/admin/%s/%s/add/' % add_opts
                if request.META['PATH_INFO'] == add:
                    field = db_field.formfield(**kwargs)
                else:
                    kwargs['widget'] = forms.HiddenInput()
                    field = db_field.formfield(**kwargs)
            return field
        return admin.ModelAdmin(self, db_field, request, **kwargs)

0

同様の問題が発生しました。ModelAdminの「add_fieldsets」と「restricted_fieldsets」で解決しました。

from django.contrib import admin  
class MyAdmin(admin.ModelAdmin):
 declared_fieldsets = None
 restricted_fieldsets = (
    (None, {'fields': ('mod_obj1', 'mod_obj2')}),
    ( 'Text', {'fields': ('mod_obj3', 'mod_obj4',)}),
 )

 add_fieldsets = (
            (None, {
             'classes': ('wide',),
             'fields': ('add_obj1', 'add_obj2', )}),
             )

例を参照してください:http//code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

ただし、これは「add_objX」のその後の変更からモデルを保護するものではありません。これも必要な場合は、Modelクラスの「保存」関数を調べて、そこで変更を確認する必要があると思います。

参照:www.djangoproject.com/documentation/models/save_delete_hooks/

グリーズ、ニック

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.