如何在 ModelSerializer 的 create 方法中实现 update_or_create
Posted
技术标签:
【中文标题】如何在 ModelSerializer 的 create 方法中实现 update_or_create【英文标题】:How to implement update_or_create inside create method of ModelSerializer 【发布时间】:2019-06-07 08:06:09 【问题描述】:代码:
类 OTP(AppModel): phone_regex = RegexValidator(regex=r'^[6789]\d9$', 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-framework
的ModelSerializer
的create
方法中执行update_or_create
。
但是,模型OTP
中的字段phone_number
必须是unique
。因此unique=True
。
我能够发布phone_number
并创建对象。但是,再次发布相同的phone_number
会引发错误otp with this phone number already exists
,而不是在它已经存在时更新它,因为我已经覆盖了create
方法。请帮忙!
【问题讨论】:
【参考方案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]\d9$', 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
方法之前进行验证。以上是关于如何在 ModelSerializer 的 create 方法中实现 update_or_create的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ModelSerializer 的 create 方法中实现 update_or_create
如何保存具有关系的modelSerializer? - django
如何使用 ModelSerializer 显示所有模型字段?
Django Rest 框架,如何在 ModelSerializer 中包含“__all__”字段和相关字段?