【问题标题】:Correct way to use Django's ORM and Django Rest Framework to serialize a queryset of nested relationships?使用 Django 的 ORM 和 Django Rest Framework 序列化嵌套关系的查询集的正确方法?
【发布时间】:2016-09-28 16:30:09
【问题描述】:

构建一个查询集的正确方法是什么,我可以将它传递给 Django Rest Framework 序列化器,以便获取相关嵌套对象的数据/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 框架有一个很好的 example in their documentation 使用 ModelSerializer,但我需要这个功能而不使用 ModelSerializer,因为我的序列化需求将变得非常定制,超出了 DB 模型表示。


附加信息:

Dealing with nested objects”的 Django Rest Framework 文档很有帮助,但我仍然不确定如何将正确的查询集传递给这样的“嵌套对象序列化器”。

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

【问题讨论】:

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


    【解决方案1】:

    首先你需要使用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)
    

    【讨论】:

    • 感谢您的回复萨多贝克。正如我的问题的最后几行所提到的,如果可能的话,我想在使用 ModelSerializer 创建自定义查询集之外实现此功能。
    • @aero 我看不出使用ModelSerializer 并扩展它的问题,ModelSerializerSerializer 的子类。这意味着你可以用Serializer 做的所有事情都可以用ModelSerializer 做,甚至更好的是它可以为你访问数据库。
    • 您的更新完全回答了我的问题。感谢您的努力 Sardorbek!
    【解决方案2】:

    为了完整起见,以及其他找到此页面的人,以下是实现相似结果的两种不同方法。

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

    【讨论】:

      猜你喜欢
      • 2018-12-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 2017-03-12
      • 2017-05-24
      • 1970-01-01
      • 2014-10-08
      相关资源
      最近更新 更多