Как я могу проверить уникальность экземпляра в коллекции в django rest framework - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть следующие модели.

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 есть пара свойств, name и factor, и коллекция ServerGroupMember объектов. Каждый объект ServerGroupMember содержит целое число position и ссылку на объект Server. Для данного ServerGroup position должно быть уникальным, а для данного ServerGroup server должно быть уникальным. Однако в глобальном плане объекты и серверные объекты не обязательно должны быть уникальными, так как в 2 ServerGroups может содержаться сервер в позиции 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): ...

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Вы также можете проверить свои проверки при переопределении метода 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}")
0 голосов
/ 28 апреля 2020

Я нашел один способ сделать это, но все же любопытно, является ли это лучшим подходом здесь. Похоже, это отлично работает для создания новых 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
...