Home > OS >  Cannot get POST data from Django request.POST
Cannot get POST data from Django request.POST

Time:12-02

I'm trying to verify that the required data was included in a POST request. I have a django backend and a vue3 frontend.

Here is my django view:

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'])

And my axios request

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()
    }
  })

I can see that username and password are set in request.body but not request.POST as shown in the django log.

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...

What am I doing incorrectly?

Edit

Here are the headers set from the axios request

{
  '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'
}

Edit 2

I was able to correct this issue by explicitly setting the Content-Type header to multipart/form-data.

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

I also had to adjust the if statement in the django view to

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

CodePudding user response:

I suspect Axios is setting automatically a content-type: application/json header which means that the request body doesn't contain HTTP POST parameters that can be understood by Django.

You can verify this by printing request.headers, and, if this is indeed the issue, solve it by either:

  1. Parsing the request body from JSON:
import json
data = json.loads(response.body.decode())
if {'username', 'password'} >= set(data):  # etc.
  1. Send the data as form data client-side:
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'}
  })

I'd personally recommand solution 1 because I find it less verbose and easier to maintain, but that mostly depends on your preferences and requirements :)

  • Related