【问题标题】:AssertionError: `HyperlinkedIdentityField` requires the request in the serializer contextAssertionError: `HyperlinkedIdentityField` 需要序列化程序上下文中的请求
【发布时间】:2016-03-30 01:01:27
【问题描述】:

我想创建一个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 给了我错误

编辑

我意识到错误可能是因为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'),
])

【问题讨论】:

  • 如何启动序列化程序?
  • 编辑成问题

标签: python django django-views django-rest-framework django-serializer


【解决方案1】:

对于外部网址,您可以简单地将请求设置为无:

context={
    'request': None
},

【讨论】:

    【解决方案2】:

    在您只需要相对 URL 的情况下,您可以简单地将 None 传递给 'request'context,例如;在命令行中测试序列化程序。

    serializer = YourModelSerializer(modelInstance_or_obj, context={'request': None})
    

    【讨论】:

    • 对于我们不关心超链接的情况,这是一个很好的答案
    【解决方案3】:

    您可以简单地通过将实例化(在views.py中)更改为如下方式来解决它:

    your_serializer = YourModelSerializer(YourQuerySet_or_object, many=True,context={'request':request})
    

    【讨论】:

      【解决方案4】:

      根据 MDT 的响应,我使用 django-rest-framework,并通过将 request 更改为 request._request 来解决它。

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

      【讨论】:

        【解决方案5】:

        根据 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)
        

        【讨论】:

        • 请注意,此处的所有其他建议均无效,仅此而已。我很困惑为什么我在项目的任何部分都没有使用 HyperlinkedIdentityField...
        【解决方案6】:

        我有两个解决方案...

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

        【讨论】:

          【解决方案7】:

          我遇到了同样的问题。我的方法是从 serializer.py 中的 Meta.fields 中删除“url”。

          【讨论】:

            【解决方案8】:

            您收到此错误是因为HyperlinkedIdentityField 期望在序列化程序的context 中接收request,因此它可以构建绝对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/

            【讨论】:

            • 您的回答解决了我的问题,但我不明白问题所在?你能再解释一下吗?因为我不是从命令行调用它
            • 我的回答有点特定于在请求/响应周期之外(即在 shell 上)实例化序列化程序。如果您还有其他问题,我建议您提出一个新问题。但是要重申:您必须在context 中有一个Request 对象才能使用HyperlinkedIdentityField。上面的 sn-p 创建了一个存根请求,以解决通常不可用的问题。
            • 如果您使用带有 REST 框架的版本控制,您需要修补请求 from rest_framework.versioning import URLPathVersioning request.version = 'v1' request.versioning_scheme = URLPathVersioning()
            • @Ashley'CptLemming'Wilson 我们不能像127.0.0.1:8000/person/1 一样。我们需要做什么?
            • 您可能会收到一条消息DisallowedHost: Invalid HTTP_HOST header: 'testserver'. You may need to add 'testserver' to ALLOWED_HOSTS.,在这种情况下,只需在您的settings.py 文件中将'testserver' 添加到ALLOWED_HOSTS 即可。
            猜你喜欢
            • 2018-09-06
            • 1970-01-01
            • 2015-12-20
            • 2013-06-26
            • 2015-09-11
            • 1970-01-01
            • 2010-10-29
            • 2018-08-11
            • 1970-01-01
            相关资源
            最近更新 更多