1

I have 3 models show as below.

    class DocumentClass(models.Model):
        text = models.CharField(max_length=100)


    class DocumentGroup(models.Model):
        text = models.CharField(max_length=100)
        documentclass = models.ForeignKey(DocumentClass)


    class DocumentType(models.Model):
        text = models.CharField(max_length=100)
        documentgroup = models.ForeignKey(DocumentGroup)

And my goal is something like this:

[
    {
        'pk': 1,
        'model': 'DocumentClass',
        'fields':{
            'text':'DocumentClass1',
            'documentgroup':
            [
                {
                    'pk': 1,
                    'model': 'DocumentGroup'
                    'field':
                    {
                        'text':'DocumentGroup1'
                    }
                }
            ]
        }
    },
    {
        'pk': 2,
        'model': 'DocumentClass',
        'fields':{
            'text':'DocumentClass2'
        }
    }
]

I usually serialize a model by

jsonstr = serializers.serialize("json", DocumentType.objects.all())

But for my goal. I have no idea. As the title. What is the best way to do that?

Edit: The relation of above models look like:

DocumentClass1
|-DocumentGroup1
| |-DocumentType1
| |-DocumentType2
| |-...
|-DocumentGroup2
| |-...
DocumentClass2
|-DocumentGroup...
| |-DocumentType...

3 Answers3

2

If The Models Are Related

This will require some more customized serialization, for which you will have to use Django Rest Framework's serializers.

Try subclassing ModelSerializer:

class DocumentTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = DocumentType


class DocumentGroupSerializer(serializers.ModelSerializer):
    types = DocumentTypeSerializer(many=True)

    class Meta:
        model = DocumentGroup


class DocumentClassSerializer(serializers.ModelSerializer):
    groups = DocumentGroupSerializer(many=True)

    class Meta:
        model = DocumentClass


queryset = DocumentClass.objects.all()
serializer = DocumentClassSerializer(queryset, many=True)
json = JSONRenderer().render(serializer.data)

If The Models Are Not Related

According to the Django docs, the 2nd argument to serialize() can be "any iterator that yields Django model instances".

Now you'll need to pass your 3 kinds of instances as an iterator. It seems like Python's itertools.chain is the preferred method, as voted here.

So your call would look something like:

instances = list(chain(DocumentClass.objects.all(), DocumentGroup.objects.all(), DocumentType.objects.all())
jsonstr = serializers.serialize("json", instances)
Community
  • 1
  • 1
nofinator
  • 2,906
  • 21
  • 25
0

As I follow by @nofinator's answer in "If The Models Are Related" section everything looks fine until json = JSONRenderer().render(serializer.data)I got above errors. How can I eliminate them?

AttributeError: Got AttributeError when attempting to get a value for field `documenttypes` on serializer `DocumentGroupSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `DocumentGroups` instance.
Original exception text was: 'DocumentGroups' object has no attribute 'documenttypes'.

Here is my serialize.py

from rest_framework import serializers
from .models import *


class DocumentTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = DocumentTypes
        fields = ('id', 'text')


class DocumentGroupSerializer(serializers.ModelSerializer):
    documenttypes = DocumentTypeSerializer(many=True)

    class Meta:
        model = DocumentGroups
        fields = ('id', 'text', 'documenttypes')


class DocumentClassSerializer(serializers.ModelSerializer):
    documentgroups = DocumentGroupSerializer(many=True)

    class Meta:
        model = DocumentClasses
        fields = ('id', 'text', 'documentgroups')

And this is my models.py

from django.db import models


class DocumentClasses(models.Model):
    text = models.CharField(max_length=100)


class DocumentGroups(models.Model):
    text = models.CharField(max_length=100)
    documentclass = models.ForeignKey(DocumentClasses)


class DocumentTypes(models.Model):
    text = models.CharField(max_length=100)
    documentgroup = models.ForeignKey(DocumentGroups)

Update. When I try to add read_only=True my serializer.py look like

from rest_framework import serializers
from .models import *

class DocumentTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = DocumentTypes
        fields = ('id', 'text', 'documentgroup')


class DocumentGroupSerializer(serializers.ModelSerializer):
    documenttypes = DocumentTypeSerializer(many=True, read_only=True)

    class Meta:
        model = DocumentGroups
        fields = ('id', 'text', 'documenttypes')


class DocumentClassSerializer(serializers.ModelSerializer):
    documentgroups = DocumentGroupSerializer(many=True, read_only=True)

    class Meta:
        model = DocumentClasses
        fields = ('id', 'text', 'documentgroups')

Then try:

queryset = DocumentClasses.objects.all()
serializer = DocumentClassSerializer(queryset, many=True)
json = JSONRenderer().render(serializer.data)

I got only '[{"id":1,"text":"class1"}]' But this is my expected:

[  
   {  
      "id":1,
      "text":"class1",
      "documentgroups":[  
         {  
            "id":1,
            "text":"group1",
            "documenttypes":[  
               {  
                  "id":1,
                  "text":"type1"
               }
            ]
         }
      ]
   }
]
0

Hi @nofinator and other django rookie like me! Thanks @nofinator for the great answer! And for django rookies like me. If you want to use django-rest-framework to serialize queryset DO NOT FORGET to use the ** related_name **(without ** ) attribute in the model like this:

class DocumentClasses(models.Model):
    text = models.CharField(max_length=100)


class DocumentGroups(models.Model):
    text = models.CharField(max_length=100)
    documentclass = models.ForeignKey(DocumentClasses, **related_name**='documentgroups')


class DocumentTypes(models.Model):
    text = models.CharField(max_length=100)
    documentgroup = models.ForeignKey(DocumentGroups, **related_name**='documenttypes')

@nofinator and ralated_name made my day! Million thanks!