【问题标题】:How to serialize a Django MPTT family and keep it hierarchical?如何序列化 Django MPTT 系列并保持分层?
【发布时间】:2018-05-25 13:57:31
【问题描述】:

我试图为this (Google cache) 寻找解决方案

我只能想出这样的解决方案:

import json

from mptt.utils import tree_item_iterator
from rest_framework import generics
from rest_framework.response import Response

from .models import Category

def tree_family_items_to_json(instances):
    data = ''
    channel = '"{}"'.format(instances[0].channel.slug)
    for category, structure in tree_item_iterator(instances):
        if structure['new_level']:
        data += '{'
        else:
            data += '],'
            data += '"channel": {}'.format(channel)
            data += '},{'
        data += '"slug": "{}",'.format(category.slug)
        data += '"name": "{}",'.format(category.name)
        data += '"subcategories": ['
        for level in structure['closed_levels']:
            data += '],'
            data += '"channel": {}'.format(channel)
            data += '}'

    return json.loads(data)

class CategoryFamily(generics.RetrieveAPIView):
    lookup_field = 'slug'
    queryset = Category.objects.all()

    def retrieve(self, request, *args, **kwargs):
        instances = self.get_object().get_family()
        json_data = tree_family_items_to_json(instances)
        return Response(json_data)

关键是我使用了来自 mptt 的tree_item_iterator,现在我正在寻找更花哨的东西。

它满足了一段时间的需要。但现在确定要多久。

有什么想法吗?

【问题讨论】:

    标签: python django django-rest-framework django-mptt mptt


    【解决方案1】:

    这是一种在rest api中具有树结构的方法:

    # serializers.py
    class CategoryTreeSerializer(ModelSerializer):
        children = SerializerMethodField(source='get_children')
        class Meta:
            fields = ('children',)  # add here rest of the fields from model 
    
        def get_children(self, obj):
            children = self.context['children'].get(obj.id, [])
            serializer = CategoryTreeSerializer(children, many=True, context=self.context)
            return serializer.data
    
    
     # views.py
     class CategoryViewSet(viewsets.ModelViewSet):
    
        queryset = Category.objects.all()
        serializer_class = CategoryTreeSerializer
    
        @detail_route()
        def tree(self, request, pk=None):
            """
            Detail route of an category that returns it's descendants in a tree structure.
            """
            category = self.get_object()
            descendants = category.get_descendants() # add here any select_related/prefetch_related fields to improve api performance
    
            children_dict = defaultdict(list)
            for descendant in descendants:
                children_dict[descendant.get_parent().pk].append(descendant)
    
            context = self.get_serializer_context()
            context['children'] = children_dict
            serializer = CategoryTreeSerializer(category, context=context)
    
            return Response(serializer.data)
    

    在我的情况下,您会获得一个新端点(取决于您的 url),它将是这样的:category/<category_pk>/tree,您可以在其中获得指定类别的树结构。

    这个想法是获取所有后代并为每个父代填充 children_dict,这将传递给序列化器的上下文以避免多次查询。

    【讨论】:

    • 看起来我可以像你说的那样做一些事情。我几乎到了那里。现在我正在加倍努力。
    • 我希望我能给你更多的信任,我很惊讶这个页面没有被那么多人访问,因为这是一个常见问题的非常合法的答案!
    【解决方案2】:

    您可以使用djangorestframework-recursive 更方便。

    views.py

    from rest_framework import viewsets, generics
    from yourapp.serializers import CategorySerializer
    from yourapp.models import Category
    
    class CategoryViewSet(viewsets.ModelViewSet):
        queryset = Category.objects.root_nodes()
        serializer_class = CategorySerializer
    

    序列化器.py

    from rest_framework import serializers
    from yourapp.models import Category
    from rest_framework_recursive.fields import RecursiveField
    
    class CategorySerializer(serializers.ModelSerializer):
        children = RecursiveField(many=True)
    
        class Meta:
            model = Category
            fields = ['id', 'name', 'children']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-20
      • 2014-02-02
      • 1970-01-01
      • 1970-01-01
      • 2013-01-26
      • 2014-04-02
      相关资源
      最近更新 更多