Without the cache_tree_children method cache_tree_children you could probably serialize your children by simply connecting ToManyField with full=True , specifying the children property:
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()
To implement the cache_tree_children function, you can write your own subclass ToManyField , which overrides the standard dehydrate function. Please note that I tested this solution very superficially:
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 = []
One of the main advantages of this method is that you no longer need to worry about the limitations / differences of the view / list. You can even parameterize this aspect of your resource until you get some default behavior that suits your needs. Based on the field, that is. I think this is cool.
source share