Currently, my Django server can return the JSON below:
[
{
"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": "..."
}
]
My models are:
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")
my serializers are:
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",
]
and my viewset is:
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
class ScheduleViewSet(
mixins.ListModelMixin,
GenericViewSet,
):
queryset = PurchaseDescriptions.objects.all()
serializer_class = PurchaseDescriptionsSerializer
I want to rewrite it and make some groups based on customer
, e.g.
[
{
"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": "..."
}
]
}
]
But I don't know how to make this using Django's views and serializers. How can I get such JSON? Note that I want to avoid creating additional tables in the database if it is possible.
# 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's response
즐코하세요
++++
If you want to implement it in a way that doesn't use a MethodField, you can use a Concat in a QuerySet to get the customer data in JSON format.
Customer.objects.annotate(customer=Concat(Value("{ \"id\": "), id, Value(",\"name\" "), name, Value("}") )).prefetch_related(~~~)
You can configure your queryset this way and use the
class PurchaseDescriptionsSchema(Serializer):
# set customer = SerializerMethodField(method_name="nested_customer")
customer = JsonField() # DRF SerializerField
data = PurchaseDescriptionSchema(many=True)
implement the Serializer as shown above.
but, above case's queryset is too messy, so I use SerializerMethodField.