3

DRF はeditable=Falseフィールドの を使用して、シリアライザーを読み取り専用にデフォルト設定します。これは私が利用する非常に便利で安全なデフォルトです (つまり、シリアライザーを読み取り専用に設定することを忘れません)。設定したらeditable=False、Django管理者にそれらのフィールドの1つを編集できるようにする方法はありますか?

おそらく管理者はスーパーユーザーであり、フィールドの値を変更できるようにしたいのですが、安全のためにデフォルトのSerializerロジックを読み取り専用にしたいと考えています。

アップデート

オブジェクトを作成するときに、実際には「設定」ほどフィールドを編集できる必要はありません。

4

2 に答える 2

4

あなたはこれについて間違った方法で進んでいます。

モデルは、モデル化するものの最も純粋な実装でなければなりません。モデルに関する何かが修正されている場合 (作成日など)、モデルで編集可能であってはなりません。変更可能な場合は、モデルで編集可能のままにします。

そうしないと、将来、あなた (または他の誰か) が、設定されているフィールドがeditable=Falseどのように変更されているのか不思議に思うかもしれません。特にドキュメントに記載されているように

False の場合、フィールドは admin またはその他の ModelForm に表示されません。また、モデルの検証中にもスキップされます。

(API などで) 編集できないビューが 1 つある場合は、そこでオーバーライドします。

モデルに複数のシリアライザーがある場合は、代わりに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 に答える