【问题标题】:How to implement update_or_create inside create method of ModelSerializer如何在 ModelSerializer 的 create 方法中实现 update_or_create
【发布时间】:2019-06-07 08:06:09
【问题描述】:

代码:

类 OTP(AppModel): phone_regex = RegexValidator(regex=r'^[6789]\d{9}$', message="电话号码无效。") phone_number = models.CharField(validators=[phone_regex], max_length=10, unique=True) 代码 = models.CharField(max_length=255) def __str__(self): 返回 str(self.phone_number) + ": "+str(self.code) 类 OTPSerializer(serializers.ModelSerializer): code = serializers.CharField(max_length=None, required=False) 元类: 型号 = OTP 字段 = ('id', 'code', 'phone_number') read_only_fields=('id', 'code') @transaction.atomic 定义创建(自我,验证数据): phone_number = 已验证数据.pop("phone_number") otp, 创建 = OTP.objects.update_or_create( phone_number=phone_number,默认值={"code": generate_otp()}) 返回 otp

我正在尝试在django-rest-frameworkModelSerializercreate 方法中执行update_or_create

但是,模型OTP 中的字段phone_number 必须是unique。因此unique=True

我能够发布phone_number 并创建对象。但是,再次发布相同的phone_number 会引发错误otp with this phone number already exists,而不是在它已经存在时更新它,因为我已经覆盖了create 方法。请帮忙!

【问题讨论】:

    标签: python django django-models django-rest-framework


    【解决方案1】:

    您可以使用Signals 以干净的方式执行此操作。简单地说,您可以将created 变量发送到您定义的receiver,并根据您的对象是否创建来处理它。在 REST 响应的情况下,只需覆盖 Serializer 中的 create 方法以根据您所处的状态返回数据,或者您在 APIView 中使用的 get/post/patch 方法不返回 serializer.data,而是返回你想要的任何东西。 以下是信号接收器的示例:

    @receiver(post_save, sender=settings.OTP_MODEL)
    def update(sender, instance=None, created=False, **kwargs):
        if created:
            # Do Something
        else:
            # Do Some Other thing
    

    【讨论】:

    • 请小心使用信号,因为它们不是原子的。您的序列化程序可以提交数据,并且信号对数据库所做的任何事情都在它自己的事务中。除非你用 django.db.transaction 中的 @atomic 来装饰视图
    【解决方案2】:

    尝试在您的序列化程序类中而不是在模型类中设置验证器。所以让你的序列化程序类看起来像这样:

    class OTPSerializer(serializers.ModelSerializer):
        code = serializers.CharField(max_length=None, required=False)
        phone_regex = RegexValidator(regex=r'^[6789]\d{9}$', message="phone no. is invalid.")  # add this line
        phone_number = serializers.CharField(validators=[phone_regex])  # and this line
        
        class Meta:
            model = OTP
            fields = ('id', 'code', 'phone_number')
            read_only_fields=('id', 'code')
    
        @transaction.atomic
        def create(self, validated_data):
            phone_number = validated_data.pop("phone_number")
            otp, created = OTP.objects.update_or_create(
                phone_number=phone_number, defaults={"code": generate_otp()})
            return otp
    

    【讨论】:

      【解决方案3】:

      您可以使phone_number 不需要,然后手动进行检查。您会收到错误消息,因为 DRF 在您之前验证了 phone_number。因此,基本上,解决方案可能如下(仅序列化代码):

      class OTPSerializer(serializers.ModelSerializer):
          code = serializers.CharField(max_length=None, required=False)
          class Meta:
              model = OTP
              fields = ('id', 'code', 'phone_number')
              read_only_fields=('id', 'code')
              extra_kwargs = {'phone_number': {'required': False}}
      
          @transaction.atomic
          def create(self, validated_data):
              phone_number = validated_data.pop("phone_number")
              otp, created = OTP.objects.update_or_create(
              phone_number=phone_number, defaults={"code": generate_otp()})
              return otp
      

      【讨论】:

      • 没有。 phone_number 是必需的。问题是:UniqueValidator 在到达 create 方法之前进行验证。
      猜你喜欢
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多