web-dev-qa-db-ja.com

AssertionError: `HyperlinkedIdentityField`にはシリアライザコンテキストでのリクエストが必要です

私は、1人が多くのクラブに所属でき、1つのクラブが多くの人を持つことができるmany-to-many関係を作成したいと考えています。次のロジックにmodels.pyserializers.pyを追加しましたが、コマンドプロンプトでシリアル化しようとすると、次のエラーが表示されます-ここで何が問題になっていますか? HyperlinkedIdentityFieldさえありません

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) 

作成されたシリアライザーを検査すると、これが得られます-

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)

しかしserializer.dataは私にエラーを与えます

****************** edit *********************私はエラーがurlパターンなので、次のURLパターンを追加しましたが、それでもエラーが発生します-

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'),
])
23
qwertp

HyperlinkedIdentityFieldがシリアライザのrequestcontextを受信すると、絶対URLを構築できるため、このエラーが発生します。コマンドラインでシリアライザを初期化しているため、リクエストにアクセスできないため、エラーを受け取ります。

コマンドラインでシリアライザを確認する必要がある場合は、次のようなことを行う必要があります。

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

URLフィールドはhttp://testserver/person/1/のようになります。

私には2つの解決策があります...

urls.py

1) router.registerを使用している場合は、base_nameを追加できます。

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

2)次のような場合:

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

コンテキストをシリアライザに渡す

views.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)

このように、シリアライザで引き続きURLを使用できます:serializers.py

...
url = serializers.HyperlinkedIdentityField(view_name="user")
...
18
Slipstream

私は同じ問題に出くわしました。私のアプローチは、serializer.pyのMeta.fieldsから「url」を削除することです。

9
Diansheng

Slipstreamの回答に続いて、私はviews.pyを編集してコンテキストを紹介しました。

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)
4
MDT

MDTの応答に続いて、Django-rest-frameworkを使用し、リクエストをrequest._requestに変更して解決します。

serializer_context = {'request': Request(request._request)}
0
Chestermomo