dojo/request PUT method dosn't work - javascript

I have a web app using Python Django and Dojo framework.
I wanna send a PUT request from Dojo (using dojo/request) to server Django but when server receives a request, the data within are empty and validate Invalid.
BUT when I change method from PUT to POST, it's work correctly.
Here is my code:
_save: function(data){
var idForm = "editForm" + this.id;
var value = dijit.byId(idForm).get('value');
console.log(value);
request.put("/api/guestbook/"+this.bookName+"/greeting/"+this.id+"/", {
data: {
book_name: this.bookName,
message: value.message
},
headers: { "X-CSRFToken": _cookie('csrftoken') }
}).then(lang.hitch(this, function(text){
}));
},
And in Django:
def put(self, request, *args, **kwargs):
form = self.get_form(self.form_class)
logging.warning(form)
logging.warning(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID!!!")
Anyone can help me?
Thanks for help!

I found the way to receive PUT method below:
def put(self, request, *args, **kwargs):
request.PUT = QueryDict(request.body)
form = self.form_class(request.PUT)
if form.is_valid():
logging.warning("This form is VALID")
else:
logging.warning("This form is INVALID")
This is ok :)
Thanks all!

I'm guessing from your X-CSRFToken header that you are doing cross domain requests, i.e. CORS.
If you look in your browser's console, you'll probably see an OPTIONS request being sent to the server. This is called a "preflight request", and your server needs to respond with CORS headers telling the browser that it's okay to make the cross domain PUT request.
In your case, you want the server to respond with headers similar to:
Access-Control-Allow-Origin: http://your-site-hostname-and-port
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-CSRFToken
Simple POST requests do not need the preflight OPTIONS request, that's probably why it works. A pretty good tutorial on html5rocks here.

Related

Fetch API post data not receiving in Django view

What I am trying to do ?
I am trying to send a post request with data to a Django view using fetch API like this:
javascript:
const data = {
search_text: "",
months: 6,
property_type: "all"
};
const headers = {
'Accept': 'application/json',
'Content-Type':'application/json',
'X-Requested-With':'XMLHttpRequest'
}
fetch("some-url", {method: "POST", headers: headers, body: JSON.stringify(data)})
.then((response) => response.json())
.then((data) => console.log(data));
views.py:
class MyView(View):
def post(self, request, *args, **kwargs):
print("request: ", request.POST)
# do stuff with post data
urls.py:
re_path(r"^my_view/$", login_required(csrf_exempt(MyView.as_view())), name="my_view"),
Problem
When I try to access the post data in my Django view I get empty QueryDict and the output of the terminal is this:
request: <QueryDict: {}>
[06/Jan/2022 06:48:19] "POST /my_app/my_view/ HTTP/1.1" 200 114
Forbidden (CSRF token missing or incorrect.): /inbox/notifications/api/unread_list/
[06/Jan/2022 06:48:22] "{"search_text":"","months":"6","property_type":"all"}GET /inbox/notifications/api/unread_list/?max=5 HTTP/1.1" 403 12291
If you notice at the last line the post data seems to get added in the terminal why is that happening ? also why I get Forbidden (CSRF token missing or incorrect.) even when I am using csrf_exempt in the urls ?
I have tried looking it up and nothing seems to work. We are using react and I know axios can also be used but it should work with fetch API why isn't it working please help.
Edit:
Even after adding csrf token like mentioned in the docs and removing csrf_exempt from the urls I still get the same issue.
Okay fixed the issue it seems the data I was looking for was not in request.POST but instead in request.body did the following changes:
import json
class MyView(View):
def post(self, request, *args, **kwargs):
print("request: ", json.loads(request.body))
# do stuff with post data
request.body returns byte string so need to convert that to json with json.loads for more info read docs
This is because your view is protected by a CSRF-protection-middleware.
You have two possibilities:
Make the view exempt from this protection, see csrf_exempt
Add the CSRF token to your request (see answer from Yevgeniy Kosmak)

Django Rest Framework is detecting AnonymousUser on PUT requests

I have this viewset
class OrderItemViewSet(viewsets.ModelViewSet):
serializer_class = OrderItemSerializer
def get_queryset(self):
print('Current User', self.request.user, self.action)
return OrderItem.objects.filter(order__owner=self.request.user.profile)
take note of the print('Current User', self.request.user) I have used that to identify the root of the problem.
urls.py
router.register('order_items', shopping_api.OrderItemViewSet, 'order_items')
So far so good... But when I make a PUT request;
const response = await fetch(api.authurl+'/order_items/'+order_item.id+'/', {
method: 'PUT',
headers: api.httpHeaders,
body: JSON.stringify(order_item)
});
This error shows up
AttributeError: 'AnonymousUser' object has no attribute 'profile'
The print statement identifies these for a GET then a POST request respectively:
[19/Jun/2020 21:03:02] "GET /sellers/3/ HTTP/1.1" 200 196
Current User AD list
[19/Jun/2020 21:03:03] "GET /order_items/ HTTP/1.1" 200 1046
Current User AnonymousUser update
So I have reason to believe that when I make a get request, the authenticated user is detected, but with a PUT it's suddenly Anonymous. I doubt I have to make frontend authentication right? e.g having Authorization with a token in my headers in the request. Since I have that GET request doing fine.
EDIT:
adding SellerViewSet:
class SellerViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = Seller.objects.all()
serializer_class = SellerSerializer
DRF authentication scheme uses Django's default session backend for authentication, if you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as PUT, PATCH, POST or DELETE requests(DRF docs)
IsAuthenticated requires the both the request.user object and the user logged in(is_authenticated).
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
you need set header X-CSRFToken to request header for next request so that the server knows who you are
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
xhr.setRequestHeader("X-CSRFToken", csrftoken);
// fetch
headers:{
'X-CSRFToken': jQuery("input[name=csrfmiddlewaretoken]").val()
}
https://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication

How to respond to a GET request in tornado?

Just started learning HTTP, trying to make a simple client-to-server request to work in tornado. Here is my javascript function trigged by a button click:
function funcOnClick(){
$.ajax({
url: "http://localhost:8889/madTest",
type: "GET",
success: function(result){alert('success')},
error: function(error){console.log(error)}
})
}
And here is my server:
import tornado.ioloop
import tornado.web
import json
class MainHandler(tornado.web.RequestHandler):
def get(self):
print('got the GET request')
self.write('abc')
def make_app():
return tornado.web.Application([
(r"/madTest", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8889)
print('server started, listening to 8889 ...')
tornado.ioloop.IOLoop.current().start()
On clicking the button, I see "got the GET request" printed, so the server must have gotten the request. However, I got this error on console:
Any suggestions? Thanks!
The error message occurs when your JS or HTML page is served from a different domain and you're trying to make an AJAX request to a different domain. This is called CORS. For security reasons, web browsers restrict cross-domain AJAX requests unless allowed by the server.
To be able to make cross origin AJAX requests, you'll need to set a header called Access-Control-Allow-Origin in your handler's response.
You can do this in the prepare method of your handler:
class MainHandler(...):
def prepare(self):
self.set_header('Access-Control-Allow-Origin', '*')
# the wildcard - '*' - allows CORS from any domain
# you should probably change it to your frontend
# domain name if you wan to restrict CORS to a single domain.
# see Mozilla docs for more info

200 Jquery server request with no response

My goal is to print a string from a rendered html page.
I'm using the code below to fetch body content from a url:
var proxy = "http://myproxyname.pythonanywhere.com/response?userinput=google"
$.ajax({
url: proxy,
dataType: 'text',
success: function(data) {
$('#display').text(data);
}
})
}
I'm using this because the API i'm working with require Allow cross origin, actually, I setup a little flask app that do the job for me. I'm able to print html of some urls I tested with this function so it's working but for the one I'm using it's 200 OK but empty response.
Can someone explain why I'm not receiving the html content? Is there a special parameters with Jquery? Should I enable cross-origin in my flask app?
My last question is how to make the request but telling Javascript not to take into account headers?
Update:
When I make the request manually from the console I get a response but unable to print it on the page cause = other. When I click on the button to make the request it throw cause = JS and there's no response inside.
Update 2:
When I receive a valid response in the console, I only see this changes in request headers:
Pragma "no-cache"
Cache-Control "no-cache"
There's a way I can add it directly to the JS code?
Update 3:
My proxy code using Python (Flask):
#app.route('/response')
def response():
url = 'http://longstringurlapi.com'
data = str(request.args.get( "userinput" , None ))
jsoninput = json.dumps(data)
r = requests.post(url ,data=jsoninput)
response = r.text
return render_template('results.html', response=response, data=data)
#app.route('/')
def home():
return render_template('index.html')

POST json data to Bottle

I am a newbie to Bottle and sort of to Python as well and I am trying create an app whenever I click a button, an AJAX is fired and POST a json to server and store it using SQLite.
However, at current stage, I am trying to figure out how do I successfully received the data in the server.
On the client side,
I have the following send_data function written in JavaScript.
function send_data(feedback) {
$.ajax({
url: "/feedback",
type: "POST",
data: JSON.stringify(feedback),
contentType: "application/json",
success: function() {
alert("Feedback successfully stored in the server!");
},
error: function() {
alert("Feedback failed to store back in the server!");
},
}
The passed in parameter feedback looks something like {"id1": 1, "id2": 2}.
On the server side, I have a feedback.py file and the code is
from bottle import request, route, run
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Right now, I just want to check if I have received the data successful. But everytime, when I click that botton, I receive the following error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/feedback. This can be fixed by moving the resource to the same domain or enabling CORS.
OPTIONS http://localhost:8080/feedback [HTTP/1.0 405 Method Not Allowed 2ms]
I am not sure if it's because I am not using the element <form>. That botton is technically just an image. Every time I click that image, send_data() function is fired.
Anyone can help? I really appreciate it. Thank you!
Cross Origins Requests are restricted as a security measure by the browser. It is possible to overcome that by setting an Access-Control-Allow-Origin header. You can can use bottle-cors or create a decorator like the following on your server code (Python/bottle):
def enable_cors(fn):
def _enable_cors(*args, **kwargs):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
and then with your example:
from bottle import request, route, run
#enable_cors
#route('/feedback', method='POST')
def feedback():
comments = request.json
print comments
run(host='localhost', port=8080)
Note that it's best to allow specific origins instead of using *.
You can read more about Cross-Origin Resource Sharing (CORS) here
You can make this work by disabling the Cross-origin restrictions.
On safari, open the Develop panel, and check disable cross-origin restrictions, or use a browser like Firefox.

Categories