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

如何在django rest框架中验证集合中实例的唯一性,django,django-rest-framework,django-views,django-serializer,django-validation,Django,Django Rest Framework,Django Views,Django Serializer,Django Validation,我有以下几种型号 class ServerGroup(models.Model): name = models.SlugField(unique=True) factor = models.IntegerField() class ServerGroupMember(models.Model): class Meta: unique_together = ( ("server_group", "position"),

我有以下几种型号

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)
服务器组有两个属性,
name
factor
,以及一组
ServerGroupMember
对象。每个
ServerGroupMember
对象都包含一个整数
position
和对
Server
对象的引用。对于给定的
服务器组
而言,
位置
必须是唯一的,对于给定的
服务器组
而言,
服务器
必须是唯一的。但是,在全局范围内,位置和服务器对象不必是唯一的,因为在2个服务器组中,位置1可能包含一个服务器,同一个服务器可能出现在多个服务器组中,但在同一个服务器组中不会出现多次

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

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): ...

您可以在覆盖模型中的
clean()
方法时检查验证,也可以在
serializers.py
中进行验证。 此外,验证只涉及
而不是ForeignKey
字段,因为您不能将
ServerGroupMember
member两次添加到
ServerGroup
server\u测试中

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}")

我想出了一种方法,但仍然好奇这是否是最好的方法。这对于创建新的
ServerGroupMember
实例似乎很有效。虽然不确定它是否也适用于更新案例,但仍有待尝试

在视图中,在实例化序列化程序时,我传递给序列化程序的构造函数,一个包含
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