【问题标题】:How can I validate uniqueness of an instance in a collection in django rest framework如何在 django rest 框架的集合中验证实例的唯一性
【发布时间】:2020-04-28 19:51:02
【问题描述】:

我有以下型号。

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 可能会出现在多个 Server Groups 中,而不是在同一个 Server Groups 中出现多次。

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

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】:

    您始终可以在覆盖模型中的 clean() 方法或在 serializers.py 中进行验证时检查您的验证。 此外,验证只涉及您的 not ForeignKey 字段,因为您不能将 ServerGroupMember member_one 添加到 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}")
    

    【讨论】:

      【解决方案2】:

      我想出了一种方法来做到这一点,但仍然很好奇这是否是最好的方法。这似乎适用于创建新的 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-29
        • 2012-07-31
        • 2013-12-22
        • 1970-01-01
        • 2021-10-27
        • 2019-10-31
        相关资源
        最近更新 更多