ManyToMany关系自定义序列化程序



假设我有两个模型:

class IPAddress(models.Model):
    address = models.CharField()
class Rule(models.Model):
    name = models.CharField()
    ips = models.ManyToMany(IPAddress)

我想通过以下请求添加一个规则:

{
"name":"Foo",
"ips":["192.168.1.40", "4.4.4.4", "8.8.8.8"]
}

此外,我想在每个请求中为新规则构造ip(没有url可以直接构造ip),所以我为管理员写了一个类,如下所示:

class RuleManager(models.Manager):
    def create(self, validated_data):
        rule = Rule(name=validate_data['name'])
        rule.save()
        rule.ips = [IPAddress.objects.get_or_create(item.lower()) for item in validated_data['ips']]

但在序列化程序中,我找不到合适的方式来显示这一点。我已经写了一个这样的序列化程序:

class RuleSerializer(serializers.Serializer):
    name = serializers.CharField()
    ips = serializers.SlugRelatedField(many=True, slug_field='address', validators=[], queryset=models.IPAddress.objects.all())

但问题是,它会验证请求中的ip,如果没有这样的ip,它会返回一个错误,尽管我为验证器设置了一个空列表。

我有两个问题,如何禁用此验证?我编写序列化程序和模型的方式是否适合我的场景(我无法更改我得到的请求和必须发送的响应)

如果您需要以以下格式返回Rule的实例:

{
"name":"Foo",
"ips":["192.168.1.40", "4.4.4.4", "8.8.8.8"]
}

您可以创建一个RuleSerializer并使用SlugRelatedField

SlugRelatedField只适用于已经存在的对象。由于您也将创建对象,因此可以修改to_internal_value实现来创建不存在的对象(从这里引用):

class CreatableSlugRelatedField(serializers.SlugRelatedField):
    def to_internal_value(self, data):
        try:
            return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
        except ObjectDoesNotExist:
            self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
        except (TypeError, ValueError):
            self.fail('invalid')
class RuleSerializer(serializers.ModelSerializer):
    ips = serializers.CreatableSlugRelatedField(
        many=True,
        slug_field='address' # this is the ip address
        queryset=IPAddress.objects.all()
    )
    class Meta:
         model = Rule
         fields: ('name', 'ips')

更新:基于问题中的评论:

我无法更改我得到的请求和响应,我必须发送

但是,如果您可以使用嵌套的序列化程序,尽管您的表示需要稍微更改:

{
    "name": "Foo",
    "ips": [
         {"address": "192.168.1.40"}, 
         {"address": "4.4.4.4"}, 
         {"address": "8.8.8.8"}
    ]
}

然后是嵌套的序列化程序(此处有更多文档):

class IPAddressSerializer(serializers.ModelSerializer):
     class Meta:
         model = IPAddress
         fields: ('address',)
class RuleSerializer(serializers.ModelSerializer):
    ips = IPAddressSerializer(many=True)
    class Meta:
         model = Rule
         fields: ('name', 'ips')

相关内容

最新更新