2013-03-08 3 views

Répondre

2

Voici comment je l'ai résolu:

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) 

Si vous ne l'utilisez, vous pouvez simplement pagination prendre cette partie dehors. C'est ce que j'ai fait.

6

Sans la méthode cache_tree_children vous pourriez probablement avoir vos enfants sérialisé simplement brancher un ToManyField avec full=True pointage à la propriété children:

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() 

Pour implémenter la fonction cache_tree_children vous pouvez écrire votre propre ToManyField sous-classe qui remplace la fonction standard dehydrate. S'il vous plaît noter que je ne testé cette solution très superficielle:

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 

L'un des principaux avantages de cette méthode est que vous n'avez pas à se soucier de détail/liste des contraintes de vue/différences plus. Vous pouvez même paramétrer cet aspect de votre ressource plus bas jusqu'à ce que vous ayez un comportement par défaut qui corresponde à vos besoins. Basé sur le terrain, c'est. Ce que je pense est cool.