Search code examples
pythondjangodebuggingposthttpie

(Django) Http POST request keeps returning bad request. I ran out of ideas regarding how to debug this


I have been trying to emulate Instagram login which takes either one of 'username', 'fullname', or 'email'.

Below are the files for my 'account' Django app that I created:

account/urls.py

from django.urls    import path
from .views         import SignInView, SignUpView

urlpatterns = [
        path('signup', SignUpView.as_view()),
        path('signin', SignInView.as_view()),
]

account/models.py

from django.db import models

class Account(models.Model):
    email       = models.CharField(max_length=200)
    password    = models.CharField(max_length=700)
    fullname    = models.CharField(max_length=200)
    username    = models.CharField(max_length=200)
    created_at  = models.DateTimeField(auto_now_add=True)
    updated_at  = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'accounts'

account/views.py

import json
import bcrypt
import jwt

from django.views       import View
from django.http        import HttpResponse, JsonResponse
from django.db.models   import Q

from .models    import Account

class SignUpView(View):
    def post(self, request):
        data = json.loads(request.body)
        try:
            if Account.objects.filter(email=data['email']).exists():
                return JsonResponse({"message": "ALREADY EXIST"}, status=409)

            hashed_pw = bcrypt.hashpw(data['password'].encode('utf-8'),bcrypt.gensalt()).decode()
            Account.objects.create(
                    email       = data['email'],
                    password    = hashed_pw,
                    fullname    = data['fullname'],
                    username    = data['username'],

            )
            return JsonResponse({"message": "SUCCESS"}, status=200)

        except KeyError:
            return JsonResponse({"message": "INVALID_KEYS"}, status=400)

class SignInView(View):
    def post(self, request):
        data = json.loads(request.body)

        try:
            if Account.objects.filter(Q(email=data['email']) | Q(username=data['username']) | Q(fullname=data['fullname'])).exists():
                account = Account.objects.get(Q(email=data['email']) | Q(username=data['username']) | Q(fullname=data['fullname']))

                encoded_pw = account.password.encode('utf-8')
                encoded_input = data['password'].encode('utf-8')
                if bcrypt.checkpw(encoded_input, encoded_pw):
                    token = jwt.encode({ 'email' : account.email }, 'secret', algorithm='HS256').decode('utf-8')
                    return JsonResponse({ 'access_token' : token }, status=200)
                return HttpResponse(status=403)

            return HttpResponse(status=402)

        except KeyError:
            return JsonResponse({"message": "INVALID_KEYS"}, status=400)

And I have been using Httpie to send Post request like so:

http -v http://127.0.0.1:8000/account/signin username='aaron' password='1234'

But the bad request keeps turning up like so:

Bad Request: /account/signin
[19/May/2020 22:20:33] "POST /account/signin HTTP/1.1" 400 27

I have already been successful in terms of Signing Up. I created an account using a POST request via Httpie (username=aaron fullname=Aaron password=1234 [email protected]). However, I have been struggling to find out what is wrong with the Sign In function.

How do I go about debugging this other than aggerssively using pdb and print()? When the Bad Request message shows up on the terminal, I can't even use the pdb's p method.


Solution

  • I guess the problem is in this line:

    if Account.objects.filter(Q(email=data['email']) | Q(username=data['username']) | Q(fullname=data['fullname'])).exists():

    This is a problem, because unless email, username and fullname are present in data it allways throws a KeyError which is catched by you and returns a 400 = BadRequest

    You should use the get(key,default=None) method on the data.

    And then you will need some logic to combine the Q objects only if the key is there.