DRF 无法使用 PrimaryKeyRelatedField 上的视图名称为超链接关系解析 URL
DRF Could not resolve URL for hyperlinked relationship using view name on PrimaryKeyRelatedField
我对 DRF 序列化器上的 POST 请求有一个令人沮丧的问题 - 由于某种原因,DRF 会转到不正确的视图名称,并且 view_name
不是可设置的 属性 在 PrimaryKeyRelated Field
.
型号:
# (the class with the issue)
class Section(models.Model):
teacher = models.ManyToManyField(Teacher)
# (a class that works, using the same pattern)
class Assessment(models.Model):
standards = models.ManyToManyField(Standard)
序列化程序:
# (doesn't work)
class SectionInfoSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="gbook:section-detail")
teacher = serializers.PrimaryKeyRelatedField(many=True, read_only=True),
teachers_id = serializers.PrimaryKeyRelatedField(write_only=True, queryset=Teacher.objects.all(), many=True, source='teacher', allow_empty=False)
class Meta:
model = Section
fields = '__all__'
read_only_fields = ['sendEmails', 'teacher', 'course']
# (works)
class AssessmentSerializer(serializers.HyperlinkedModelSerializer):
pk = serializers.PrimaryKeyRelatedField(read_only=True)
url = serializers.HyperlinkedIdentityField(view_name="appname:assessments-detail")
standards = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
standards_id = serializers.PrimaryKeyRelatedField(queryset=Standard.objects.all(), source='standards', write_only=True, many=True, allow_empty=False)
class Meta:
model = Assessment
fields = '__all__'
网址:
router.register(r'teachers', teacher_views.TeacherViewSet, basename='teacher')
router.register(r'sections', course_views.SectionViewSet)
router.register(r'standards', gbook.views.standard_views.StandardViewSet, basename='standards')
router.register(r'assessments', AssessmentViewSet, basename='assessments')
我在 POST 和 PUT 期间使用 _id
字段发送相关对象的 ID,然后序列化它们。这对 AssessmentSerializer
(以及其他几个)非常有效,但由于我无法弄清楚的原因而失败了。当然,错误返回的视图中缺少应用程序名称,但我不知道为什么会这样,为什么以前没有这样。
堆栈跟踪:
Internal Server Error: /appname/sections/
Traceback (most recent call last):
File "/venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 393, in to_representation
url = self.get_url(value, self.view_name, request, format)
File "/venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 331, in get_url
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
File "/venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 47, in reverse
url = _reverse(viewname, args, kwargs, request, format, **extra)
File "/venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 60, in _reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
File "/venv2/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "/venv2/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'teacher-detail' not found. 'teacher-detail' is not a valid view function or pattern name.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
raise exc
File "/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/mixins.py", line 20, in create
headers = self.get_success_headers(serializer.data)
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 562, in data
ret = super().data
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 529, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 533, in to_representation
return [
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 534, in <listcomp>
self.child_relation.to_representation(value)
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 408, in to_representation
raise ImproperlyConfigured(msg % self.view_name)
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "teacher-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
[24/Dec/2020 09:55:04] "POST /appname/sections/ HTTP/1.1" 500 157269
所以,我错过的是这些是 HyperlinkedModelSerializer。评估的不同之处在于您处理 ManyToMany 的方式。
HyperlinkedModelSerializer,为相关字段生成 HyperlinkedRelatedField,并从 rest_framework.utils.get_detail_view_name
生成 view_name,它没有应用程序名称的功能。
这是由 build_field
完成的,它根据从 rest_framework.utils.model_meta.get_field_info()
获得的模型信息委托给 build_relational_field
。
您的 teacher
字段可能在那里。
我不确定为什么它适用于评估,因为我也找不到 reject/accept 的条件,但我的直觉告诉我,因为 PrimaryKeyRelatedField 是一个相关字段,它不会构建一个HyperlinkedRelatedField.
无论哪种方式,您都应该查看传递给 build_relational_field
的字段名称 is/are 来解决这个问题。
解决方案
删除教师字段定义后的尾随逗号:
teacher = serializers.PrimaryKeyRelatedField(many=True, read_only=True),
------^
这会将 teacher 变成一个元组,teachers_id 也会消失。结果,创建了标准超链接相关字段:
SectionInfoSerializer(instance=<Section: Section object (1)>):
url = HyperlinkedIdentityField(view_name='gbook:section-detail')
teachers_id = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=<QuerySet [<Teacher: Teacher object (1)>]>, source='teacher', write_only=True)
send_emails = BooleanField(required=False)
teacher = HyperlinkedRelatedField(allow_empty=False, many=True, read_only=True, view_name='teacher-detail')
course = HyperlinkedRelatedField(allow_empty=False, many=True, read_only=True, view_name='course-detail')
我对 DRF 序列化器上的 POST 请求有一个令人沮丧的问题 - 由于某种原因,DRF 会转到不正确的视图名称,并且 view_name
不是可设置的 属性 在 PrimaryKeyRelated Field
.
型号:
# (the class with the issue)
class Section(models.Model):
teacher = models.ManyToManyField(Teacher)
# (a class that works, using the same pattern)
class Assessment(models.Model):
standards = models.ManyToManyField(Standard)
序列化程序:
# (doesn't work)
class SectionInfoSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="gbook:section-detail")
teacher = serializers.PrimaryKeyRelatedField(many=True, read_only=True),
teachers_id = serializers.PrimaryKeyRelatedField(write_only=True, queryset=Teacher.objects.all(), many=True, source='teacher', allow_empty=False)
class Meta:
model = Section
fields = '__all__'
read_only_fields = ['sendEmails', 'teacher', 'course']
# (works)
class AssessmentSerializer(serializers.HyperlinkedModelSerializer):
pk = serializers.PrimaryKeyRelatedField(read_only=True)
url = serializers.HyperlinkedIdentityField(view_name="appname:assessments-detail")
standards = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
standards_id = serializers.PrimaryKeyRelatedField(queryset=Standard.objects.all(), source='standards', write_only=True, many=True, allow_empty=False)
class Meta:
model = Assessment
fields = '__all__'
网址:
router.register(r'teachers', teacher_views.TeacherViewSet, basename='teacher')
router.register(r'sections', course_views.SectionViewSet)
router.register(r'standards', gbook.views.standard_views.StandardViewSet, basename='standards')
router.register(r'assessments', AssessmentViewSet, basename='assessments')
我在 POST 和 PUT 期间使用 _id
字段发送相关对象的 ID,然后序列化它们。这对 AssessmentSerializer
(以及其他几个)非常有效,但由于我无法弄清楚的原因而失败了。当然,错误返回的视图中缺少应用程序名称,但我不知道为什么会这样,为什么以前没有这样。
堆栈跟踪:
Internal Server Error: /appname/sections/
Traceback (most recent call last):
File "/venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 393, in to_representation
url = self.get_url(value, self.view_name, request, format)
File "/venv2/lib/python3.8/site-packages/rest_framework/relations.py", line 331, in get_url
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
File "/venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 47, in reverse
url = _reverse(viewname, args, kwargs, request, format, **extra)
File "/venv2/lib/python3.8/site-packages/rest_framework/reverse.py", line 60, in _reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
File "/venv2/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "/venv2/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'teacher-detail' not found. 'teacher-detail' is not a valid view function or pattern name.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
raise exc
File "/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "/lib/python3.8/site-packages/rest_framework/mixins.py", line 20, in create
headers = self.get_success_headers(serializer.data)
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 562, in data
ret = super().data
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "/lib/python3.8/site-packages/rest_framework/serializers.py", line 529, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 533, in to_representation
return [
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 534, in <listcomp>
self.child_relation.to_representation(value)
File "/lib/python3.8/site-packages/rest_framework/relations.py", line 408, in to_representation
raise ImproperlyConfigured(msg % self.view_name)
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "teacher-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
[24/Dec/2020 09:55:04] "POST /appname/sections/ HTTP/1.1" 500 157269
所以,我错过的是这些是 HyperlinkedModelSerializer。评估的不同之处在于您处理 ManyToMany 的方式。
HyperlinkedModelSerializer,为相关字段生成 HyperlinkedRelatedField,并从 rest_framework.utils.get_detail_view_name
生成 view_name,它没有应用程序名称的功能。
这是由 build_field
完成的,它根据从 rest_framework.utils.model_meta.get_field_info()
获得的模型信息委托给 build_relational_field
。
您的 teacher
字段可能在那里。
我不确定为什么它适用于评估,因为我也找不到 reject/accept 的条件,但我的直觉告诉我,因为 PrimaryKeyRelatedField 是一个相关字段,它不会构建一个HyperlinkedRelatedField.
无论哪种方式,您都应该查看传递给 build_relational_field
的字段名称 is/are 来解决这个问题。
解决方案
删除教师字段定义后的尾随逗号:
teacher = serializers.PrimaryKeyRelatedField(many=True, read_only=True),
------^
这会将 teacher 变成一个元组,teachers_id 也会消失。结果,创建了标准超链接相关字段:
SectionInfoSerializer(instance=<Section: Section object (1)>):
url = HyperlinkedIdentityField(view_name='gbook:section-detail')
teachers_id = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=<QuerySet [<Teacher: Teacher object (1)>]>, source='teacher', write_only=True)
send_emails = BooleanField(required=False)
teacher = HyperlinkedRelatedField(allow_empty=False, many=True, read_only=True, view_name='teacher-detail')
course = HyperlinkedRelatedField(allow_empty=False, many=True, read_only=True, view_name='course-detail')