How to receive POST data in django - django

I've been trying to integrate a payment gateway into my site in django.
I'm having trouble getting the response data from the payment gateway.
The payment gateway has sample docs for php which looks like this :
$ErrorTx = isset($_POST['Error']) ? $_POST['Error'] : ''; //Error Number
$ErrorResult = isset($_POST['ErrorText']) ? $_POST['ErrorText'] : ''; //Error message
$payID = isset($_POST['paymentid']) ? $_POST['paymentid'] : ''; //Payment Id
In the view for the url that the payment gateway is redirecting to after entering card details etc, I'm checking if it's a GET if request.method == "GET" and then passing the request to a function. When I debug the request, I can see an empty query dict. and if I try something like res = request.GET['paymentid'] I get an error that says there's no key called paymentid.
Am I missing something obvious? I'm still pretty new to django, so I'm sure I'm doing something wrong.

res = request.GET['paymentid'] will raise a KeyError if paymentid is not in the GET data.
Your sample php code checks to see if paymentid is in the POST data, and sets $payID to '' otherwise:
$payID = isset($_POST['paymentid']) ? $_POST['paymentid'] : ''
The equivalent in python is to use the get() method with a default argument:
payment_id = request.POST.get('payment_id', '')
while debugging, this is what I see in the response.GET: <QueryDict: {}>, request.POST: <QueryDict: {}>
It looks as if the problem is not accessing the POST data, but that there is no POST data. How are you are debugging? Are you using your browser, or is it the payment gateway accessing your page? It would be helpful if you shared your view.
Once you are managing to submit some post data to your page, it shouldn't be too tricky to convert the sample php to python.

You should have access to the POST dictionary on the request object.

for class based views, try this:
class YourApiView(generics.ListAPIView):
"""
API endpoint
"""
def post(self, request, *args, **kwargs):
print("request data")
print(request.data)

Related

Django - RawPostDataException: You cannot access body after reading from request's data stream

I'm really stuck at this problem for a couple of days now.
While I understand, what's happening here, I don't really know the best workaround/solution for this.
Problem:
I'm trying to create a user login endpoint using Django and DRF in general.
My login API needs to support a login via password as well as login via OTP.
My LoginView looks like:
def post(self, request, **kwargs):
"""
post
Method to handle user login
:param request:
:param args:
:param kwargs:
:return:
"""
request_data = request.data
login_using_password = request_data.get('login-with-password') is True
login_using_otp = request_data.get('login-with-otp') is True
if request_data is not None:
if all((login_using_password, login_using_otp)):
raise accounts_exceptions.InvalidLoginRequestError()
if login_using_password:
return Response(self._login_with_password(request))
elif login_using_otp:
return Response(self._login_with_otp(request))
raise accounts_exceptions.InvalidLoginRequestError()
return Response(self._login_with_password(request))
Also my _login_with_password looks like:
def _login_with_password(self, request, **kwargs):
"""
_login_with_password
A utility method to handle login with password
:param request:
:return:
"""
return getattr(ObtainJSONWebToken.as_view()(request=request._request, ), 'data')
When I try to login, Django complains saying RawPostDataException You cannot access body after reading from request's data stream
I'm using JWT to authenticate requests. ObtainJSONWebToken is a view provided by DRF-JWT to obtain access tokens to authenticate requests.
What is the workaround/solution for this?
Is there a better way to support such a login requirement?
Thanks in advance!
Resolved this.
There's no concrete way to solve the problem above.
Django disallows access to request.data multiple times.
It could be done only once for the entire request lifetime.
So, this left me with two solutions:
Move my request payload to query params.
Move my request payload to url context.
I ended up using a mix and match of both.
So, basically I used request.query_params and self.context to fetch data from the request and changed my URL and request structure accordingly.

How to make Django 2.1 to accept PATCH/DELETE requests

I am building an app with Django 2.1 and I want to be able to do PATCH/DELETE requests through ajax calls. Through researching about this I found out the solution to be to deceive the browser by using a POST request, but setting the header X_METHODOVERRIDE to the desired method.
I would start doing this by creating a middleware that will take care of this. What is the best way of doing?
Please note that I don't want to use Django-REST
Code so far for making the DELETE request:
view.py
class CategoryManageView(StaffRequiredMixin, View):
model = Category
response_dict = {'status': False, 'text': '', 'data': {}}
def delete(self, request, *args, **kwargs):
cat = get_object_or_404(Category, request.POST['id'])
self.response_dict['data'] = cat
cat.delete()
self.response_dict['status'] = True
self.response_dict['text'] = 'Category deleted successfuly'
return JsonResponse(self.response_dict)
If the ajax call method is set to DELETE instead of POST or GET I get error in console:
DELETE http://127.0.0.1:8000/dashboard/admin/categories/manage 403 (Forbidden)
The error code 403 indicates that this is because of CSRF protection. As the CSRF documentation shows, PUT and DELETE - as well as POST - are considered "unsafe" methods, and Django therefore disallows the requests if they don't have a valid CSRF token.
The same page has documentation on how to enable the token in your Ajax requests. Alternatively - although this is strongly discouraged - you can use the #csrf_exempt decorator on the view to disable the protection.

Django: call REST API through a view instead of Postman

I have a working python code on my desktop that prints and makes PDFs perfectly. All I want to do is use that code and use Django to allow users to enter a value.
My code uses docusign API to call data. I use postman which needs a key and other parameters to use the API. The value entered by my user will determine what data they get.
What I think I have to do is rewrite my code, put it somewhere, then turn it into a view. The view will be sent to template.
Edit -
My code:
# Get Envelope Data- use account ID from above
# Get Todays Date, Daily Setting
day = datetime.datetime.today().strftime('%Y-%m-%d')
url = "https://demo.docusign.net/restapi/v2/accounts/" + accountId + "/envelopes"
# if Envelope is completed
querystring = {"from_date": Date, "status": "completed"}
headers = {
'X-DocuSign-Authentication': "{\"Username\":\""+ email +"\",\"Password\":\""+Password+"\",\"IntegratorKey\": \""+IntegratorKey+"\"}",
'Content-Type': "application/json",
'Cache-Control': "no-cache",
'Postman-Token': "e53ceaba-512d-467b-9f95-1b89f6f65211"
}
response = requests.request("GET", url, headers=headers, params=querystring)
envelopes = response.text
Sorry, let me try again. I currently have a python3 program on my desktop. I run it with idle and everything is how I want it.
What I want to do with Django is use this code to print its outputs on a webpage and have the user download it’s additional csv file output. I have managed to make a Django localhost and I am stuck at that point. I do not know how to use my python3 code to run to webpage.
The code is made up of API calls, I use postman to help me with sending the right parameters. I will add a picture of code. All I want is for user to enter value such as accountID so that the API can complete the request and give them data for their own request.
I'll try to give you a overview of how this could work with Django.
You could have a form to obtain the users account_id.
class AccountForm(forms.Form):
account_id = forms.IntegerField()
You could display this form through a generic FormView (see also this):
class AccountView(views.FormView):
form_class = AccountForm
template_name = 'account.html'
def form_valid(self, form):
# here you make your request to the external API
account_id = form.cleaned_data['account_id']
url = "https://demo.docusign.net/restapi/v2/accounts/" + account_id + "/envelopes"
headers = ...
querystring = ...
resp = requests.request("GET", url, headers=headers, params=querystring)
ctx = {
'result': resp.text,
}
return render(self.request, 'result.html', ctx)
I don't show the template account.html here. You will have to figure that one out yourself; the links I provided should point you in the right direction.
Now, what remains to be determined is what exactly the method form_valid should return. The code I showed renders a template with the API call response in the context, so in your template result.html you could display the result data any way you like.
You mentioned downloading a CSV file as well. That could be a different view, probably triggered by a link or button in result.html.

How to parse request in django

Hi i am making an webserver , In which I have to hit some request from html page and return the response. The URL which is generated using html is
http://192.168.2.253:8080/searchSMS/?KPImsgId=0&circle=&subId=&startDate=DD-MM-YYYY&endDate=DD-MM-YYYY&Username=ashish
but in the server side I am not able to see the request data. I am using
q = QueryDict(request.body) but it is showing <QueryDict: {}>
How to find the all the parameters coming in request.
In your case you send the data in url so access the data through request.GET as follow:
username = request.GET.get('Username')
start_date = request.GET.get('startDate')
# ... the same for all the other parameter after the `?` marque.
In fact there is a difference between request data, request.body, request.GET and request.POST:
If you are sending POST request to django function view or class based view: you access the request data in request.body or request.POST.
If you are sending POST request to Django REST Framework: you access the data in request.data. You may also find in Internet request.DATA that correct but it's deprecated in the newer version of DRF in favor of request.data.
If you send parameter in the url like in you case, you access the data form request.GET as explained above.

request.POST.get() always returning None

I am completely new to django , you can I just started it today
when I am making a POST request with parameters using postman , I am always getting None for email,password, name and other variables
#csrf_exempt
def signup(request):
if request.method != 'POST':
raise Http404
email = request.POST.get('email')
password = request.POST.get('password')
name = request.POST.get('name')
os = request.POST.get('os')
device_id = request.POST.get('device_id')
version = request.POST.get('version')
device = request.POST.get('device')
print "email value is = %s", email
user=AppUser.objects.get_or_create(email=password,password=password)
user.save()
return HttpResponse(json.dumps({"result": True}), content_type='application/json')
Please help , Why it is always showing None even though I am passing values from POST request for email and for other parameters
Below is the body request from post man using POST
http://127.0.0.1:8000/v1.0/signup/?email=nagu#nagu.com&password=nagendra&name=nagendra&os=android&device_id=12345678&version=23.0.1&device=samsung
below postman screen shot
The parameters you added to the url are GET parameters not POST parameters. POST parameters are in the request body and not visible through urls. Even you specify your request method is POST with your original url, you are not going to send any data.
If you in your commandline do something like:
curl --data "email=nagu#nagu.com&password=nagendra&name=nagendra&os=android&device_id=12345678&version=23.0.1&device=samsung" http://127.0.0.1:8000/v1.0/signup/
It should send POST data to your view.
Take a look at this SO question and answer on how POST requests are delivered.
I have tried postman in chrome.
Below is the screenshot.
Does this work for you?
please make sure your parameter of body in postman is correct, it
should be "x-www-form-urlencoded".
THKS!
check your header
you probably may have
Content-type set to application/json