By Post request received data is None. Why it's possible - django

I have django app in it's views.py created for accepting, and saving objects from received data into database.
from .models import Hook
def hooktrack(request):
source=requests.POST.get("source")
b=Hook(dsourse=source).save()
Than I link this view to .urls.py
urlpatterns = [
path("hooktrack/",hooktrack),
]
My full url use http protockol not https
maybe it involved in my problem
I several times tested hooktrack view and it was accept and save received data.
curl -d "source=google" -X POST http://example.net/hooktrack/
After curling sent source=value accessible to query from dB.
from my.models import Hook
a=Hook.objects.all()
for item in a:
print(item.dsource)
...google
Than I linked my hooktrack view to production for accepting hooks from our business partner. After receiving them all of them saved to database but has None value
Updated
I inspected my Nginx logs and found that POST request and it is looking isn't as json
[05/Oct/2020:17:46:59 +0000] "POST /calltrackinghook/?dsource=google&dmedium=cpc&dcampaign=10393090041&dterm=+%D1%85%D0%BE%D0%BB%D0%BE%D0%B4%D0%B8%D0%BB%D1%8C%D0%BD%D0%B8%D0%BA%20+%D0%B1%D0%BE%D1%88_b&dcontent=gclid=CjwKCAjwiOv7BRBREiwAXHbv3O6RZTQ_CCIENfrX0FJqtKBFhPmhF6gZFjbewnG-P-UUnHQn_5n7ZhoCtmwQAvD_BwE&disposition=ANSWERED&virtual_number=8005337639&caller=9324034020&real_number=17612021180&uniqueid=1601920016.1303437&datetime=2020-10-05%2020:46:56&duration=0&recordlink=https%3A%2F%2Fcalltracking.ru%2FshareRecords%2F2020-10-05%2F1601920016.1303437.mp3&project_id=9892&source_id=&accountcode=&landing=https%3A%2F%2Fm.05.ru%2F&client_landing=&source_name=Google.Adwords&call_region=%D0%A5%D0%B0%D0%BD%D1%82%D1%8B-%D0%9C%D0%B0%D0%BD%D1%81%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9%20%D0%90%D0%9E&referrer=http%3A%2F%2Fwww.google.com%2F&cid

POST parameters available when you submit data in the application/x-www-form-urlencoded format (e.g., using a HTML form). So request 'Content-Type' must be application/x-www-form-urlencoded or multipart/form-data.
If data send as JSON, you can access your JSON data as follows:
import json
def hooktrack(request):
data = json.loads(request.body)
# Data is now a python dict, e.g.,
Maybe also interesting for you, csrf_exempt decorator.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def hooktrack(request):
source=requests.POST.get("source")
b=Hook(dsourse=source).save()
...

Related

Django Rest Framework: How to send data to request.data

Im building a simple api in Django Rest Framework using class based views and the documentation mentions request.data (https://www.django-rest-framework.org/tutorial/2-requests-and-responses/)
from rest_framework.views import APIView
class myView(APIView):
def post(self, request):
print(request.data)
When I try to send post requests either with
curl: curl --data param1=val1&param2=val2 url
djangos browser interface with post (using formatted url and the post option
Advanced Rest Client (chrome add on)
The data of all three appears to end up in request.query_params.
When I try to print request.data, however I get an empty response {}
I could just use request.query_params, Im just curious as to how one would get data to go to request.data since it is talked about in the documentation
edit: so curl --data param1=val1&param2=val2 -X POST url sends information to request.data (now if I say request.query_params if get the empty dict {} but request.data contains an object that is the dict query_params.)
curl request doesn't have the -X and POST added.
Add these

How to print post request data in django

In PHP when I send post request data from template form to controller I can use print_r($data) to print form send data for debugging purpose but in Django how can I print post request form data in view.py
If you get your form data like PHP you may use
from django.http import HttpResponse
return HttpResponse(request.POST.items())
And for more debuging follow this Link

How does interacting with the django rest api through the url work?

I get that the Django rest framework is for interacting with the Django server programmatically but one thing I still don't understand is how.what i want to do is have my client app (mobile app) send data (somehow) to the Django server in order to create/retrieve data based on variables and obviously this has to be done through the URL since there will be no direct GUI interaction with the API. (unless I'm mistaken, which I probably am) I have gone through the official documentation and followed the tutorial to the end and still don't understand how this is supposed to work.all I ask for is a quick and simple explanation because I have searched everywhere and haven't found a simple enough explanation to grasp the core concept of how this is all supposed to work.
I think what you're looking for is JSONResponse and related objects:
This will allow you to send JSON in response to a request.
from django.http import JsonResponse
def my_view_json(request):
response = JsonResponse({'foo': 'bar'})
return response
If your templates or webpages need to make a request to a view and specify different parameters, they can do so by adding POST variables (examples). These can be parsed in the view like so:
def myView(request):
my_post_var = request.POST.get('variable_name', 'default_value')
my_get_var = request.GET.get('variable_name', 'default_value')
You can then parse what was sent any way you like and decide what you want to do with it.
Basically,
You define the URLS upon which you perform Get/POST/PUT Requests and You can Send Data to that.
Eg:
urls.py
from django.conf.urls import url,include
from app import views
urlpatterns = [
url(r'^(?i)customertype/$',views.CustomerViewSet.as_view()),
url(r'^(?i)profile/$', views.Save_Customer_Profile.as_view()),
url(r'^(?i)customer_image/$', views.Save_Customer_Image.as_view()),
]
Now Whenever User would send a Request to:
example.com/profile ==> This would be received in the Save_Customer_Profile View based on the Method Type, Save_Customer_Profile is as follows:
class Save_Customer_Profile(APIView):
"""Saves and Updates User Profile!"""
def get(self, request, format=None):
return AllImports.Response({"Request":"Method Type is GET Request"})
def post(self, request, format=None):
return AllImports.Response({"Request":"Method Type is Post Request"})
def put(self,request, format=None):
return AllImports.Response({"Request":"Method Type is Put Request"})
I think the OP was referring to how to do GET/POST request programmatically. In that case, it is enough to do (values are dummy):
GET:
import requests
r = requests.get('http://localhost:8000/snippets/')
print(r.json())
print(r.status_code, r.reason)
POST:
data = {'code': 'print(" HELLO !!!")', 'language': 'java','owner': 'testuser'}
r = requests.post('http://localhost:8000/snippets/', data=data, auth=('testuser', 'test'))

Secure way to POST to Django from a trusted external (Node-RED) server?

What I want
I have a Node-RED instance on one server doing real-time analysis of a data stream. I want it to securely notify a Django app on a different server of any actionable findings.
[Edit: I bundle findings to rate-limit requests to 1/second, but any solution needs to be performant enough to not slow it further than that.]
Problem
By default Django protects against cross-site request forgeries by requiring "unsafe" requests (like POST) to contain a CSRF token/secret that Django provides (as a cookie? rendered into the page?) when rendering an HTML form containing the {% csrf_token %} template tag or a view decorated with csrf_protect.
The above seems like it will only allow POSTS starting from pages that the Django app itself served (that's probably the point). My Node-RED instance is not requesting a page from Django to start with, so it has no token/secret to include in a POST.
Approaches considered so far:
Use GET requests instead
The requests Node-RED would be sending will cause side-effects in Django, and I don't want a third party sending bogus requests and making Django do somersaults for no reason.
Remove check using Django's csrf_exempt decorator
See above.
[Edit 2: Think I'll actually go with this option, since 1) both the Node-RED and Django servers are on an internal network that's inaccessible from the outside web and 2) looking more closely, it seems that the actions my requests are supposed to trigger are already accessible in views that are csrf_exempt.]
Use HTTP basic authentication
The Node-RED http request node has an option to set a username/password to be sent in (I think) the WWW-Authenticate header and I found this decorator to map basic auth to django auth.
By default, though, basic auth is sent in plaintext, which is bad. The http request node does also have an option to enable SSL/TLS and specify certs, private keys, etc., but unfortunately the Django site does not use HTTPS (I hate this, but it's not a priority for my employers atm).
Trust POSTs from [Node-RED hostname]
I'm not sure what the best way is to do this. To my knowledge, there is no guaranteed way to determine client hostname from a request. You can get IP, but my Node-RED server uses DHCP so its IP isn't static. Something like this might work:
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from socket import gethostbyaddr
#csrf_exempt
def my_view(request):
# retrieve the client IP from the request
# use gethostbyaddr to do a DNS lookup on the IP and get a hostname
# if hostname matches [Node-RED hostname]:
# process the body of the request
return HttpResponse(status=200)
# else:
return HttpResponse(status=403)
I feel like this isn't airtight; my understanding of networking is weak, but if the Node-RED server loses its DHCP lease because it's rebooting or the network is under heavy load or something, an attacker could get a lease for that hostname and send malicious requests.
If the client hostname is unreliable and the client IP is dynamic, putting some kind of custom secret in the request headers could be useful, but only if it's encrypted - otherwise it's trivial to copy. I don't know what decent approach to doing that would be.
Are any of these approaches close to a good solution? Is there something built in somewhere for this situation?
To use django API, you may consider using Django REST framework as it will allow you to perfom HTTP requests without any CSRF token.
For example, create an endpoint with the Views Tutorial and use the AllowAny Permission:
views.py
from django.contrib.auth.models import User
from rest_framework import serializers
from rest_framework import viewsets
from rest_framework import permissions
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'groups']
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [permissions.AllowAny] # or permissions.IsAuthenticated
urls.py
from django.urls import include, path
from rest_framework import routers
from tutorial.quickstart import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Then run manage.py runserver and perform a GET or POST request:
POST /users/ {"username": "test"} -> 201 Created
GET /users/ -> 200 OK

HTTP post request in Django

I am trying to do the following:
1) A payment solution is supposed to send an HTTP Post to my site
2) I would like to read the contents of the request(xml) and update my records to reflect the payment
I am trying this for the first time. When I create a URL path, and send a post to that address I get the csrf error.
Is there a way using Django wherein I can accept a post and don't have to return a response.
Thanks
Tanmay
Your view should return an http response, otherwise you will get an error. However, Django does not mind if that response does not contain any content. Your view can be as simple as:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def my_view(request):
# do something with request.POST
return HttpResponse("")
Since it is a third party that is submitting the post request, and not a user submitting a form on your site, you can mark the view as exempt from CSRF protection using the csrf_exempt decorator, as above.
Note that anyone could submit a post request to your url, so you should have some way of checking that the response is genuine. Your payment solution should be able to advise a suitable way to do this.