我想在 API 响应中获取一个 json 字段,其中列出了基于 two 反向外键关系的相关对象的标识符。下面给出了我的意思的简单例子。我非常希望在 Django REST Framework 序列化器级别上处理它,而不是必须以某种方式更改模型,但我几乎没有 DRF 经验,而且我一生都无法弄清楚如何实际执行它。
示例模型.py:
class Person(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
father = models.ForeignKey(
"self",
related_name="children_as_father",
blank=True,
null=True,
on_delete=models.SET_NULL,
)
mother = models.ForeignKey(
"self",
related_name="children_as_mother",
blank=True,
null=True,
on_delete=models.SET_NULL,
)
数据库数据示例:
id | 名字 | 姓氏 | 妈妈 | 父亲 |
---|---|---|---|---|
1 | 简 | 史密斯 | ||
2 | 约翰 | 史密斯 | ||
3 | 克拉伦斯 | 史密斯 | 1 | 2 |
4 | 托马斯 | 史密斯 | 1 | 2 |
我想获得的序列化 json 示例:
[
{
"pk": 1,
"first_name": "Jane",
"last_name": "Smith",
"mother": null,
"father": null,
"children": [
3,4
],
},
{
"pk": 2,
"first_name": "John",
"last_name": "Smith",
"mother": null,
"father": null,
"children": [
3,4
],
},
{
"pk": 3,
"first_name": "Clarence",
"last_name": "Smith",
"mother": 1,
"father": 2,
"children": [],
},
{
"pk": 4,
"first_name": "Thomas",
"last_name": "Smith",
"mother": 1,
"father": 2,
"children": [],
}
]
这就是我的实验所能得到的:
序列化器.py
from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField
from .models import Person
class FamilySerializer(ModelSerializer):
children_as_mother = PrimaryKeyRelatedField(
many=True, read_only=True, allow_null=True
)
children_as_father = PrimaryKeyRelatedField(
many=True, read_only=True, allow_null=True
)
class Meta:
model = Person
fields = [
"pk",
"first_name",
"last_name",
"mother",
"father",
"children_as_mother",
"children_as_father",
]
views.py
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from .models import Person
from .serializers import FamilySerializer
class FamilyViewSet(ModelViewSet):
"""
API endpoint with family data
"""
queryset = Person.objects.all()
serializer_class = FamilySerializer
permission_classes = [IsAuthenticated]
序列化json:
[
{
"pk": 1,
"first_name": "Jane",
"last_name": "Smith",
"mother": null,
"father": null,
"children_as_mother": [
3,4
],
"children_as_father": [],
},
{
"pk": 2,
"first_name": "John",
"last_name": "Smith",
"mother": null,
"father": null,
"children_as_mother": [],
"children_as_father": [
3,4
],
},
{
"pk": 3,
"first_name": "Clarence",
"last_name": "Smith",
"mother": 1,
"father": 2,
"children_as_mother": [],
"children_as_father": [],
},
{
"pk": 4,
"first_name": "Thomas",
"last_name": "Smith",
"mother": 1,
"father": 2,
"children_as_mother": [],
"children_as_father": [],
}
]
正如你所看到的,与第一个 json 示例相比,这并不完全是我想要的 - 我想要一个 json 字段来列出一个人的孩子标识符(“children”),而不是两个(“children_as_mother”,“children_as_father”) .
我设法找到了一个可以接受的解决方案。以下是我如何通过重写 to_representation 函数来修改序列化器:
class FamilySerializer(ModelSerializer):
children_as_mother = PrimaryKeyRelatedField(
many=True, read_only=True, allow_null=True
)
children_as_father = PrimaryKeyRelatedField(
many=True, read_only=True, allow_null=True
)
class Meta:
model = Person
fields = [
"pk",
"first_name",
"last_name",
"mother",
"father",
"children_as_mother",
"children_as_father",
]
def to_representation(self, instance):
data = super(FamilySerializer, self).to_representation(instance)
data["children"] = data["children_as_father"]+data["children_as_mother"]
del data["children_as_mother"]
del data["children_as_father"]
return data
或者 to_representation 也可以像这样被覆盖,以获得与我的特定数据集相同的效果:
def to_representation(self, instance):
data = super(FamilySerializer, self).to_representation(instance)
if data["children_as_father"]:
data["children"] = data["children_as_father"]
elif data["children_as_mother"]:
data["children"] = data["children_as_mother"]
else:
data["children"]=[]
del data["children_as_mother"]
del data["children_as_father"]
return data
我会将问题留出几天,以防有人想到其他解决方案,之后我会将其标记为正确答案。