使用 Django 的 ORM 和 Django Rest Framework 序列化嵌套关系查询集的正确方法?
Correct way to use Django's ORM and Django Rest Framework to serialize a queryset of nested relationships?
构建查询集的正确方法是什么,我可以将其传递到 Django Rest Framework Serializer 以获得相关嵌套对象的 data/json 结果。
比如我有两个模型:
class Topping(models.Model):
name = models.CharField(max_length=50)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
我的序列化程序:
class ToppingSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=50)
class PizzaSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=50)
toppings = ToppingSerializer(many=True, required=False)
然后我如何创建并传入查询集以获得类似这样的结果:
[
{
"name": "Hawaiian",
"toppings": [
{"name": "Pinapple"},
{"name": "Canadian Bacon"},
{"name": "Cheese"}
]
},
{
"name": "Pepperoni Pizza",
"toppings": [
{"name": "Pepperoni"},
{"name": "Cheese"}
]
},
{
"name": "Jamaican",
"toppings": [
{"name": "Chicken"},
{"name": "Jerk"},
{"name": "Cheese"}
]
}
]
请注意:
Django Rest Framework 有一个很好的 example in their documentation 使用 ModelSerializer,但我需要此功能而不使用 ModelSerializer,因为我的序列化需求将变得非常定制化,超出了 DB 模型表示。
附加信息:
“Dealing with nested objects”的 Django Rest Framework 文档很有帮助,但我仍然不确定如何将正确的查询集传递给这样的“嵌套对象序列化程序”。
如何创建“嵌套”查询集?
首先你需要使用ModelSerializer
instead of Serializer
, and provide fields
元属性。如果您使用默认字段配置,则无需显式提供序列化程序字段。
class ToppingSerializer(serializers. ModelSerializer):
class Meta:
model = Topping
fields = ('name',)
class PizzaSerializer(serializers. ModelSerializer):
class Meta:
model = Pizza
fields = ('name', 'toppings')
之后只需使用 ListAPIView
并为其提供序列化程序。
class PizzaListApiView(ListAPIView):
queryset = Pizza.objects.all()
serializer_class = PizzaSerializer
更新
How can I create a "nested" queryset?
嵌套表示模型中有 ForeignKey
或 ManyToManyField
,例如您的 Pizza
模型。你可以做 prefetch_related
on your queryset, for example if you want to do it explicitly(http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects)
queryset = Pizza.objects.all().prefetch_related('toppings')
serializer = PizzaSerializer(queryset, many=True)
为了完整性和其他人找到此页面,下面是实现类似结果的两种不同方法。
感谢 Sardorbek 最初回答了这个问题。
观点:
class PizzaList(APIView):
"""
View for the Serializer not using ModelSerializer
"""
def get(self, request, format=None):
pizzas = Pizza.objects.all().prefetch_related('toppings')
serializer = PizzaSerializer(pizzas, many=True)
return Response(serializer.data)
class PiePizzaList(APIView):
"""
View for the Serializer useing ModelSerializer
"""
def get(self, request, format=None):
pizzas = Pizza.objects.all()
serializer = PiePizzaSerializer(pizzas, many=True)
return Response(serializer.data)
序列化器 1(没有 ModelSerializer):
class ToppingSerializer(serializers.Serializer):
name = serializers.CharField(required=True, allow_blank=False, max_length=50)
class PizzaSerializer(serializers.Serializer):
name = serializers.CharField(required=True, allow_blank=False, max_length=50)
toppings = ToppingSerializer(many=True, required=False)
或序列化器 2(带有 ModelSerializer):
class PieToppingSerializer(serializers.ModelSerializer):
class Meta:
model = Topping
fields = ('name',)
class PiePizzaSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True)
toppings = PieToppingSerializer(many=True, required=False)
class Meta:
model = Pizza
构建查询集的正确方法是什么,我可以将其传递到 Django Rest Framework Serializer 以获得相关嵌套对象的 data/json 结果。
比如我有两个模型:
class Topping(models.Model):
name = models.CharField(max_length=50)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
我的序列化程序:
class ToppingSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=50)
class PizzaSerializer(serializers.Serializer):
name = serializers.CharField(required=True, max_length=50)
toppings = ToppingSerializer(many=True, required=False)
然后我如何创建并传入查询集以获得类似这样的结果:
[
{
"name": "Hawaiian",
"toppings": [
{"name": "Pinapple"},
{"name": "Canadian Bacon"},
{"name": "Cheese"}
]
},
{
"name": "Pepperoni Pizza",
"toppings": [
{"name": "Pepperoni"},
{"name": "Cheese"}
]
},
{
"name": "Jamaican",
"toppings": [
{"name": "Chicken"},
{"name": "Jerk"},
{"name": "Cheese"}
]
}
]
请注意:
Django Rest Framework 有一个很好的 example in their documentation 使用 ModelSerializer,但我需要此功能而不使用 ModelSerializer,因为我的序列化需求将变得非常定制化,超出了 DB 模型表示。
附加信息:
“Dealing with nested objects”的 Django Rest Framework 文档很有帮助,但我仍然不确定如何将正确的查询集传递给这样的“嵌套对象序列化程序”。
如何创建“嵌套”查询集?
首先你需要使用ModelSerializer
instead of Serializer
, and provide fields
元属性。如果您使用默认字段配置,则无需显式提供序列化程序字段。
class ToppingSerializer(serializers. ModelSerializer):
class Meta:
model = Topping
fields = ('name',)
class PizzaSerializer(serializers. ModelSerializer):
class Meta:
model = Pizza
fields = ('name', 'toppings')
之后只需使用 ListAPIView
并为其提供序列化程序。
class PizzaListApiView(ListAPIView):
queryset = Pizza.objects.all()
serializer_class = PizzaSerializer
更新
How can I create a "nested" queryset?
嵌套表示模型中有 ForeignKey
或 ManyToManyField
,例如您的 Pizza
模型。你可以做 prefetch_related
on your queryset, for example if you want to do it explicitly(http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects)
queryset = Pizza.objects.all().prefetch_related('toppings')
serializer = PizzaSerializer(queryset, many=True)
为了完整性和其他人找到此页面,下面是实现类似结果的两种不同方法。
感谢 Sardorbek 最初回答了这个问题。
观点:
class PizzaList(APIView):
"""
View for the Serializer not using ModelSerializer
"""
def get(self, request, format=None):
pizzas = Pizza.objects.all().prefetch_related('toppings')
serializer = PizzaSerializer(pizzas, many=True)
return Response(serializer.data)
class PiePizzaList(APIView):
"""
View for the Serializer useing ModelSerializer
"""
def get(self, request, format=None):
pizzas = Pizza.objects.all()
serializer = PiePizzaSerializer(pizzas, many=True)
return Response(serializer.data)
序列化器 1(没有 ModelSerializer):
class ToppingSerializer(serializers.Serializer):
name = serializers.CharField(required=True, allow_blank=False, max_length=50)
class PizzaSerializer(serializers.Serializer):
name = serializers.CharField(required=True, allow_blank=False, max_length=50)
toppings = ToppingSerializer(many=True, required=False)
或序列化器 2(带有 ModelSerializer):
class PieToppingSerializer(serializers.ModelSerializer):
class Meta:
model = Topping
fields = ('name',)
class PiePizzaSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True)
toppings = PieToppingSerializer(many=True, required=False)
class Meta:
model = Pizza