AssertionError: `HyperlinkedIdentityField` requires the request in the serializer context
Solution 1
You're getting this error as the HyperlinkedIdentityField
expects to receive request
in context
of the serializer so it can build absolute URLs. As you are initializing your serializer on the command line, you don't have access to request and so receive an error.
If you need to check your serializer on the command line, you'd need to do something like this:
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
Your url field would look something like http://testserver/person/1/
.
Solution 2
I have two solutions...
urls.py
1) If you are using a router.register, you can add the base_name:
router.register(r'users', views.UserViewSet, base_name='users')
urlpatterns = [
url(r'', include(router.urls)),
]
2) If you have something like this:
urlpatterns = [
url(r'^user/$', views.UserRequestViewSet.as_view()),
]
You have to pass the context to the serializer:
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)
Like this you can continue to use the url on your serializer: serializers.py
...
url = serializers.HyperlinkedIdentityField(view_name="user")
...
Solution 3
I came across the same problem. My approach is to remove 'url' from Meta.fields in serializer.py.
Solution 4
Following Slipstream's answer, I edited my views.py
introducing the context and now it works.
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)
Solution 5
You can simply pass None
to 'request'
key in context
in situations where you just need the relative URL, e.g; testing a serializer in command line.
serializer = YourModelSerializer(modelInstance_or_obj, context={'request': None})
qwertp
Updated on January 19, 2022Comments
-
qwertp over 2 years
I want to create a
many-to-many
relationship where one person can be in many clubs and one club can have many persons. I added themodels.py
andserializers.py
for the following logic but when I try to serialize it in the command prompt, I get the following error - What am I doing wrong here? I don't even have aHyperlinkedIdentityField
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)
Inspecting the created serializer gives me this -
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)
but
serializer.data
gives me the errorEdit
I realized the error could be because of
url
patterns, so I added the following url patterns but I still get the error -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'), ])
-
Naila Akbar almost 8 yearsyour answer resolved my issue but i didn't understand the problem? can you please explain it a little more? as I'm not calling it from command line
-
Ashley 'CptLemming' Wilson almost 8 yearsMy answer is somewhat specific to instantiating a serializer outside of the request / response cycle (i.e. on the shell). If you're having issues other than this I'd suggest raising a new question. However to reiterate: you must have a
Request
object available incontext
in order to useHyperlinkedIdentityField
. The above snippet creates a stub request to get around this where one is not normally available. -
Sergei almost 8 yearsif you using Versioning with REST framework you need to patch request
from rest_framework.versioning import URLPathVersioning request.version = 'v1' request.versioning_scheme = URLPathVersioning()
-
James Gardiner almost 6 yearsNote to others, ALL other suggestions here did not work, and it was only this that did. And I am confused as to why as I don't use HyperlinkedIdentityField in any part of my project...
-
MadhuP over 5 years@Ashley'CptLemming'Wilson can't we get like 127.0.0.1:8000/person/1. What we need to do that?
-
lmiguelvargasf over 5 yearsprobably you will get a message
DisallowedHost: Invalid HTTP_HOST header: 'testserver'. You may need to add 'testserver' to ALLOWED_HOSTS.
, in that case, just add'testserver'
toALLOWED_HOSTS
in yoursettings.py
file. -
Aaron about 3 yearsThis is a great answer for cases where we just don't care about the hyperlink
-
Azhar Uddin Sheikh about 2 years@JamesGardiner it's working just need to add
context={'request':request}
where your serializer is instantiated as Django suggest