只写,只读django rest框架中的字段

时间:2016-01-25 10:11:27

标签: django django-rest-framework

我有这样的模特:

class ModelA(models.Model):
    name = models.CharField()


class ModelB(models.Model):
    f1 = models.CharField()
    model_a = models.ForeignKey(ModelA)

串行器:

class ASerializer(serializers.ModelSerializer):
    model_b_ids = serializers.CharField()
    class Meta:
        model = ModelA
        write_only_fields = ('model_b_ids',)

的观点:

class AView(CreateModelMixin, GenericViewSet):

    def perform_create(self, serializer): 
        model_b_ids = parse_somehow(serializer.validated_data["model_b_ids"])
        #do something...

我得到的问题是“model_b_ids”

用户应在发送帖子数据时提交。

我在perform_create中使用它来链接到相关模型。

但那不是ModelA中的“真正的专栏”所以当我试图保存它时会引发异常。

我尝试从validated_data弹出,然后再次在某处无法从模型中读取model_b_ids的错误。有没有正确使用这种领域的想法?

6 个答案:

答案 0 :(得分:58)

如果我错了,请纠正我,但我不认为django rest framework有Meta属性

write_only_fields

根据 docs ,您在extra_kwargs中设置只写字段

e.g

class UserSerializer(ModelSerializer):
    """
    ``Serializer`` for ``User`` ..
    """

    class Meta:
        model = User
        fields = ('id', 'email', 'first_name', 'last_name' ,'security_question', 'security_question_answer', 'password', 'is_active', 'is_staff')
        read_only_fields = ('is_active', 'is_staff')
        extra_kwargs = {
            'security_question': {'write_only': True},
            'security_question_answer': {'write_only': True},
            'password': {'write_only': True}
        }

答案 1 :(得分:39)

根据Django REST框架documentation

  

ModelSerializer上的write_only_fields选项已移至PendingDeprecation并替换为更通用的extra_kwargs

这就是为什么建议这样做的原因:你应该使用extra_kwargs:

extra_kwargs = {'model_b_ids': {'write_only': True}}

或:

 model_b_ids = serializers.IntegerField(write_only=True)

答案 2 :(得分:2)

您可能正在监督ModelA拥有财产modelb_set。在Django中,您可以在一个模型类中描述关系。 Django通过降低目标模型的下限并将其后缀为_set来提供向后关系。所以你可以这样做:

a = ModelA.objects.get(pk=1)
a.modelb_set.all()

这将从ModelA获取具有ID(或主键)1的元素,并检索所有相关的ModelB元素。

您可以设置related_name的值以覆盖默认值:

class ModelB(models.Model):
    f1 = models.CharField()
    model_a = models.ForeignKey(ModelA, related_name='model_b')

在DRF中,您可以稍微调整序列化程序:

class ASerializer(serializers.ModelSerializer):
    model_b = serializers.PrimaryKeyRelatedField(many=True, read_only=False)

    class Meta:
        model = ModelA
        write_only_fields = ('model_b',)

使用serializers.CharField(),您无法发布值并将其写入模型,因为它不是模型字段。

试试这个例子。修补和实验。它应该让你更接近解决方案。

编辑: 我不确定Django如何为PascalCase类名的后向关系创建名称。 model_b_setModelB吗?或者是modelb_set?你可以尝试找出它。

答案 3 :(得分:2)

从 DRF v3 开始,将字段设置为只读或只写可以使用序列化程序字段核心参数,如下所述。

核心论点

<块引用>

每个序列化器字段类构造函数至少需要 这些论点。一些 Field 类需要额外的、特定于字段的 参数,但应始终接受以下内容:

只读

<块引用>

只读字段包含在 API 输出中,但应该 在创建或更新操作期间不包含在输入中。任何 序列化程序中错误包含的“只读”字段 输入将被忽略。

将此设置为 True 以确保在序列化 a 时使用该字段 表示,但在创建或更新实例时不使用 在反序列化期间。

默认为 False

例如:

price = serializers.IntegerField(read_only=True)

只写

<块引用>

将此设置为 True 以确保该字段可在以下情况下使用 更新或创建实例,但在序列化时不包括在内 表示。

默认为 False

例如:

company = serializers.PrimaryKeyRelatedField(write_only=True)

答案 4 :(得分:1)

docs中,您可以使用read_only

  

只读字段包含在API输出中,但在创建或更新操作期间不应包含在输入中。错误地包含在序列化器输入中的所有“只读”字段都将被忽略。

     

将此字段设置为True以确保序列化表示形式时使用该字段,而在反序列化期间创建或更新实例时不使用该字段。

     

默认为False

例如:

我们可以在序列化器字段中使用它:

model_b_ids = serializers.IntegerField(read_only=True)

或者我们可以在extra_kwargs中使用它:

extra_kwargs = {
    'model_b_ids': {'read_only': True}
}

答案 5 :(得分:0)

你可以覆盖ASerializer上的serializer.save()方法来实例化modelA对象,设置它的属性,保存它,然后在现有的modelB对象上设置关系,保存它们并喝到成功。 但我认为也许在建议的序列化器上设置related_name和RelatedField会做同样的事情......打字更少......整体更好:)