2012-07-19 5 views
6

-je obtenir une profondeur de récursivité maximale dépassée si une course le code ci-dessous:Django Tastypie lance une 'profondeur maximale de récurrence dépassée' lorsque full = True sur la relation inverse.

from tastypie import fields, utils 
from tastypie.resources import ModelResource 
from core.models import Project, Client 


class ClientResource(ModelResource): 
    projects = fields.ToManyField(
     'api.resources.ProjectResource', 'project_set', full=True 
    ) 
    class Meta: 
     queryset = Client.objects.all() 
     resource_name = 'client' 


class ProjectResource(ModelResource): 
    client = fields.ForeignKey(ClientResource, 'client', full=True) 
    class Meta: 
     queryset = Project.objects.all() 
     resource_name = 'project' 

# curl http://localhost:8000/api/client/?format=json 
# or 
# curl http://localhost:8000/api/project/?format=json 

Si un ensemble complet = False sur l'une des relations qu'il travaille. Je comprends pourquoi cela se produit mais j'ai besoin que les deux relations apportent des données, pas seulement le "resource_uri". Y a-t-il une façon Tastypie de le faire? J'ai réussi à résoudre le problème en créant une méthode de sérialisation sur mon modèle de projet, mais il est loin d'être élégant. Merci.

Répondre

13

Vous devez remplacer la méthode full_dehydrate sur au moins une ressource pour ignorer la ressource associée à la déshydratation qui provoque la récursivité. Vous pouvez également définir deux types de ressources qui utilisent le même modèle avec full=True et un autre avec full=False.

+3

Merci pour la pointe des deux ressources, cela me ont beaucoup aidé ... :) –

+0

@MarkShust: Je suis confronté le même genre de problème, pouvez-vous s'il vous plaît donner des précisions sur l'un des la méthode qui a fonctionné pour vous? –

+0

@NikhilAgrawal Si je me souviens bien, je viens de faire deux ressources, une avec full = True, une avec full = False, suffixé le full = False avec Simple, donc je sais quelle ressource est quoi. puis référencez la ressource appropriée. –

3

Merci @astevanovic de pointer dans la bonne direction.

J'ai trouvé que le remplacement de la méthode dehydrate pour traiter uniquement certains champs spécifiés est un peu moins fastidieux que de surcharger la méthode full_hydrate pour ignorer les champs.

Dans la poursuite de la réutilisation, je suis venu avec les extraits de code suivants. Espérons que ce serait utile à certains:

class BeeModelResource(ModelResource): 

    def dehydrate(self, bundle): 
     bundle = super(BeeModelResource, self).dehydrate(bundle) 
     bundle = self.dehydrate_partial(bundle)   
     return bundle 

    def dehydrate_partial(self, bundle): 
     for field_name, resource_field in self.fields.items(): 
      if not isinstance(resource_field, RelatedField): 
       continue 

      if resource_field.full: # already dehydrated 
       continue 

      if not field_name in self._meta.partial_fields: 
       continue 

      if isinstance(resource_field, ToOneField): 
       fk_object = getattr(bundle.obj, resource_field.attribute) 
       fk_bundle = Bundle(obj=fk_object, request=bundle.request) 
       fk_resource = resource_field.get_related_resource(fk_object) 

       bundle.data[field_name] = fk_resource.dehydrate_selected( 
         fk_bundle, self._meta.partial_fields[field_name]).data 
      elif isinstance(resource_field, ToManyField): 
       data = [] 

       fk_objects = getattr(bundle.obj, resource_field.attribute) 
       for fk_object in fk_objects.all(): 
        fk_bundle = Bundle(obj=fk_object, request=bundle.request) 
        fk_resource = resource_field.get_related_resource(fk_object) 
        fk_bundle = fk_resource.dehydrate_selected_fields( 
          fk_bundle, self._meta.partial_fields[field_name]) 
        data.append(fk_bundle.data) 
       bundle.data[field_name] = data 

     return bundle 

    def dehydrate_selected_fields(self, bundle, selected_field_names): 
     # Dehydrate each field. 
     for field_name, field_object in self.fields.items(): 
      # A touch leaky but it makes URI resolution work. 
      # (borrowed from tastypie.resources.full_dehydrate) 
      if field_name in selected_field_names and not self.is_special_fields(field_name): 
       if getattr(field_object, 'dehydrated_type', None) == 'related': 
        field_object.api_name = self._meta.api_name 
        field_object.resource_name = self._meta.resource_name 

       bundle.data[field_name] = field_object.dehydrate(bundle) 

     bundle.data['resource_uri'] = self.get_resource_uri(bundle.obj) 
     bundle.data['id'] = bundle.obj.pk 

     return bundle 

    @staticmethod 
    def is_special_fields(field_name): 
     return field_name in ['resource_uri'] 

Avec l'exemple de @sigmus, les ressources auront besoin 3 modifications:

  1. deux ressources utilisera BeeModuleResource comme super-classe (ou, ajouter dehydrate_partial à un ressources et dehydrate_selected à l'autre.)
  2. unset full=True sur l'une des ressources
  3. ajouter partial_fields dans la ressource Meta la ressource unset

`` `

class ClientResource(BeeModelResource): # make BeeModelResource a super class 
    projects = fields.ToManyField(
     'api.resources.ProjectResource', 'project_set' 
    ) # remove full=True 
    class Meta: 
     queryset = Client.objects.all() 
     resource_name = 'client' 
     partial_fields = {'projects': ['memo', 'title']} # add partial_fields 

class ProjectResource(BeeModelResource): # make BeeModelResource a super class 
    client = fields.ForeignKey(ClientResource, 'client', full=True) 
    class Meta: 
     queryset = Project.objects.all() 
     resource_name = 'project' 
Questions connexes