В недавнем проекте с DRF v3.9.1 и django 2.1 мне нужно было рекурсивно показать все дочерние объекты объекта, имея только прямую связь с родителем, который мог иметь несколько дочерних элементов.
Раньше, если бы я запрашивал «дерево» объекта, я получал:
{
"uuid": "b85385c0e0a84785b6ca87ce50132659",
"name": "a",
"parent": null
}
Применяя сериализацию, показанную ниже, я получаю:
{
"uuid": "b85385c0e0a84785b6ca87ce50132659",
"name": "a",
"parent": null
"children": [
{
"uuid": "efd26a820b4e4f7c8e56c812a7791fcb",
"name": "aa",
"parent": "b85385c0e0a84785b6ca87ce50132659"
"children": [
{
"uuid": "ca2441fc7abf49b6aa1f3ebbc2dae251",
"name": "aaa",
"parent": "efd26a820b4e4f7c8e56c812a7791fcb"
"children": [],
}
],
},
{
"uuid": "40e09c85775d4f1a8578bba9c812df0e",
"name": "ab",
"parent": "b85385c0e0a84785b6ca87ce50132659"
"children": [],
}
],
}
Вот models.py
рекурсивного объекта:
class CategoryDefinition(BaseModelClass):
name = models.CharField(max_length=100)
parent = models.ForeignKey('self', related_name='children',
on_delete=models.CASCADE,
null=True, blank=True)
Чтобы получить все обратные объекты во внешнем ключе, примените поле к классу сериализатора:
class DeepCategorySerializer(serializers.ModelSerializer):
children = serializers.SerializerMethodField()
class Meta:
model = models.CategoryDefinition
fields = '__all__'
def get_children(self, obj):
return [DeepCategorySerializer().to_representation(cat) for cat in obj.children.all()]
Затем примените этот сериализатор к функции представления DRF или к универсальному классу, например:
re_path(r'categories/(?P<pk>[\w\d]{32})/',
generics.RetrieveUpdateDestroyAPIView.as_view(
queryset=models.CategoryDefinition.objects.all(),
serializer_class=serializers.DeepCategorySerializer),
name='category-update'),