Quản trị viên django đặt trường chỉ đọc khi sửa đổi obj nhưng bắt buộc khi thêm obj mới


91

Trong quản trị, tôi muốn tắt một trường khi sửa đổi đối tượng, nhưng yêu cầu nó khi thêm đối tượng mới.

Cách django để đi về cái này là gì?

Câu trả lời:


176

Bạn có thể ghi đè get_readonly_fieldsphương thức của quản trị viên :

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
Cảnh báo nhỏ / lớn: Điều này không hoạt động đối với nội tuyến. Nút động "thêm một X khác" hiển thị trường chỉ đọc là "(Không có)", không phải trường biểu mẫu như bạn mong đợi.
Cerin

17

Nếu bạn muốn đặt tất cả các trường là chỉ đọc trên dạng xem thay đổi, hãy ghi đè get_readonly_fields của quản trị viên:

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

nếu bạn muốn ẩn các nút lưu trên chế độ xem thay đổi :

  1. Thay đổi chế độ xem

    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. Thay đổi quyền nếu người dùng đang cố gắng chỉnh sửa:

    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
    

    Giải pháp này đã được thử nghiệm trên Django 1.11


Hoàn hảo. Đây chính xác là những gì tôi cần!
wogsland

3

FYI: trong trường hợp người khác gặp phải hai vấn đề tương tự mà tôi gặp phải:

  1. Bạn vẫn nên khai báo bất kỳ trường readonly_fields vĩnh viễn nào trong phần thân của lớp, vì thuộc tính lớp readonly_fields sẽ được truy cập từ xác thực (xem django.contrib.admin.validation: validate_base (), line.213 appx)

  2. Điều này sẽ không hoạt động với Inlines vì ​​obj được chuyển đến get_readonly_fields () là obj gốc (Tôi có hai giải pháp khá hack và bảo mật thấp sử dụng css hoặc js)


2
2. point - đó là do lỗi trong quản trị viên: # 15602 Có vẻ như nó sẽ không được sửa sớm (hoạt động gần đây nhất cách đây 2 năm), vì vậy có vẻ như chúng ta đang sử dụng các giải pháp CSS / JS.
frnhr

2

Một biến thể dựa trên gợi ý tuyệt vời trước đây của Bernhard Vallant, cũng bảo tồn mọi tùy chỉnh có thể có được cung cấp bởi lớp cơ sở (nếu có):

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

Tình trạng với các biểu mẫu nội tuyến vẫn chưa được khắc phục cho Django 2.2.x nhưng giải pháp từ John thực sự khá thông minh.

Mã điều chỉnh một chút cho tình huống của tôi:

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

Bạn có thể thực hiện việc này bằng cách ghi đè phương thức formfield_for_foreignkey của ModelAdmin:

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

Có một vấn đề tương tự. Tôi đã giải quyết nó bằng "add_fieldsets" và "limited_fieldsets" trong ModelAdmin.

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

Vui lòng xem ví dụ: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

Nhưng điều này không bảo vệ mô hình của bạn khỏi những thay đổi sau này của "add_objX". Nếu bạn cũng muốn điều này, tôi nghĩ bạn phải đi qua chức năng "lưu" của lớp Model và kiểm tra các thay đổi ở đó.

Xem: www.djangoproject.com/documentation/models/save_delete_hooks/

Greez, Nick

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.