【问题标题】:Write only, read only fields in django rest frameworkdjango rest框架中的只写,只读字段
【发布时间】:2016-05-01 14:29:34
【问题描述】:

我有这样的模型:

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 中的“真实列”,所以当我尝试保存它时会引发异常。

我试图从验证数据中弹出它,但又在某个地方出现错误,无法从模型中读取 model_b_ids。关于正确使用这种字段的任何想法?

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    Django Rest 框架不再有 Meta 属性 write_only_fields

    根据他们的docs,您在 extra_kwargs 中设置了只写字段

    例如

    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}
            }
    

    更新

    正如@AKHIL MATHEW 在下面的回答中强调的那样

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

    只写

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

    默认为假 例如:

    company = serializers.PrimaryKeyRelatedField(write_only=True)

    【讨论】:

    • 请在下面找到我的答案,了解 DRF 版本 3 中的最新方法
    • 谢谢,会更新我的答案
    【解决方案2】:

    按照 Django REST 框架documentation

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

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

    extra_kwargs = {
        'model_b_ids': {'write_only': True},
        'another_field': {'read_only': True}
    }
    

    或:

     model_b_ids = serializers.IntegerField(write_only=True)
    

    【讨论】:

    • 我刚刚将 DRF 从 3.1.3 更新到 3.3.3,突然我的用户密码被发回(我之前有 write_only 元属性。您的解决方案解决了这个问题。谢谢!
    • @vabada 我希望你的意思是哈希?
    【解决方案3】:

    您可能正在监督您的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 类名称创建反向关系名称。 ModelBmodel_b_set 吗?还是modelb_set?你可以试试看。

    【讨论】:

      【解决方案4】:

      来自docs,您可以使用read_only

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

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

      默认为False

      例如:

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

      model_b_ids = serializers.IntegerField(read_only=True)
      

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

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

      【讨论】:

      • 难以捉摸,但这就是它在 Django 3.1 中的工作方式
      【解决方案5】:

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

      核心论点

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

      只读

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

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

      默认为假

      例如:

      price = serializers.IntegerField(read_only=True)
      

      只写

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

      默认为假

      例如:

      company = serializers.PrimaryKeyRelatedField(write_only=True)
      

      【讨论】:

        【解决方案6】:

        你可以重写 ASerializer 上的 serializer.save() 方法来实例化 modelA 对象,设置它的属性,保存它,然后在现有的 modelB 对象上设置关系,保存它们并成功。 但我认为也许按照建议在序列化程序上设置 related_name 和 RelatedField 会做完全相同的事情.. 输入更少.. 整体更好:)

        【讨论】:

          猜你喜欢
          • 2018-04-27
          • 1970-01-01
          • 2017-08-29
          • 2015-02-19
          • 2017-03-04
          • 2021-03-06
          • 2021-10-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多