具有 OneToOne 关系的文件的 Django 序列化程序

Django serializer with a filed that has a OneToOne relationship

在我的项目中,我有两个 'types' 用户:客户和企业。它们是来自 django.contrib.auth.models.User.

的 django 基本用户的扩展

我的 models.py:

class Customer(models.Model):
    user = models.OneToOneField(User, related_name='user', on_delete=models.CASCADE)

    birth_date = models.DateField(blank=True, null=True)
    phone = PhoneNumberField(unique=True)

    def __str__(self):
        return self.user.username

class Business(models.Model):
    user = models.OneToOneField(User, related_name='business', on_delete=models.CASCADE)

    cf = models.CharField(max_length=16, validators=[ssn_validation])
    birth_date = models.DateField(null=True)
    city = models.CharField(max_length=50, blank=False)
    address = models.CharField(max_length=150, blank=False)

好的,那我有两种不同的注册方式,一种用于客户,一种用于企业。 一个问题是,要验证从 REST API 发送的密码,我需要将 passwordpassword2 进行比较,创建一个用户(django 基础),并将其传递给我的 Customer.objects.create, 喜欢:

我的 serializers.py:

class CustomerRegistationSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username',
                                     validators=[UniqueValidator(queryset=User.objects.all())])
    email = serializers.CharField(source='user.email',
                                  validators=[UniqueValidator(queryset=User.objects.all())])
    first_name = serializers.CharField(source='user.first_name')
    last_name = serializers.CharField(source='user.last_name')
    password = serializers.CharField(source='user.password', write_only=True)
    password2 = serializers.CharField(style={'input_style': 'password'}, write_only=True)

    birth_date = serializers.CharField(required=False)

    class Meta:
        model = Customer
        fields = ['id', 'username', 'email', 'password', 'password2', 'first_name', 'last_name',
                  'birth_date', 'phone']

    def save(self):
        username = self.validated_data['user']['username']
        password = self.validated_data['user']['password']
        password2 = self.validated_data['password2']
        email = self.validated_data['user']['email']
        first_name = self.validated_data['user']['first_name']
        last_name = self.validated_data['user']['last_name']
        phone = self.validated_data['phone']

        try:
            birth_date = self.validated_data['birth_date']
        except KeyError:
            birth_date = None

         if password != password2:
            raise serializers.ValidationError({'password': 'Passwords must match!'})

        user = User.objects.create(username=username, email=email, first_name=first_name, last_name=last_name)
        user.set_password(password)
        user.is_active = False
        user.save()

        customer = Customer.objects.create(user=user,
                                           birth_date=birth_date,
                                           phone=phone)
        return customer

这确实有效,但如果出现错误,可能会创建用户,但不会创建客户。 是否有更简洁的方式来进行客户注册,始终检查 password == password2?

编辑: 我找到了一种更优雅的处理方式:

@transaction.atomic 定义保存(自我): 密码 = self.validated_data['user']['password'] 密码 2 = self.validated_data['password2']

user = User.objects.create(**self.validated_data['user'])

if password != password2:
    raise serializers.ValidationError({'password': 'Passwords must match!'})
user.set_password(password)
user.is_active = False
user.save()
update_last_login(None, user)

del self.validated_data['user']
del self.validated_data['password2']

customer = Customer.objects.create(user=user, **self.validated_data)
return customer

如果你想要求你在 save() 方法中进行的所有数据库事务都成功以有效地将其写入数据库,并且如果在任何时候出现错误则不写入任何内容进程,您通常要求 atomicity(数据库的四种 ACID 功能之一)

使用这个 Django 装饰器,通常是为此而设计的:

from django.db import transaction

    @transaction.atomic    
    def save(self):
        <...>