我有以下模型。
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号位置的服务器,同一个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): ...
你可以在覆盖了 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}")
我想出了一种方法,但还是很好奇这是否是最好的方法。 这似乎对创建新的 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