DRF will use the editable=False
on a field to default the Serializer to read-only。这是我利用的一个非常有用/安全的默认值(即我不会忘记将Serializer设置为只读)。有人说,一旦我设置了editable=False
,就有办法强制Django管理员允许编辑其中一个字段吗?
据推测,管理员是一个超级用户,我确实希望他能够更改字段值但是安全性我希望默认的Serializer
逻辑是只读的。
更新
我实际上并不需要像#34; set-it"那样编辑字段。当我创建对象时。
答案 0 :(得分:3)
你这是错误的做法。
您的模型应该是您正在建模的事物的最纯粹的实现。如果关于模型的某些内容是固定的(例如创建日期),则它不应该在模型中可编辑,如果它是可变的,则在模型中保留为可编辑。
否则,将来你(或其他人)可能会不知道为什么设置为editable=False
的字段会被改变。 Especially as the documentation states:
如果为False,该字段将不会显示在admin或任何其他ModelForm中。在模型验证过程中也会跳过它们。
如果您有一个不应该可编辑的视图(例如在API中),请在那里覆盖它。
如果您有一个模型的多个序列化器,而是创建一个带有read_only_fields
集的抽象序列化器,然后将其子类化。例如:
class AbstractFooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
read_only_fields = ('bar',)
class MainFooSerializer(AbstractFooSerializer):
pass
class DifferentFooSerializer(AbstractFooSerializer):
pass
如果你真的,真的想要使用editable=False
,但允许在管理网站中仅在创建上编辑项目,那么你就会有一场上山战。
可能最好的方法是重新实现您用于管理员的AdminForm
所以而不是:
class FooAdmin(admin.ModelAdmin):
使用:
class FooAdmin(admin.ModelAdmin):
form = MySpecialForm
然后声明表格:
class MySpecialForm(forms.Model):
def __init__(self, *args, **kwargs):
self.is_new = False
if kwargs.get('instance',None) is None:
# There is no instance, thus its a new item
self.is_new = True
self.fields['one_time_field'] = forms.CharField() # Or what have you.
super(MySpecialForm, self).__init__(*args, **kwargs)
def save(self, commit=True):
instance = super(MySpecialForm, self).save(commit)
if self.is_new:
instance.your_one_time_only_field = self.one_time_field
instance.save()
return instance
注意:您需要手动添加字段并保存要为其执行此操作的每个readonly
字段。这可能是也可能不是100%有效。
答案 1 :(得分:1)
对于那些只想在创建期间允许编辑不可编辑字段的人(尚无instance.pk
):
# models.py
class Entity(Model):
name = CharField(max_length=200, unique=True, null=False, blank=False, editable=False)
# admin.py
@register(Entity)
class EntityAdmin(ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if obj: # This is the case when obj is already created i.e. it's an edit
return ['id', 'name']
else:
return []
# this override prevents that the new_name field shows up in the change form if it's not a creation
def get_form(self, request, obj=None, **kwargs):
orig_self_form = self.form
if not obj:
self.form = CreateEntityForm
result = super().get_form(request, obj=obj, **kwargs)
self.form = orig_self_form
return result
# forms.py
class CreateEntityForm(ModelForm):
new_name = CharField(max_length=200, min_length=2, label='Name', required=True)
def clean_new_name(self):
code = self.cleaned_data['new_name']
# validate uniqueness - if you need
exists = Entity.objects.filter(name=code).first()
if exists:
raise ValidationError('Entity with this name already exists: {}', exists)
return name
def save(self, commit=True):
if self.instance.pk:
raise NotImplementedError('Editing of existing Entity is not allowed!')
self.instance.name = self.cleaned_data['new_name'].upper()
return super().save(commit)
class Meta:
model = Entity
fields = ['new_name']
exclude = ['id', 'name']