在公共外键上合并两个序列化查询集的正确方法

时间:2016-04-04 20:58:22

标签: django django-rest-framework

假设我(作为一个人为的例子)有两个模型DogHouse,他们拥有所有者的外键。对于此示例,假设每个Owner最多只能有一个Dog和一个House

class Dog(models.Model):
    name = models.CharField(max_length=36)
    fk_owner = models.ForeignKey(Owner)

class House(models.Model):
    address = models.CharField(max_length=128)
    color = models.CharField(max_length=6) #hexcode
    fk_owner = models.ForeignKey(Owner)

我从API获取序列化数据。我可以单独为DogHouse对象获取它,如下所示:

serializers.py

from rest_framework import serializers
from my_app import Dog

class DogSerializer(serializers.ModelSerializer):
    owner = serializers.CharField(source=fk_owner.name, read_only=True)
    class Meta:
        model = Dog
        fields = ('name', 'owner')
        #same thing for House

dog_api.py

from my_app.views import DogSerializer
from my_app.models import Dog
from rest_framework import generics
from django.utils.decorators import method_decorator
from rest_framework.decorators import api_view

@method_decorator(api_view(['GET']), name='dispatch')
class DogAPI(generics.ListAPIView):
    model=Dog
    serializer_class=DogSerializer
    queryset = Dog.objects.all()

哪个会给我JSON:[{"name" : "SnoopDogg", "owner" : "Bob Jones"}, etc]

问题:

组合两个具有相同Owner的JSON查询的最佳做法是什么(记住每个Owner只拥有一个HouseDog) ? DRF可以做到,还是我需要编写自己的合并功能?我想生成这个JSON:

[{"name":"SnoopDogg", "owner":"Bob Jones", "house":
    {"address":"1 Main St", "color":"FC09A9"}
},
{"name":"Snoopy", "owner":"Charlie Brown", "house":
    {"address":"1 Comic Strip", "color":"00FF00"}
},
etc...
]

1 个答案:

答案 0 :(得分:1)

首先,如果拥有者只能拥有一只狗和一所房子,那么您应该使用OneToOne relation代替OneToMany。

class Dog(models.Model):
    name = models.CharField(max_length=36)
    fk_owner = models.OneToOneField(Owner)

class House(models.Model):
    address = models.CharField(max_length=128)
    color = models.CharField(max_length=6) #hexcode
    fk_owner = models.OneToOneField(Owner)

如果我找到了你,你希望DogAPI视图也能归还所有者/狗居住的房子。您可以通过在HouseSerializer中定义SerializerMethodFieldDogSerializer来实现这一目标:

from rest_framework import serializers
from my_app import Dog, House

class HouseSerializer(serializers.ModelSerializer):

    class Meta:
        model = House

class DogSerializer(serializers.ModelSerializer):
    owner = serializers.CharField(source=fk_owner.name, read_only=True)
    house = serializers.SerializerMethodField()

    class Meta:
        model = Dog
        fields = ('name', 'owner', 'house')

    def get_house(self, obj):
        """
        Return serialized house data
        """
        house = obj.fk_owner.house
        return HouseSerializer(house).data