无法从 Django request.POST 获取 POST 数据

Posted

技术标签:

【中文标题】无法从 Django request.POST 获取 POST 数据【英文标题】:Cannot get POST data from Django request.POST 【发布时间】:2022-01-08 07:59:12 【问题描述】:

我正在尝试验证所需数据是否包含在 POST 请求中。我有一个django 后端和一个vue3 前端。

这是我的 Django 视图:

views.py

# Sign user in and issue token
@require_http_methods(['POST'])
def login(request: HttpRequest):
    if request.method == 'POST':
        # check that required fields were send with POST
        print(request.body)
        if 'username', 'password' >= set(request.POST):  # <- evaluates as False
            print('missing required fields. INCLUDED: ' + str(request.POST))
            return JsonResponse(
                data='message': 'Please provide all required fields.',
                content_type='application/json',
                status=400)
        # check that username exists and password matches
        if (User.objects.filter(username=request.POST['username']).count() >
                0):
            user = User.objects.get(username=request.POST['username'])
            if user.password == request.POST['password']:
                # Delete previously issued tokens
                Token.objects.filter(user_id=user.id).delete()
                token = Token(user_id=user.id)
                token.save()
                return JsonResponse(data='userToken': token.to_json(),
                                    content_type='application/json',
                                    status=200)
        else:
            return JsonResponse(
                data='message': 'Incorrect username or password.',
                content_type='application/json',
                status=400)
    else:
        return HttpResponseNotAllowed(permitted_methods=['POST'])

还有我的 axios 请求

Login.vue

axios
  .post('http://localhost:8000/api/users/login', 
    'username': form.get('username'),
    'password': form.get('password'),
  , 
    validateStatus: (status) => 
      return status !== 500
    ,
  )
  .then((response) => 
    console.log(response.data)
    if (response.data.success) 
      // Commit token value to store
      store.commit('setToken', response.data.token)
 
      // Request user data ...

     else 
      alert.message = response.data.message
      alert.type = 'error'
      document.querySelector('#alert')?.scrollIntoView()
    
  )

我可以看到usernamepassword 设置在request.body 但不是request.POST,如django 日志所示。

December 01, 2021 - 17:40:29
Django version 3.2.9, using settings 'webserver.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
b'"username":"site.admin","password":"password"'
missing required fields. INCLUDED: <QueryDict: >
Bad Request: /api/users/login
[01/Dec/2021 17:40:30] "POST /api/users/login HTTP/1.1" 400 50
/Users/colby/Projects/emotions/backend/webserver/users/views.py changed, reloading.
Watching for file changes with StatReloader
Performing system checks...

我做错了什么?

编辑

这是从 axios 请求中设置的标头


  'Content-Length': '47',
  'Content-Type': 'application/json',
  'Host': 'localhost:8000',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0',
  'Accept': 'application/json,
   text/plain, */*',
  'Accept-Language': 'en-US,en;q=0.5',
  'Accept-Encoding': 'gzip, deflate',
  'Origin': 'http://localhost:8080',
  'Dnt': '1',
  'Connection': 'keep-alive',
  'Referer': 'http://localhost:8080/',
  'Sec-Fetch-Dest': 'empty',
  'Sec-Fetch-Mode': 'cors',
  'Sec-Fetch-Site': 'cross-site',
  'Sec-Gpc': '1'

编辑 2

我可以通过将 Content-Type 标头显式设置为 multipart/form-data 来解决此问题。

axios
  .post('http://localhost:8000/api/users/login', formData, 
  
     validateStatus: (status) => 
     return status !== 500
  ,
  headers: 
    'Content-Type': 'multipart/form-data',
  
).then(...)

我还必须将 django 视图中的 if 语句调整为

if 'username' not in request.POST or 'password' not in request.POST:
  ...

【问题讨论】:

【参考方案1】:

我怀疑 Axios 自动设置了 content-type: application/json 标头,这意味着请求正文不包含 Django 可以理解的 HTTP POST 参数。

您可以通过打印request.headers 来验证这一点,如果这确实是问题,请通过以下任一方式解决:

    从 JSON 解析请求正文:
import json
data = json.loads(response.body.decode())
if 'username', 'password' >= set(data):  # etc.
    将数据作为表单数据客户端发送:
var formData = new FormData();
formData.append("username", form.get("username"))
formData.append("password", form.get("password"))
axios
  .post('http://localhost:8000/api/users/login',
    formData,
    headers: 'Content-Type': 'multipart/form-data'
  )

我个人推荐解决方案 1,因为我发现它不那么冗长且更易于维护,但这主要取决于您的偏好和要求 :)

【讨论】:

感谢您的建议!我用请求标头编辑了帖子。您对添加的内容类型标头是正确的。当我尝试使用解决方案 1 并通过 FormData 时,我仍然遇到同样的问题。 我想我弄错了,应该是我formData.append而不是formData.set,你能试试吗? 我能够通过显式设置内容类型标头并将if 语句更改为:if 'username' not in request.POST or 'password' not in request.POST: 来更正此问题。我将接受您的回答并在原帖中发布最终代码。

以上是关于无法从 Django request.POST 获取 POST 数据的主要内容,如果未能解决你的问题,请参考以下文章

Django 无法通过request.POST.get()获取数据的问题

Django request.POST 从输入中获取数据

Django:如何在删除视图中使用 request.POST

只有 Django request.body 包含数据(不是 request.POST)

数据访问:Django 表单与 request.POST 方法 [关闭]

Django save request.POST to JSONField 从列表中选择最后一项而不是保存列表