Django: Nesting serializers in each other

2019-07-18 09:37发布

问题:

I'm figuring out how serializers can be merged or nested into each other. In this example I have a column model (consisting of Column class) and data that belong to the column model (consisting of Data class). My problems is that I don't know how to call ModelSerializer from another serializer class and pass the arguments (the result is always empty).

Can you advice me if my model is correct for this situation and how to create the desired JSON so that the result reuses existing serializers and avoids duplicating any data?

Note: in best case the data attributes should be dependent on each other, so that only those data get serialized that are defined as columns.

models.py

class Column(models.Model):
    data = models.CharField(max_length=200)
    title = models.CharField(max_length=200)

    def __str__(self):
        return self.order

class Data(models.Model):
    doc = models.CharField(max_length=200)
    order = models.CharField(max_length=200)
    nothing = models.CharField(max_length=200)

    def __str__(self):
        return self.order

Desired output:

{
    "columns": [
        {
            "data": "doc",
            "title": "Doc."
        },
        {
            "data": "order",
            "title": "Order no."
        },
        {
            "data": "nothing",
            "title": "Nothing"
        }
    ],
    "data": [
        {
            "doc": "564251422",
            "nothing": 0.0,
            "order": "56421"
        },
        {
            "doc": "546546545",
            "nothing": 0.0,
            "order": "98745"
        }
    ]
}

But the result with ModelSerializer is like this:

[
    {
        "doc": "564251422",
        "order": "56421",
        "nothing": "0.0"
    },
    {
        "doc": "546546545",
        "order": "98745",
        "nothing": "0.0"
    }
]

回答1:

You have to add a model that contains columns and data attributes because they are currently not linked.

your models.py file :

class Table(models.Model):
    pass

class Column(models.Model):
    data = models.CharField(max_length=200)
    title = models.CharField(max_length=200)
    table = models.ForeignKey(Table)

    def __str__(self):
        return self.order

class Line(models.Model):
    doc = models.CharField(max_length=200)
    order = models.CharField(max_length=200)
    nothing = models.CharField(max_length=200)
    table = models.ForeignKey(Table)

    def __str__(self):
        return self.order

your serializer.py file :

# import your related models and serializers

class ColumnSerializer(serializers.ModelSerializer):

    class Meta:
        model = Column
        fields = [
            'data',
            'title'
        ]

class LineSerializer(serializers.ModelSerializer):

    class Meta:
        model = Line
        fields = [
            'doc',
            'order',
            'nothing'
        ]

class TableSerializer(serializers.ModelSerializer):
    columns = ColumnSerializer(many=True)
    lines = LineSerializer(many=True)

    class Meta:
        model = Table
        fields = [
            'columns',
            'lines'
        ]

Now use the TableSerializer serializer to serialize and deserialize your Table object.

Concerning your models, Line instead of Data is maybe more appropriate. And

Read Django-Rest-Framework - NestedRelationships for more information and learn how to support write-operations to a nested serializer field.



回答2:

First you need to modify you models. You can make data ForeignKey field in Column model like:

class Column(models.Model):
    data = models.ForeignKey("Data")
    title = models.CharField(max_length=200)

Next create a new serializer for Data like:

class DataSerializer(serializers.ModelSerializer):

    class Meta:
        model = Data

Now you can use DataSerializer in your ColumnSerializer to get data for each column like:

class ColumnSerializer(serializers.ModelSerializer):
    data = DataSerializer(read_only=True)

    class Meta:
        model = Column

This would give output like:

[
    {
        "title" : "Doc",
        "data" :{
            "doc": "564251422",
            "nothing": 0.0,
            "order": "56421"
        }
     },
     {
        "title" : "Order no.",
        "data" :{
            "doc": "546546545",
            "nothing": 0.0,
            "order": "98745"
        }
    }
]