Di admin saya ingin menonaktifkan bidang saat memodifikasi objek, tetapi membuatnya diperlukan saat menambahkan objek baru.
Apa cara django melakukan yang satu ini?
Jawaban:
Anda dapat mengganti metode admin 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
Jika Anda ingin menyetel semua bidang sebagai hanya baca di tampilan ubah, timpa get_readonly_fields admin:
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
Dan jika Anda ingin menyembunyikan tombol simpan pada tampilan perubahan :
Ubah tampilan
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)
Ubah izin jika pengguna mencoba mengedit:
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
Solusi ini telah diuji melalui Django 1.11
FYI: jika orang lain mengalami dua masalah yang sama yang saya temui:
Anda tetap harus mendeklarasikan readonly_fields secara permanen di badan kelas, karena atribut kelas readonly_fields akan diakses dari validasi (lihat django.contrib.admin.validation: validate_base (), line.213 appx)
Ini tidak akan berfungsi dengan Inlines karena obj yang diteruskan ke get_readonly_fields () adalah objek induk (saya punya dua solusi yang agak hacky dan keamanan rendah menggunakan css atau js)
Variasi berdasarkan saran luar biasa sebelumnya dari Bernhard Vallant, yang juga mempertahankan kemungkinan penyesuaian yang diberikan oleh kelas dasar (jika ada):
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
Situasi dengan formulir sebaris masih belum diperbaiki untuk Django 2.2.x tetapi solusi dari John sebenarnya cukup cerdas.
Kode sedikit disesuaikan dengan situasi saya:
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)
# ...
Anda dapat melakukan ini dengan mengganti metode formfield_for_foreignkey dari 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)
Punya masalah serupa. Saya menyelesaikannya dengan "add_fieldsets" dan "limited_fieldsets" di 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', )}),
)
Silakan lihat misalnya: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py
Tapi ini tidak melindungi model Anda dari perubahan "add_objX" nanti. Jika Anda menginginkan ini juga, saya pikir Anda harus melewati fungsi "simpan" kelas Model dan memeriksa perubahan di sana.
Lihat: www.djangoproject.com/documentation/models/save_delete_hooks/
Astaga, Nick