ในผู้ดูแลระบบฉันต้องการปิดการใช้งานฟิลด์เมื่อแก้ไขอ็อบเจ็กต์ แต่ทำให้จำเป็นเมื่อเพิ่มอ็อบเจกต์ใหม่
django จะไปเกี่ยวกับเรื่องนี้อย่างไร?
ในผู้ดูแลระบบฉันต้องการปิดการใช้งานฟิลด์เมื่อแก้ไขอ็อบเจ็กต์ แต่ทำให้จำเป็นเมื่อเพิ่มอ็อบเจกต์ใหม่
django จะไปเกี่ยวกับเรื่องนี้อย่างไร?
คำตอบ:
คุณสามารถแทนที่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
หากคุณต้องการตั้งค่าฟิลด์ทั้งหมดเป็นแบบอ่านอย่างเดียวในมุมมองการเปลี่ยนแปลงให้แทนที่ 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
และหากคุณต้องการซ่อนปุ่มบันทึกในมุมมองการเปลี่ยนแปลง :
เปลี่ยนมุมมอง
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)
เปลี่ยนสิทธิ์หากผู้ใช้พยายามแก้ไข:
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
FYI: ในกรณีที่มีคนอื่นประสบปัญหาสองประการเดียวกันกับที่ฉันพบ:
คุณยังควรประกาศ readonly_fields อย่างถาวรในเนื้อหาของคลาสเนื่องจากแอตทริบิวต์คลาส readonly_fields จะเข้าถึงได้จากการตรวจสอบความถูกต้อง (ดู django.contrib.admin.validation: validate_base (), line.213 appx)
สิ่งนี้จะใช้ไม่ได้กับ Inlines เนื่องจาก obj ส่งไปยัง get_readonly_fields () คือ obj หลัก (ฉันมีโซลูชันที่ค่อนข้างแฮ็กและมีความปลอดภัยต่ำโดยใช้ css หรือ js)
รูปแบบตามข้อเสนอแนะที่ยอดเยี่ยมก่อนหน้านี้ของ 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
สถานการณ์ที่มีรูปแบบอินไลน์ยังไม่ได้รับการแก้ไขสำหรับ 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)
# ...
คุณสามารถทำได้โดยการแทนที่เมธอด formfield_for_foreignkey ของ 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)
มีปัญหาที่คล้ายกัน ฉันแก้ไขด้วย "add_fieldsets" และ "restricted_fieldsets" ใน 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', )}),
)
โปรดดูตัวอย่าง: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py
แต่สิ่งนี้ไม่ได้ป้องกันโมเดลของคุณจากการเปลี่ยนแปลงในภายหลังของ "add_objX" ถ้าคุณต้องการสิ่งนี้เช่นกันฉันคิดว่าคุณต้องทำตามฟังก์ชัน "บันทึก" คลาส Model และตรวจสอบการเปลี่ยนแปลง
ดู: www.djangoproject.com/documentation/models/save_delete_hooks/
Greez นิค
โซลูชันที่เสียบได้มากขึ้นสำหรับโซลูชันที่ยอดเยี่ยมของ Bernhard และ Mario ซึ่งเพิ่มการสนับสนุนสำหรับ createonly_fields analog ไปยัง readonly_fields:
class MyModelAdmin(admin.ModelAdmin):
# ModelAdmin configuration as usual goes here
createonly_fields = ['title', ]
def get_readonly_fields(self, request, obj=None):
readonly_fields = list(super(MyModelAdmin, self).get_readonly_fields(request, obj))
createonly_fields = list(getattr(self, 'createonly_fields', []))
if obj: # editing an existing object
readonly_fields.extend(createonly_fields)
return readonly_fields