微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

POST 上的 django-rest-framework“此字段是必需的”

如何解决POST 上的 django-rest-framework“此字段是必需的”

每当我 POST 到我的 django-rest-framework (DRF) 端点时,我都会收到 "HTTP 400 Bad Request" {"offeror_organization":["This field is required."]} 响应。但是,鉴于下面的 curl 示例,我明确指定了一个值。

无论内容类型(application/json、application/x-www-form-urlencoded、multipart/form-data)如何,都会发生这种情况。它唯一有效的时间是当我使用 DRF 网络界面上的“HTML 表单”(与“原始数据”)选项卡提交时。

有一些类似的 SO 帖子(例如 thisthis),但似乎没有一个解决方案适合我。

型号:

class OrganizationManager(models.Manager):
    def get_by_natural_key(self,offeror_organization):
        return self.get(offeror_organization=offeror_organization)

class Organization(models.Model):
    idorganization = models.AutoField(primary_key=True)
    offeror_organization = models.CharField(max_length=250,null=False,blank=False,verbose_name='Offeror Organization')
    created_at = models.DateTimeField(auto_Now_add=True,null=False)
    updated_at = models.DateTimeField(auto_Now=True,null=False)

    objects = OrganizationManager()

    def natural_key(self):
        return "%s" % (self.offeror_organization)

    def __str__(self):
        return self.offeror_organization

序列化程序:

class OrganizationSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Organization
        fields = ['offeror_organization']

    # I've tried both with and without a create function
    def create(self,validated_data): 
        organization_data = validated_data.pop('offeror_organization',None)
        if organization_data:
            organization = Organization.objects.get_or_create(**organization_data)[0]
            validated_data['offeror_organization'] = organization

views/api.py:

from webapp.models import Organization
from webapp.serializers import OrganizationSerializer

from rest_framework import viewsets

class OrganizationViewSet(viewsets.ModelViewSet):
    queryset = Organization.objects.all().order_by('offeror_organization')
    serializer_class = OrganizationSerializer

urls.py:

from django.urls import include,path
from rest_framework import routers
from . import views

router = routers.DefaultRouter()
router.register(r'organization',views.OrganizationViewSet)

urlpatterns = [
    ...
    path('api/',include(router.urls)),path('api-auth/',include('rest_framework.urls',namespace='rest_framework')),]

卷曲命令:

curl -X POST -H 'Content-Type: application/json' -d '{"offeror_organization":"Test2"}' 10.101.10.228:29000/webapp/apI/Organization/

settings.py 中间件:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.auth.middleware.RemoteUserMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','csp.middleware.CSPMiddleware','whitenoise.middleware.WhiteNoiseMiddleware'
]

settings.py REST_FRAMEWORK

# currently have all API authentication disabled while troubleshooting this issue
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [],'DEFAULT_PERMISSION_CLASSES': [],}

解决方法

就我而言,解决这个问题需要围绕几个不同的实现约束进行“机动”。

nginx + uWSGI Socket + Django REMOTE_USER 认证: 正如这篇文章的评论/聊天中提到的,我的 Django 应用程序前面有一个 nginx 代理和一个 uWSGI 应用程序服务器。由于我依赖于 REMOTE_USER Authentication,因此我的 uwsgi/nginx 配置必须使用 uWSGI 套接字(相对于 http),以便我可以将 REMOTE_USER 作为环境变量从 nginx 传递到 Django。当使用 http(与 nginx proxy_pass 耦合)时,虽然 proxy_pass 可以设置 headers 或 cookie,但那些似乎无法转换为 Django(需要环境变量)。

我认为在尝试 POST 到使用 uWSGI 套接字服务的 Django/DRF 应用程序时存在一些问题。根据 uWSGI Things to know (best practices)"TL/DR:如果您打算直接向公众公开 uWSGI,请使用 --http,如果您想将其代理到使用后端的 http 网络服务器后面,请使用 -- http-socket”。 就我而言,同时拥有 Web 应用程序和基于 DRF 的 API(我希望其他服务和系统与之通信),我需要两者!作为(希望是临时的)解决方法,我目前正在生成两个 uWSGI 进程 - 一个使用 --socket,另一个使用 --http(用于 API POST 调用)。如果您在使用 ---socket 时进行 POST,您可能会收到来自 DRF 的 Empty Response 错误。

顺便说一句,我最初看到使用 uwsgi_curl(来自 uwsgi_tools)通过 uWSGI 套接字进行 POST 的一些“承诺”(这导致了“field is required”错误(与空响应错误),但那是我开始遇到第二个问题的时候......

POST 嵌套应用程序/json 并同时上传文件: 帖子中引用的“组织”模型主要是概念验证,因为它是我的 Django 应用程序中最简单的模型。实际上,我需要使用嵌套序列化发布到更复杂的模型,因为该模型包含其他模型的外键。但这对 DRF 来说是完全可行的。 除了在我的情况下,我的模型属性之一是 FileUpload 字段。正如其他 SO 问题(如 this 一个)中所述,在尝试使用单个文件上传嵌套(即不是“平面”) 应用程序/json 时也存在一些问题要求。虽然我永远无法完全理解正在发生的问题(至少在我的情况下使用 drf_writable_nested.serializers.WritableNestedModelSerializer),但我通过编写自己的自定义序列化程序 (serializers.Serializer) 简化了手头的问题,这样我就可以避免嵌套的 JSON 对象(例如我的 POST 请求中的 { "offeror_organization": {"offeror_organization: "Test"}}。这解决了我的问题。

使用自定义序列化程序来缓解嵌套的 JSON + 文件上传问题,我敢打赌 uwsgi_curl POST 会起作用。尽管那时外部客户端系统/服务仅限于使用该 Python 包。无论如何,我会在尝试后更新我的答案。感谢@Michael 的评论并帮助我走上正确的“道路”。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。