11

Desidero creare una relazione many-to-many in cui una persona può trovarsi in molti club e un club può avere più persone. Ho aggiunto models.py e serializers.py per la seguente logica, ma quando provo a serializzarlo nel prompt dei comandi, ottengo il seguente errore - Che cosa sto facendo male qui? Non hanno nemmeno un HyperlinkedIdentityFieldAssertionError: `HyperlinkedIdentityField` richiede la richiesta nel contesto serializzatore

Traceback (most recent call last): 
File "<console>", line 1, in <module> 
File "C:\Users\user\corr\lib\site-packages\rest_framework\serializers.py", line 503, in data 
ret = super(Serializer, self).data 
File "C:\Users\user\corr\lib\site-packages\rest_framework\serializers.py", line 239, in data 
self._data = self.to_representation(self.instance) 
File "C:\Users\user\corr\lib\site-packages\rest_framework\serializers.py", line 472, in to_representation 
ret[field.field_name] = field.to_representation(attribute) 
File "C:\Users\user\corr\lib\site-packages\rest_framework\relations.py", line 320, in to_representation"the serializer." % self.__class__.__name__ 
AssertionError: `HyperlinkedIdentityField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer. 

models.py

class Club(models.Model): 
    club_name = models.CharField(default='',blank=False,max_length=100) 

class Person(models.Model): 
    person_name = models.CharField(default='',blank=False,max_length=200) 
    clubs = models.ManyToManyField(Club) 

serializers.py

class ClubSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Club 
     fields = ('url','id','club_name','person') 

class PersonSerializer(serializers.ModelSerializer): 
    clubs = ClubSerializer() 
    class Meta: 
     model = Person 
     fields = ('url','id','person_name','clubs') 

views.py

class ClubDetail(generics.ListCreateAPIView): 
serializer_class = ClubSerializer 

def get_queryset(self): 
    club = Clubs.objects.get(pk=self.kwargs.get('pk',None)) 
    persons = Person.objects.filter(club=club) 
    return persons 

class ClubList(generics.ListCreateAPIView): 
    queryset = Club.objects.all() 
    serializer_class = ClubSerializer 


class PersonDetail(generics.RetrieveUpdateDestroyAPIView): 
    serializer_class = PersonSerializer 


def get_object(self): 
    person_id = self.kwargs.get('pk',None) 
    return Person.objects.get(pk=person_id) 

Ispezione del serializzatore creato mi dà questo -

PersonSerializer(<Person: fd>): 
url = HyperlinkedIdentityField(view_name='person-detail') 
id = IntegerField(label='ID', read_only=True) 
person_name = CharField(max_length=200, required=False) 
clubs = ClubSerializer(): 
    url = HyperlinkedIdentityField(view_name='club-detail') 
    id = IntegerField(label='ID', read_only=True) 
    club_name = CharField(max_length=100, required=False) 

ma serializer.data mi dà l'errore

****************** modificare ***** **************** ho capito l'errore potrebbe essere causa di url modelli, così ho aggiunto i seguenti modelli di URL, ma ancora ottengo l'errore -

urlpatterns = format_suffix_patterns([ 
url(r'^$', views.api_root), 
url(r'^clubs/$', 
    views.ClubList.as_view(), 
    name='club-list'), 
url(r'^clubs/(?P<pk>[0-9]+)/persons/$', 
    views.ClubDetail.as_view(), 
    name='club-detail'), 
url(r'^person/(?P<pk>[0-9]+)/$', 
    views.PersonDetail.as_view(), 
    name='person-detail'), 
]) 
+0

Come si avvia il serializzatore? –

+0

modificato nella domanda – qwertp

risposta

18

È si sta verificando questo errore dato che lo HyperlinkedIdentityField si aspetta di ricevere request i n context del serializzatore in modo che possa creare URL assoluti. Mentre si sta inizializzando il serializzatore sulla riga di comando, non si ha accesso alla richiesta e quindi si riceve un errore.

Se avete bisogno di controllare il vostro serializzatore sulla riga di comando, avresti bisogno di fare qualcosa di simile:

from rest_framework.request import Request 
from rest_framework.test import APIRequestFactory 

from .models import Person 
from .serializers import PersonSerializer 

factory = APIRequestFactory() 
request = factory.get('/') 


serializer_context = { 
    'request': Request(request), 
} 

p = Person.objects.first() 
s = PersonSerializer(instance=p, context=serializer_context) 

print s.data 

tuo campo URL sarebbe simile http://testserver/person/1/.

+0

la risposta ha risolto il problema ma non ho capito il problema? puoi spiegarlo un po 'di più? poiché non lo chiamo dalla riga di comando –

+1

La mia risposta è in qualche modo specifica per l'istanziazione di un serializzatore al di fuori del ciclo richiesta/risposta (cioè sulla shell). Se hai problemi diversi da questo suggerirei di sollevare una nuova domanda. Tuttavia, per ripetere: devi avere un oggetto 'Request' disponibile in' context' per usare 'HyperlinkedIdentityField'. Il frammento di cui sopra crea una richiesta di stub per aggirare questo in cui uno non è normalmente disponibile. –

+0

se si utilizza versioni con quadro REST è necessario patchare richiesta 'da rest_framework.versioning importazione URLPathVersioning request.version = 'v1' request.versioning_scheme = URLPathVersioning()' – Sergei

6

Mi sono imbattuto nello stesso problema. Il mio approccio è quello di rimuovere 'url' da Meta.fields in serializer.py.

6

Ho due soluzioni ...

urls.py

1) Se si utilizza un router.register, è possibile aggiungere la base_name:

router.register(r'users', views.UserViewSet, base_name='users') 
urlpatterns = [  
    url(r'', include(router.urls)), 
] 

2) Se si dispone di cosa come questa:

urlpatterns = [  
    url(r'^user/$', views.UserRequestViewSet.as_view()), 
] 

Devi passare il contesto per il serializzatore:

vista.py

class UserRequestViewSet(APIView):    
    def get(self, request, pk=None, format=None): 
     user = ...  
     serializer_context = { 
      'request': request, 
     } 
     serializer = api_serializers.UserSerializer(user, context=serializer_context)  
     return Response(serializer.data) 

come non è possibile continuare a utilizzare l'URL sul serializer: serializers.py

... 
url = serializers.HyperlinkedIdentityField(view_name="user") 
... 
2

seguito la risposta di Slipstream, ho modificato il mio views.py introducendo il contesto e ora funziona .

class UserViewSet(viewsets.ModelViewSet): 

    """ 
    API endpoint that allows users to be viewed or edited. 
    """ 
    queryset = User.objects.all().select_related('profile').order_by('-date_joined') 
    serializer_class = UserSerializer 

    @list_route(methods=['get'], url_path='username/(?P<username>\w+)') 
    def getByUsername(self, request, username): 
     serializer_context = { 
      'request': request, 
     } 
     user = get_object_or_404(User, username=username) 
     return Response(UserSerializer(user, context=serializer_context).data, status=status.HTTP_200_OK) 
Problemi correlati