python - Django ORM 和 Django REST 框架 : How to make "grouped" arrays?

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

目前,我的 Django 服务器可以返回以下 JSON:

[
  {
    "id": 1,
    "customer": {
      "id": 1,
      "name": "John Doe"
    },
    "description1": "...",
    "description2": "...",
    "description3": "...",
    "description4": "..."
  },
  {
    "id": 2,
    "customer": {
      "id": 1,
      "name": "John Doe"
    },
    "description1": "...",
    "description2": "...",
    "description3": "...",
    "description4": "..."
  },
  {
    "id": 3,
    "customer": {
      "id": 1,
      "name": "John Doe"
    },
    "description1": "...",
    "description2": "...",
    "description3": "...",
    "description4": "..."
  },
  {
    "id": 4,
    "customer": {
      "id": 2,
      "name": "Jane Doe"
    },
    "description1": "...",
    "description2": "...",
    "description3": "...",
    "description4": "..."
  },
  {
    "id": 5,
    "customer": {
      "id": 2,
      "name": "Jane Doe"
    },
    "description1": "...",
    "description2": "...",
    "description3": "...",
    "description4": "..."
  }
]

我的模型是:

from django.db import models

class Customer(models.Model):
    name = models.CharField(verbose_name="Customer name")

from django.db import models


class PurchaseDescriptions(models.Model):
    customer =  models.ManyToManyField("customer.Customer", related_name="customer", verbose_name="Customer")
    description1 = models.CharField(verbose_name="Description 1")
    description2 = models.CharField(verbose_name="Description 2")
    description3 = models.CharField(verbose_name="Description 3")
    description4 = models.CharField(verbose_name="Description 4")

我的序列化器是:

from rest_framework import serializers

class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = [
            "id",
            "name",
        ]

class PurchaseDescriptionsSerializer(serializers.ModelSerializer):
    customer = CustomerSerializer()
    
    class Meta:
        model = PurchaseDescriptions
        fields = [
            "id",
            "customer",
            "description1",
            "description2",
            "description3",
            "description4",
        ]

我的观点是:

from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins

class ScheduleViewSet(
    mixins.ListModelMixin,
    GenericViewSet,
):
    queryset = PurchaseDescriptions.objects.all()
    serializer_class = PurchaseDescriptionsSerializer

我想重写它并根据客户创建一些组,例如

[
  {
    "customer": {
      "id": 1,
      "name": "John Doe"
    },
    "data": [
      {
        "id": 1,
        "description1": "...",
        "description2": "...",
        "description3": "...",
        "description4": "..."
      },
      {
        "id": 2,
        "description1": "...",
        "description2": "...",
        "description3": "...",
        "description4": "..."
      },
      {
        "id": 3,
        "description1": "...",
        "description2": "...",
        "description3": "...",
        "description4": "..."
      }
    ]
  },
  {
    "customer": {
      "id": 2,
      "name": "Jane Doe"
    },
    "data": [
      {
        "id": 4,
        "description1": "...",
        "description2": "...",
        "description3": "...",
        "description4": "..."
      },
      {
        "id": 5,
        "description1": "...",
        "description2": "...",
        "description3": "...",
        "description4": "..."
      }
    ]
  }
]

但我不知道如何使用 Django 的 View 和序列化器来实现这一点。我怎样才能得到这样的JSON?请注意,如果可能的话,我希望避免在数据库中创建其他表。

最佳答案

# defined model 

class Customer(models.Model):
    name = models.CharField(verbose_name="Customer name")

class PurchaseDescriptions(models.Model):
    customer =  models.ManyToManyField("Customer", related_name="customer", verbose_name="Customer")
    description1 = models.CharField(verbose_name="Description 1")
    description2 = models.CharField(verbose_name="Description 2")
    description3 = models.CharField(verbose_name="Description 3")
    description4 = models.CharField(verbose_name="Description 4")

    
   

# serializers.py
from rest_framework.serializers import ModelSerializer, Serializer
from rest_framework.fields import CharField, SerializerMethodField
from drf_spectacular.utils import extend_schema_field


class PurchaseDescriptionSchema(ModelSerializer):
    class Meta:
        model = PurchaseDescriptions
        exclude = ("customer",)


class PurchaseDescriptionsSchema(Serializer):
    customer = SerializerMethodField(method_name="nested_customer")
    data = PurchaseDescriptionSchema(many=True)
    
    # i don't like MethodField 
    # but there is no other way because it's too wierd schema structure
    @extend_schema_field(OpenApiTypes.OBJECT)
    def nested_customer(self, obj: Customer2) -> Dict[str,Any]:
        return {
            "id": obj.id,
            "name": obj.name
        }
    


# viewSets.py
class ScheduleViewSet(
    mixins.ListModelMixin,
    GenericViewSet,
):
    queryset = Customer.objects.prefetch_related(
        Prefetch(lookup="purchasedescriptions_set", to_attr="data", queryset=PurchaseDescriptions.objects.all())
    ).all()
    serializer_class = PurchaseDescriptionsSchema

ViewSetList 的响应

enter image description here

즐코하세요

++++

如果您想以不使用 MethodField 的方式实现它,您可以在 QuerySet 中使用 Concat 来获取 JSON 格式的客户数据。

Customer.objects.annotate(customer=Concat(Value("{ \"id\": "), id, Value(",\"name\" "), name, Value("}") )).prefetch_related(~~~)

您可以通过这种方式配置查询集并使用

class PurchaseDescriptionsSchema(Serializer):
    # set customer = SerializerMethodField(method_name="nested_customer")
    customer = JsonField() # DRF SerializerField
    data = PurchaseDescriptionSchema(many=True)

如上所示实现序列化器。

但是,上面案例的查询集太乱了,所以我使用了 SerializerMethodField。

关于python - Django ORM 和 Django REST 框架 : How to make "grouped" arrays?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75910298/

相关文章:

python - 翻译 argparse 的内部字符串

python - 使用 xlsxwriter 将数据框导出到 Excel 文件

python - 获取图像中红色的坐标(0.01*dst.max()) - python

python - json 模块中的 object_hook 似乎没有按预期工作

javascript - Angular Controller 中的事件仅触发一次

Django-Oscar 从管理面板取消注册一个类

python - Django模板中根据用户选择不同的样式表

python - UUID 由于格式化而导致单元 pytest 失败?

django - django 模板列表变量中的最后一个元素

javascript - 向 API 发送请求以接收 JSON 并将其作为原始 JSON 文本附加到文档中