【问题标题】:Serializing django-mptt trees in Tastypie在 Tastypie 中序列化 django-mptt 树
【发布时间】:2013-03-08 01:52:15
【问题描述】:

如何序列化Tastypie 中的django-mptt 树?

我想使用django-mpttcache_tree_children()。我尝试过应用不同的 Tastypie 钩子,但它会引发错误。

【问题讨论】:

    标签: django tastypie django-mptt


    【解决方案1】:

    如果没有cache_tree_children 方法,您可能只需将ToManyField 与指向children 属性的full=True 连接起来,就可以让您的孩子序列化:

    class MenuResource(ModelResource):
    
        children = fields.ToManyField('self', 'children', null=True, full=True)
        parent = fields.ToOneField('self', 'parent', null=True)
    
        class Meta:
            queryset = Menu.objects.all()
    

    要实现cache_tree_children 函数,您可以编写自己的ToManyField 子类来覆盖标准dehydrate 函数。请注意,我只是非常肤浅地测试了这个解决方案:

    def dehydrate(self, bundle):
        if not bundle.obj or not bundle.obj.pk:
        if not self.null:
            raise ApiFieldError("The model '%r' does not have a primary key and can not be used in a ToMany context." % bundle.obj)
    
            return []
    
        the_m2ms = None
        previous_obj = bundle.obj
        attr = self.attribute
    
        if isinstance(self.attribute, basestring):
            attrs = self.attribute.split('__')
            the_m2ms = bundle.obj
    
            for attr in attrs:
                previous_obj = the_m2ms
                try:
                    the_m2ms = getattr(the_m2ms, attr, None)
                except ObjectDoesNotExist:
                    the_m2ms = None
    
                if not the_m2ms:
                    break
    
        elif callable(self.attribute):
            the_m2ms = self.attribute(bundle)
    
        if not the_m2ms:
            if not self.null:
                raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
    
            return []
    
        self.m2m_resources = []
        m2m_dehydrated = []
    
        # There goes your ``cache_tree_children``
        for m2m in cache_tree_children(the_m2ms.all()):
            m2m_resource = self.get_related_resource(m2m)
            m2m_bundle = Bundle(obj=m2m, request=bundle.request)
            self.m2m_resources.append(m2m_resource)
            m2m_dehydrated.append(self.dehydrate_related(m2m_bundle, m2m_resource))
    
        return m2m_dehydrated
    

    此方法的主要优点之一是您不必再关心细节/列表视图约束/差异。您甚至可以进一步参数化资源的这一方面,直到您获得某种符合您需要的默认行为。即基于字段。我认为这很酷。

    【讨论】:

      【解决方案2】:

      我就是这样解决的:

      class MenuResource(ModelResource):
          parent = fields.ForeignKey('self', 'parent', null=True)
      
          class Meta:
              serializer = PrettyJSONSerializer()
              queryset = Menu.objects.all().select_related('parent')
              include_resource_uri = False
              fields = ['name']
      
          def get_child_data(self, obj):
              data =  {
                  'id': obj.id,
                  'name': obj.name,
              }
              if not obj.is_leaf_node():
                  data['children'] = [self.get_child_data(child) \
                                      for child in obj.get_children()]
              return data
      
          def get_list(self, request, **kwargs):
      
              base_bundle = self.build_bundle(request=request)
              objects = self.obj_get_list(bundle=base_bundle, 
                                          **self.remove_api_resource_names(kwargs))
              sorted_objects = self.apply_sorting(objects, options=request.GET)
      
              paginator = self._meta.paginator_class(
                  request.GET, sorted_objects, 
                  resource_uri=self.get_resource_uri(), limit=self._meta.limit, 
                  max_limit=self._meta.max_limit, 
                  collection_name=self._meta.collection_name
              )
              to_be_serialized = paginator.page()
      
              from mptt.templatetags.mptt_tags import cache_tree_children
              objects = cache_tree_children(objects)
      
              bundles = []
      
              for obj in objects:
                  data = self.get_child_data(obj)
                  bundle = self.build_bundle(data=data, obj=obj, request=request)
                  bundles.append(self.full_dehydrate(bundle))
      
              to_be_serialized[self._meta.collection_name] = bundles
              to_be_serialized = self.alter_list_data_to_serialize(request, 
                                                                  to_be_serialized)
              return self.create_response(request, to_be_serialized)
      

      如果你不使用分页,你可以把那部分去掉。我就是这么做的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-11
        • 1970-01-01
        • 1970-01-01
        • 2012-09-02
        • 2011-08-01
        • 2018-05-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多