首页 > 解决方案 > 如何使用 django rest 框架正确保存和验证对象

问题描述

我正在学习django rest framework,我发现正确验证和保存对象的问题。

当我收到创建对话的请求时,我首先需要创建一个对话,然后向其中添加参与者。

这是Dialog模型的代码:

class DialogManager(models.Manager):
    def create_dialog(self, name):
        max_length(name, 30)
        dialog = self.model(name=name)
        dialog.save()
        return dialog


class Dialog(models.Model):
    name                = models.CharField(null=False)
    created_at          = models.DateTimeField(auto_now_add=True)

    objects = DialogManager()

我的Participant模型:

class ParticipantManager(models.Manager):
    def create_participant(self, dialog, user, role="user"):
        if role not in ["user", "admin"]:
            raise ValueError('Incorrect role for the user')

        max_length(role, 30)

        participant = Participant(role=role, dialog=dialog, user=user)
        participant.save()
        return participant


class Participant(models.Model):
    role                = models.CharField(null=False)
    dialog              = models.ForeignKey(Dialog, on_delete=models.CASCADE)
    user                = models.ForeignKey(CustomUser, on_delete=models.CASCADE)

    objects = ParticipantManager()

    class Meta:
        unique_together = ('dialog', 'user',)

Dialog设置:

class DialogSet(viewsets.ModelViewSet):

    queryset = Dialog.objects.all()

    serializer_class = DialogSerializer
    pagination_class = DialogSetPagination

    def create(self, request):
        data = request.data
        users = CustomUser.objects.filter(pk__in=data['ids'])
        dialog_serializer = DialogSerializer(data=data)
        if not dialog_serializer.is_valid():
            return Response(dialog_serializer.errors, status.HTTP_400_BAD_REQUEST)
        with transaction.atomic():
            dialog = dialog_serializer.save()
            i = 0
            for user in users:
                participant_serializer = ParticipantSerializer(data={'dialog': dialog.pk, 'user': user.pk, 'role': 'user'})
                if not participant_serializer.is_valid():
                    return Response(participant_serializer.errors, status.HTTP_400_BAD_REQUEST)
                i += 1

        return Response(dialog, status.HTTP_201_CREATED)       

问题是我可以保存一个对象Dialog,然后验证participants对象,它们将是无效的。我需要回滚。我可以在不使用事务的情况下更改创建dialog和对象的过程吗?participants这让我想到了许多其他问题。

  1. 有人告诉我,模型和序列化程序中的双重验证不是一个好主意。据我了解,最好将所有验证存储在模型中,但在序列化程序中仅添加与数据库无关的验证?

  2. 因此,我将自定义create方法添加到模型DialogParticipant. 但在这种情况下,事实证明创建方法也处理验证,我知道django模型中没有在创建对象之前调用的验证方法。那么,在哪里确定验证?

  3. 还有另一个问题,create据我了解,方法涉及保存对象。我需要将保存的dialog对象放入对象中,但如果对象无效participants,我将需要回滚更改。participants创建方法要保存对象吗?

  4. 当我没有将序列化程序的role密钥Participant放在我的DialogSet然后调用中.is_valid()时,它会调用validate序列化程序,它会检查是否指定了角色。因此,我再次在validate方法和create_participant. 但是我想role通过在我的序列化程序中调用模型验证方法来检查是否指定,然后调用create_participant以保存对象。我可以做吗?

总而言之,我想得到这样的东西:

class ParticipantSerializer(serializers.ModelSerializer):

    class Meta:
        model = Participant
        fields = '__all__'

    def validate(self, data):
        data = ParticipantManager.validate(**data)
        return data


    def create(self, validated_data):
        role = validated_data['role']
        user = validated_data['user']
        dialog = validated_data['role']
        participant = Participant.objects.create_participant(dialog, user, role)
        return participant

class ParticipantManager(models.Manager):

    def create_participant(self, dialog, user, role):
        participant = Participant(dialog=dialog, user=user, role=role)
        participant.save()
        return participant

    def validate(self, data):
        ## validate data
        return data

如果此代码不正确,请告诉我如何正确执行。

标签: djangodjango-rest-framework

解决方案


抱歉,我已经阅读了 Django 中的 clean() ,它解决了我的问题。问题已结束。


推荐阅读