在管理员中,我想在修改对象时禁用字段,但在添加新对象时将其设为必填字段。
django如何处理这个问题?
Answers:
您可以覆盖管理员的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上进行了测试
仅供参考:如果有人遇到我遇到的两个同样的问题:
您仍应在类的主体中声明任何永久性的readonly_fields,因为readonly_fields类属性将从验证中访问(请参阅django.contrib.admin.validation:validate_base(),line.213 appx)。
这不适用于Inlines,因为传递给get_readonly_fields()的obj是父obj(我有两个使用CSS或JS的非常hacky和低安全性的解决方案)
基于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)
    # ...
    您可以通过重写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)
    有类似的问题。我在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类的“保存”功能并检查那里的更改。
请参阅:www.djangoproject.com/documentation/models/save_delete_hooks/
尼克·格雷兹