DRF 无法使用 PrimaryKeyRelatedField 上的视图名称解析超链接关系的 URL

问题描述

我在 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,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(以及其他几个)效果很好,但由于我无法弄清楚的原因而失败。当然,错误返回的视图中缺少 appname,但我不知道为什么会发生这种情况,以及为什么之前没有发生。

堆栈跟踪:

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,format,**extra)
  File "/venv2/lib/python3.8/site-packages/rest_framework/reverse.py",line 60,in _reverse
    url = django_reverse(viewname,args=args,**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",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,**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,**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。与评估的不同之处在于您如何处理多对多。

一个 HyperlinkedModelSerializer,为相关字段生成 HyperlinkedRelatedField 并从 rest_framework.utils.get_detail_view_name 生成 view_name,它没有应用名称的工具。

这由 build_field 完成,它根据从 build_relational_field 获得的模型信息委托给 rest_framework.utils.model_meta.get_field_info()

您的 teacher 字段可能在那里。

我不确定为什么它适用于评估,因为我也找不到拒绝/接受的条件,但我的直觉说,因为 PrimaryKeyRelatedField 是一个相关字段,所以它不会构建 HyperlinkedRelatedField。>

无论哪种方式,您都应该查看传递给 build_relational_field 的字段名称以了解这一点。

解决方案

去掉teacher字段定义后面的逗号:

teacher = serializers.PrimaryKeyRelatedField(many=True,read_only=True),------^

这会将老师变成一个元组,并且老师的_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,read_only=True,view_name='teacher-detail')
    course = HyperlinkedRelatedField(allow_empty=False,view_name='course-detail')

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...