如何在ModelSerializer的create方法中实现update_or_create

时间:2019-01-12 18:49:29

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

代码:

class OTP(AppModel):
    phone_regex = RegexValidator(regex=r'^[6789]\d{9}$', message="phone no. is invalid.")
    phone_number = models.CharField(validators=[phone_regex], max_length=10, unique=True)
    code = models.CharField(max_length=255)

    def __str__(self):
        return str(self.phone_number) + ": "+str(self.code)

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')

    @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

我正在尝试在update_or_create的{​​{1}}的{​​{1}}方法中进行create

但是,模型django-rest-framework中的字段ModelSerializer必须为phone_number。因此,OTP

我能够发布unique并创建对象。但是,再次发布相同的unique=True会引发错误phone_number,而不是更新错误(如果已经存在),因为我已经覆盖了phone_number方法。请帮忙!

3 个答案:

答案 0 :(得分:0)

您可以不要求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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

您可以使用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