在 Django Rest Framework 中生成 OpenAPI Schema:更新视图集中的 URL 关键字

Posted

技术标签:

【中文标题】在 Django Rest Framework 中生成 OpenAPI Schema:更新视图集中的 URL 关键字【英文标题】:Generating OpenAPI Schema in Django Rest Framework: URL Keyword in Update ViewSet 【发布时间】:2021-01-13 09:12:05 【问题描述】:

我正在尝试做一些应该非常直截了当的事情,但我遇到了一个我无法正面或反面的问题。我希望有人能帮我解决这个问题。

我已经使用 DRF 创建了一些 API 端点。自然地,我使用 django_rest_framework.generics 构建了 Create、Update、Retrieve 和 Delete 端点。我需要从 CreateAPIView 和 UpdateAPIView 上的 ViewSet 向序列化程序发送一些额外的数据。为此,我在这些 ViewSet 上扩展了 get_serializer_context() 方法。

我现在正在尝试为这些端点创建 OpenAPI 文档。但是,当我在 manage.py 中运行 generateschema 时,它会返回错误。此错误发生在我扩展 get_serializer_context() 方法的每个 UpdateAPIViews 中。此错误的示例如下所示。

AssertionError: Expected view UpdateStaffViewSet to be called with a URL keyword argument named "staff_id". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.

当然,我们会认为我弄错了 URL 关键字或 lookup_field,正如错误所述。除非我正在查看一些明显的东西,否则我就是看不出问题所在。在使用 curl 或 postman 进行测试时,这些端点可以完美运行。我知道如果我删除扩展的get_serializer_context() 方法,generateschema 命令可以正常工作。 (但是使用 postman/curl 的测试会失败。)为什么这种扩展方法很重要!?

urls.py

url_patterns = [
    path('v1/staff/retrieve/<int:staff_id>/', RetrieveStaffViewSet.as_view()),
    path('staff/update/<int:staff_id>/', UpdateStaffViewSet.as_view()),
    ...
]

视图集

class UpdateRetrieveBase:
    serializer_class = StaffSerializer
    queryset = Staff.objects.select_related('user')
    lookup_url_kwarg = 'staff_id'
    lookup_field = 'pk'


class UpdateStaffViewSet(UpdateRetrieveBase, UpdateAPIView):

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['validation_refs'] = get_validation_refs(staff=self.get_object())

        return context


class RetrieveStaffViewSet(UpdateRetrieveBase, RetrieveAPIView):
    pass

【问题讨论】:

【参考方案1】:

好吧,毕竟,我找到了自己的答案。我会把它贴在这里以防其他人也被难住了。

由于generateschema 命令运行测试但不包含 URL kwargs,我们不能在视图集中调用get_object()。测试必须考虑到这一点,但不考虑我们可能会在其他任何地方调用该方法。为了在我的特殊情况下解决这个问题,我编辑了代码。

视图集

class UpdateAEAContractViewSet(UpdateRetrieveBase, UpdateAPIView):

    def get_serializer_context(self):
        context = super().get_serializer_context()
        contract_id = self.kwargs.get(self.lookup_url_kwarg)
        context['validation_refs'] = get_validation_refs(contract_id=contract_id)
        return context

验证参考子作业

def get_validation_refs(staff_id=None):
    staff = Staff.objects.get(pk=staff_id) if staff_id else None

    ...

【讨论】:

以上是关于在 Django Rest Framework 中生成 OpenAPI Schema:更新视图集中的 URL 关键字的主要内容,如果未能解决你的问题,请参考以下文章

django使用rest_framework

Django Rest Framework

Django rest framework 身份和权限验证

Django Rest Framework:非模型服务

django-rest-framework - 在可浏览的 API 中自动生成表单?

在 django-rest-framework 中,是不是可以同时使用 oauth 和 session 身份验证?