正确使用Django的ORM和Django Rest Framework来序列化嵌套关系的查询集吗?

时间:2016-05-30 19:29:18

标签: python json django django-rest-framework django-orm

构建查询集的正确方法是什么,我可以将其传递给Django Rest Framework Serializer,以获取相关嵌套对象的数据/ 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文档很有帮助,但我仍然不确定如何将正确的查询集传递给这样的“嵌套对象序列化程序”。

如何创建“嵌套”查询集?

2 个答案:

答案 0 :(得分:3)

首先,您需要使用ModelSerializer代替Serializer,并提供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

<强>更新

  

如何创建“嵌套”查询集?

嵌套意味着在模型中使用ForeignKeyManyToManyField,就像您的Pizza模型一样。您可以在查询集上执行prefetch_related,例如,如果您想明确地执行此操作(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)

答案 1 :(得分:0)

为了完整性和其他人找到这个页面,下面是两种不同的方法来实现类似的结果。

感谢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)

Serializer 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)

OR Serializer 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