如何解决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 帖子(例如 this 和 this),但似乎没有一个解决方案适合我。
型号:
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 举报,一经查实,本站将立刻删除。