Django 如何使用输入值在序列化程序中获取外键引用
要创建产品对象,我们只需发送通道obj的id,序列化程序就可以获得引用的对象。 我有一个公开端点的服务,客户端只需发布创建对象的请求。客户端不知道通道ID,它只知道通道的名称 在这种情况下,是否可能有一个序列化程序,其中客户端仍然可以在请求中发送通道名称,但在创建产品obj时在数据库中获得正确的外键引用?有人能给我举一些例子或文档来处理这个问题吗 编辑 如果我在post请求中提供id,视图和序列化程序如下所示Django 如何使用输入值在序列化程序中获取外键引用,django,django-models,django-rest-framework,Django,Django Models,Django Rest Framework,要创建产品对象,我们只需发送通道obj的id,序列化程序就可以获得引用的对象。 我有一个公开端点的服务,客户端只需发布创建对象的请求。客户端不知道通道ID,它只知道通道的名称 在这种情况下,是否可能有一个序列化程序,其中客户端仍然可以在请求中发送通道名称,但在创建产品obj时在数据库中获得正确的外键引用?有人能给我举一些例子或文档来处理这个问题吗 编辑 如果我在post请求中提供id,视图和序列化程序如下所示 class Channel(models.Model): name = mod
class Channel(models.Model):
name = models.CharField(max_length=20)
class Product(models.Model):
channel = models.Foreignkey(Channel, on_delete=models.PROTECT)
id | name
-------------
1 | Channel1
2 | Channel2
3 | Channel3
4 | Channel4
请求机构将是
class ProductsViewSet(viewsets.ModelViewSet):
queryset = models.Product.objects.all()
serializer_class = serializers.ProductSerializer
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = models.Product
fields = "__all__"
但我希望发送如下请求,但仍然能够使用上面的序列化程序,希望有一些小改动
{
"channel": 1
}
进一步编辑
下面是Sasja给我的答案。我必须提供一个额外的参数queryset,完整的序列化程序如下所示
{
"channel": "Channel1"
}
如果要创建引用模型的对象(如果该模型不存在),则必须扩展SlugRelatedField,因为默认情况下它无法创建对象。我发现下面有一个例子
如果我理解正确,您应该在序列化程序上实现.create方法。然后,您可以访问已验证的_数据以获取通道,并创建带有引用的产品
class ProductSerializer(serializers.ModelSerializer):
channel = serializers.SlugRelatedField(
many=False,
read_only=False,
slug_field='name',
queryset=models.Channel.objects.all()
)
class Meta:
model = models.Product
fields = "__all__"
如果要对名称进行搜索,应确保通道模型上的名称字段具有unique=True
供参考:
编辑:
编辑问题后,似乎有一些内置解决方案是默认读/写的SlugRelatedField。另请注意,根据:
当使用SlugRelatedField作为读写字段时,通常需要确保slug字段对应于unique=True的模型字段
您能展示您的序列化程序和视图吗?谢谢您的时间。是的,这就是我想要继续的方式,但我认为由于你已经提到的原因,这有点脆弱。仅当名称与大小写完全匹配时,它才起作用。我有多个序列化程序需要这样做,所以我想避免重复,并想知道是否有任何内置的这种情况。
class CreateProductSerializer(serializers.Serializer):
name = serializers.CharField(max_length=20)
def create(self, validated_data):
name = validated_data.get('name', False)
# naive implementation, should still handle errors (eg. not found)
# you need to be sure that only 1 object with that name will exist (see comment below)
channel = Channel.objects.get(name=name)
return Product(channel=channel)
class ProductSerializer(serializers.ModelSerializer):
channel = serializers.SlugRelatedField(
many=False,
read_only=False,
slug_field='name'
)
class Meta:
model = models.Product
fields = "__all__"