如何在django rest框架中验证一个集合中实例的唯一性?

问题描述 投票:0回答:1

我有以下模型。

class ServerGroup(models.Model):
    name = models.SlugField(unique=True)
    factor = models.IntegerField()

class ServerGroupMember(models.Model):
    class Meta:
        unique_together = (
            ("server_group", "position"),
            ("server_group", "server"),
        )

    position = models.IntegerField()
    server_group = models.ForeignKey(
        "ServerGroup", related_name="servers", on_delete=models.CASCADE
    )
    server = models.ForeignKey("Server", on_delete=models.CASCADE)

一个ServerGroup有几个属性。namefactor以及一系列 ServerGroupMember 对象。 每个 ServerGroupMember 对象,包含一个整数 position 并提及 Server 对象。对于一个给定的 ServerGroupposition 必须是唯一的,而且对于一个给定的 ServerGroupserver 必须是唯一的。 但是,从全局来看,位置和服务器对象不一定是唯一的,比如2个ServerGroups中可能会包含1号位置的服务器,同一个Server可以出现在多个ServerGroup中,只是不能在同一个ServerGroup中多次出现。

鉴于我有以下序列器,如何验证上述情况? 目前,该模型确实在数据库级别验证了该条件,但如果我试图违反该条件,就会引发一个唯一约束错误。 我想要的是能够在我的视图中检测到这一点,这样我就可以在它有机会击中DB并引发该异常之前返回一个适当的验证错误消息响应。

class ServerGroupMemberSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.ServerGroupMember
        fields = ("position", "server")
    server = serializers.SlugRelatedField(
        slug_name="name", queryset=models.Server.objects.all()
    )

class SrvereGroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.ServerrGroup
        fields = ("name", "factor", "servers")
    servers = ServerGroupMemberSerializer(many=True, required=False)

    def create(self, validated_data): ...
    def update(self, validated_data): ...
django django-rest-framework django-views django-serializer django-validation
1个回答
1
投票

你可以在覆盖了 clean() 方法,或者在你的模型中进行验证。serializers.py. 此外,验证只涉及你的 not ForeignKey 字段,因为你不能添加一个 ServerGroupMember 成员_一两次到一个 ServerGroup server_test。

class ServerGroupMember(models.Model):
    class Meta:
        unique_together = (
            ("server_group", "position"),
            ("server_group", "server"),
        )

    position = models.IntegerField()
    server_group = models.ForeignKey(
        "ServerGroup", related_name="servers", on_delete=models.CASCADE
    )
    server = models.ForeignKey("Server", on_delete=models.CASCADE)

   def clean(self):
       super().clean()
       if self.position in ServerGroup.server_group_set.all().values_list('position', flat=True):
           raise ValidationError(f"Position {self.position} already exists for ServerGroup {self.server_group.name}")

0
投票

我想出了一种方法,但还是很好奇这是否是最好的方法。 这似乎对创建新的 ServerGroupMember 实例。 虽然不知道对于Update的情况是否同样有效,但这还有待尝试。

在视图中,当实例化序列化器时,我向序列化器的构造函数传递了一个上下文对象,其中包含了 ServerGroup 名。例如

def post(self, request: Request, name: str, format=None) -> Response:
    server_group = self.get_object()  # defined elsewhere
    serializer = serializers.ServerGroupMemberSerializer(
        data=request.data, context={"server_group": server_group.name}
    )
    ...

那么在 ServerGroupMemberSerializer 我增加了字段级的验证器,如

def validate_position(self, value):
    server_group = self.context.get("server_group")
    try:
        models.ServerGroupMember.objects.get(
            server_group__name=server_group, position=position
        )
    except models.ServerGroupMember.DoesNotExist:
        return value
    raise serializers.ValidationError(
        f"A server group member with position {position} already exists"
    )

def validate_server(self, value):
    ... # Follow same pattern as above
© www.soinside.com 2019 - 2024. All rights reserved.