DRF多对一反向查找

rat*_*kin 9 django django-rest-framework

我有一个返回宠物及其主人的 API 端点。

  • 每个主人都有一个名字和一只或多只宠物
  • 每只宠物都有一个名字和一个主人

Django 模型示例:

class Owner(models.Model):
    name = models.CharField(max_length=200)

class Pet(models.Model):
    owner = models.ForeignKey(Owner, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
Run Code Online (Sandbox Code Playgroud)

我已经配置了我的 API 来返回这样的 JSON 数据:

[
    {
        "id": 2,
        "name": "Scotch",
        "owner": {
            "id": 2,
            "name": "Ben"
        }
    },
    {
        "id": 3,
        "name": "Fluffy",
        "owner": {
            "id": 1,
            "name": "Fred"
        }
    },
    {
        "id": 1,
        "name": "Spot",
        "owner": {
            "id": 1,
            "name": "Fred"
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

DRF 序列化器示例:

class OwnerSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Owner
        fields = ("id", "name")

class PetSerializer(serializers.HyperlinkedModelSerializer):
    owner = OwnerSerializer()
    class Meta:
        model = Pet
        fields = ("id", "name", "owner")
Run Code Online (Sandbox Code Playgroud)

虽然这一切都很好,但我实际上希望有一个返回所有者及其宠物列表的端点。所以我会得到这个数据:

[
    {
        "id": 1,
        "name": "Fred",
        "pets": [
            { "id": 1, "name": "Spot" },
            { "id": 3, "name": "Fluffy" }
        ]
    },
    {
        "id": 2,
        "name": "Ben",
        "pets": [
            { "id": 2, "name": "Scotch" }
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

我怎样才能达到那个输出?

nev*_*ner 9

您需要pet_set像这样向 OwnerSerializer添加字段:

class PetSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Pet
        fields = ("id", "name")

class OwnerSerializer(serializers.HyperlinkedModelSerializer):
    pet_set = PetSerializer(many=True, read_only=True)
    class Meta:
        model = Owner
        fields = ("id", "name", "pet_set")
Run Code Online (Sandbox Code Playgroud)

这将起作用,因为多对一关系默认反向查找名称是<model>_setpet_set在您的情况下。您可以使用related_name以下方法更改它:

class Pet(models.Model):
    owner = models.ForeignKey(Owner, related_name='pets', on_delete=models.CASCADE)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以pets在序列化程序中使用名称:

class OwnerSerializer(serializers.HyperlinkedModelSerializer):
    pets = PetSerializer(many=True, read_only=True)
Run Code Online (Sandbox Code Playgroud)

现在OwnerListView你可以使用这个新的序列化器:

class OwnerListView(ListAPIView):
    queryset = Owner.objects.all()
    serializer_class = OwnerSerializer
Run Code Online (Sandbox Code Playgroud)