3

DRF 将使用editable=Falseon a 字段将 Serializer 默认为 read-only。这是我利用的一个非常有用/安全的默认设置(即我不会忘记将 Serializer 设置为只读)。话虽如此,一旦我设置editable=False了,有什么方法可以强制 Django 管理员允许编辑其中一个字段?

大概管理员是超级用户,我确实希望他能够更改字段值,但为了安全起见,我希望默认Serializer逻辑是只读的。

更新

当我创建对象时,我实际上不需要像“set-it”那样编辑字段。

4

2 回答 2

4

你正在以错误的方式解决这个问题。

您的模型应该是您正在建模的事物的最纯粹的实现。如果有关模型的某些内容是固定的(例如创建日期),则它不应该在模型中可编辑,如果它是可变的,则在模型中保留为可编辑。

否则,将来您(或其他人)可能会想知道为什么设置为的字段是editable=False如何更改的。特别是如文档所述

如果为 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% 的功能。

于 2015-03-18T22:31:33.313 回答
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']
于 2017-06-23T11:18:28.557 回答