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:
Bạn có thể ghi đè get_readonly_fields
phươ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
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
Và nếu bạn muốn ẩn các nút lưu trên chế độ xem thay đổi :
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)
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
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:
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)
Đ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)
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
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)
# ...
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)
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