django rest框架多个外键序列化

时间:2016-08-30 16:38:38

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

起初看起来很简单,现在我感到困惑。我写了数据结构,现在很难得到它。到目前为止我所拥有的:

class Area(models.Model):
    name = models.CharField(max_length=128)
    ...

class Category(models.Model):
    name = models.CharField(max_length=128)
    ....

class Venue(models.Model):
    name = models.CharField(max_length=128)
    category = models.ForeignKey(Category, related_name='venues')
    area = models.ForeignKey(Area, related_name='venues')

我需要根据Area pk获取其中包含场地的类别。是否可以使用django rest框架这样做?结果应该类似于:

  {
    "pk": 1,
    "name": "London",
    "categories": [
        {
             "pk": 1,
             "name": "Bars",
             "venues": [
                 {
                      "pk": 1,
                      "name": "Cool bar"
                 },
                 {
                      "pk": 2,
                      "name": "Cooler bar"
                 },
                 {
                      "pk": 3,
                      "name": "Coldest bar"
                 },
            ]
        }
    ]

}

理想情况下,我需要这样的事情:

class VenueSerializer(serializers.ModelSerializer):
  .....

class CategorySerializer(serializers.ModelSerializer):
    venues = VenueSerializer(read_only=True, many=True)

    class Meta:
        model = Category
        fields = ('pk', 'name', 'venues', )

class AreaSerializer(serializers.ModelSerializer):
    categories = CategorySerializer(read_only=True, many=True)

    class Meta:
        model = Area
        fields = ('pk', 'name', 'categories', )

但当然这不起作用,因为Area不是直接Category相关。所以我的问题, 是否可以在不改变数据结构的情况下做到这一点?

1 个答案:

答案 0 :(得分:2)

这有点难看,但如果您在对象模型上设置,则可以使用DRF's SerializerMethodField执行此操作。

您的区域序列化程序将类似于:

class AreaSerializer(serializers.ModelSerializer):
    categories = SerializerMethodField()

    def get_categories(self, obj):
        # this will find all categories with a venue in given area
        categories = Category.objects.filter(venues__area=obj)
        serializer = CategorySerializer(categories, many=True)
        return serializer.data

    class Meta:
        model = Area
        fields = ('pk', 'name', 'categories', )

如果没有优化,此结构将生成大量数据库查询。我建议使用Django's prefetch_related操作来减少还原剂查询的数量。