django 관리자는 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"단추는 읽기 전용 필드를 예상 한 양식 필드가 아닌 "(없음)"으로 표시합니다.
Cerin 2013-01-22

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
    

    이 솔루션은 Django 1.11 에서 테스트되었습니다.


완전한. 이것이 바로 내가 필요한 것입니다!
wogsland

3

참고 : 다른 사람이 내가 겪은 동일한 두 가지 문제에 직면 한 경우 :

  1. readonly_fields 클래스 속성은 유효성 검사에서 액세스되므로 클래스 본문에 영구적으로 readonly_fields를 선언해야합니다 (django.contrib.admin.validation : validate_base (), line.213 appx 참조).

  2. get_readonly_fields ()에 전달 된 obj가 부모 obj이므로 인라인에서는 작동하지 않습니다 (css 또는 js를 사용하는 다소 해키하고 보안 수준이 낮은 솔루션이 두 개 있습니다)


2
2. 포인트-이것은 관리자의 버그 때문입니다. # 15602 곧 수정되지 않을 것 같으므로 (2 년 전 마지막 활동) CSS / JS 솔루션에 맡겨진 것 같습니다.
frnhr

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

인라인 양식 의 상황 은 여전히 ​​Django 2.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 클래스 "save"함수를 넘어 가서 변경 사항을 확인해야한다고 생각합니다.

참조 : www.djangoproject.com/documentation/models/save_delete_hooks/

Greez, Nick

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.