I’m new to ViewSets and am trying to get the values sent from the front-end fetch method to Django’s request object in the create function. I don’t know whether it’s just a simple syntax error or whether the data isn’t being sent properly from the front-end, but I think it’s a back-end issue.
The stringified data in the post method seems to log correctly at the front-end like with this test:
{"title":"test","type":"landing","slug":"","notes":""}
Printing variables in the ViewSet’s create function however shows these:
print(request.POST["title"]) # fails with keyerror: 'title' MultiValueDictKeyError(key) django.utils.datastructures.MultiValueDictKeyError: 'title'
print(request["title"]) # fails with TypeError: 'Request' object is not subscriptable
print(request.POST.get("title", “test”)) # fails as print test
print(request.POST.get("title")) # fails as it just returns None
print(request.get("title")) # fails with AttributeError: 'WSGIRequest' object has no attribute 'get'
print(self.request.query_params.get("title", None)) # prints None
print(self.request.query_params) # prints empty QueryDict: <QueryDict: {}>
Here’s the create function:
class PagesViewSet(viewsets.ViewSet):
def create(self, request):
# printing went here
page = Page.objects.create(
title="testing", type="other", slug="test-slug", notes="test notes"
)
serializer = PageSerializer(page)
return Response(serializer.data)
I’ve just chucked in demo data inside the page create method to ensure it works, which it does, and now want to use the real data which should be in the request.
Does anyone know what might be the issue here?
For visibility, here’s the front-end API-request function:
const createPage = async (data: CreatePageFormInputs) => {
console.log('stringified: ', JSON.stringify(data)); // logs correctly
const res = await fetchCreatePage('http://localhost:8000/api/pages/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
};
Maybe irrelevant but in case you're wondering what fetchCreatePage is, it's just this part of a custom react hook:
const fetchCreatePage: FetchDataFn = async (url, options?) => {
const setFailed = () => {
setFetchError(true);
setLoading(false);
};
const setSuccess = (data: any) => {
setData(data);
setLoading(false);
};
try {
setLoading(true);
const res = await fetch(url, options);
if (!res.ok) {
console.log('Error detected. Returning...');
setFailed();
return;
}
if (res.status === 204) {
setSuccess({
success: true,
info: 'Item successfully deleted',
});
return;
}
const data = await res.json();
setSuccess(data);
} catch (e) {
setFailed();
}
}
I assume the POST method is correct. Any help would be appreciated, thanks.
You wrote the data as body of the request in a JSON format. You thus should decode the JSON format to a dictionary with:
import json
data = json.loads(request.body)
print(data['title'])
If you are using a request from the Django REST framework, you work with request.data:
import json
print(request.data['title'])
request.data will look for POST parameters and a JSON body.
Related
I want to pass a number off variables (either as a JSON or Array) via an API, such as:
{'age': 35, 'gender':'female', ...etc}
I am not sure how to pass this information into the Djano URL. I could set up individual parameters in the URL, but I got quite a few to pass. there must be an easier way of doing it
SOLUTION:
Solved by switching of a POST Call in the API and setting up the serializers for each variable so that they can be passed through the request.
I am using axios to make calls from django backend. In my case I can do:
js.file:
function search(token, status, q) {
return (dispatch) => {
dispatch(start(token));
axios
.get(`${serverIP}/invoices/sales-invoice/`, {
params: {
status: status,
q: q,
},
})
.then((res) => {
dispatch(successSearch(res.data, status));
})
.catch((err) => {
dispatch(fail(err));
});
};
}
Here I am sending 2 params, but you can actually send object, for example user info.
And than in views get them
views.py:
def list(self, request, *args, **kwargs):
status = request.query_params.get('status')
q= request.query_params.get('q')
These is exapmple with DRF model viewset
How to access GET request data in django rest framework. In the docs, they have mentioned "For clarity inside your code, we recommend using request.query_params instead of the Django's standard request.GET"
https://www.django-rest-framework.org/api-guide/requests/
But when I use request.query_params.get('some_vaue') it gives me none even though I pass the data in the request body.
sample code example:
class TestView(APIView):
def get(self, request):
test = request.query_params.get('test')
print('data',test)
...
...
...
When I pass some value in the body of the request in postman and print the value, it actually prints None.
Update
Below is my axios code
axios.get(API_URL, {
headers: {
'Content-Type': 'application/json'
},
params: {
page_num: 1,
test: 'test data'
}
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.response.data);
});
Re-Update:
For testing purpose I printed out the request object like
print(request.__dict__)
so it printed out
{'_request': <WSGIRequest: GET '/api/my api url/?page_num=1&test=test+data'>, 'parsers': [<rest_framework.parsers.JSONParser object at 0x0000016742098128>, <rest_framework.parsers.FormParser object at 0x00000167420980B8>, <rest_framework.parsers.MultiPartParser object at 0x00000167420980F0>], 'authenticators': (), 'negotiator': <rest_framework.negotiation.DefaultContentNegotiation object at 0x0000016742098080>, 'parser_context': {'view': <app_name.views.APIClassName object at 0x0000016742280400>, 'args': (), 'kwargs': {}, 'request': <rest_framework.request.Request object at 0x0000016742107080>, 'encoding': 'utf-8'}, '_data': {}, '_files': <MultiValueDict: {}>, '_full_data': {}, '_content_type': <class 'rest_framework.request.Empty'>, '_stream': None, 'accepted_renderer': <rest_framework.renderers.JSONRenderer object at 0x00000167421070B8>, 'accepted_media_type': 'application/json', 'version': None, 'versioning_scheme': None, '_authenticator': None, '_user': <django.contrib.auth.models.AnonymousUser object at 0x0000016741FFAC88>, '_auth': None}
I could see that it is passing the data but not sure why if i do request.data['page_num'] or any other value it doesn't get the data.
If you are using class based views :
POST provides data in request.data and GET in request.query_params
If you are using function based views:
request.data will do the work for both methods.
axios does not support sending params as body with get method , it will append params in url. so if you are using axios you will have to use query_params
Axios example code:
axios.get(API_URL, {
params: {
testData: 'test data',
pageNum: 1
}
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.response.data);
});
DRF example code:
Class TestView(APIView):
def get(self, request):
test_data_var = request.query_params['testData']
page_num_var = request.query_params['pageNum']
Note:
If you're testing it in postman then put the get request query params in Params tab.
For me the accepted answer did not work.
A much simplier solution I saw no one mention is the following :
Append them to the URL like this : yourApi.com/subdomain/?parameter1=something
Axios.js
const target = "someApiYouWantToFetch.com"
let parameter = "DataYouWantToSend"
axios.get(`${target}?parameter=${parameter }`)
views.py
def get(self,request,*args,**kwargs): #or def list()
data = request.GET.get('name')
In DRF if you want to access request.GET you should use request.request.GET
for example
#action(methods=['GET',], detail=False)
def activation(request, *args, **kwargs):
uid = request.request.GET.get('uid')
token = request.request.GET.get('token')
Have been trying to filter data using django-filters. The code is working when I send a separate POST or GET request from the template. I want to avoid that extra reload that's taking place to filter the table of information.
Here's the view:
def search(request):
dynamic_filter = [f.name for f in Controlpanel._meta.get_fields()]
class UserFilter(django_filters.FilterSet):
class Meta:
model = Controlpanel
fields = dynamic_filter
user_list = Controlpanel.objects.all()
user_filter = UserFilter(request.GET.get("filters[]"),
queryset=user_list)
chart = list(user_filter.qs.values())
return JsonResponse(chart, safe=False)
Here's the AJAX code that calls this above view:
$('#filter-data').on('submit', function (event) {
event.preventDefault();
var dynamic = $('#filter-data').serialize();
console.log($('#filter-data').serializeArray())
$.ajax({
url: '/search/',
type: 'GET',
data: {
filters : dynamic
},
dataType: 'json',
success : function(json) {
console.log(json); // log the returned json to the console
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
The request.GET(or POST) currently stays empty even if I add a CSRF token and make it a POST request.
I came across some question on SO stating that use of request.body solves the issue but even that was a fail.
The issue was that the POST request was being passed as a string.
This solved the issue:
user_filters = request.POST.get('filters', '')
user_filters = user_filters.split("&")
user_filters = {item.split("=")[0]: item.split("=")[1].replace("%20", " ")
for item in user_filters}
user_filters.pop('csrfmiddlewaretoken')
i'm new in django and also in angularjs.
I wants to use Django for a REST api and angularjs for frontend view.
I have a django view that returns a json response:
class MyView(View):
def get(self, request):
data = serializers.serialize('json', MyModel.objects.order_by('name'))
return HttpResponse(data, mimetype='application/json')
def options(self, request):
response = HttpResponse()
response['allow'] = ','.join(['get', 'post', 'put', 'delete', 'options'])
return response
calling
http://localhost:8000/myapp/myview
i get the right json response
If in an angularjs controller (controllers.js) i try to call that view like this:
angular.module('myApp.controllers', []).
controller('MyCtrl', ['$scope', '$http', function($scope, $http) {
$scope.test = "Hola";
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://localhost:8000/myapp/myview').success(function(data) {
$scope.results = data;
console.log(data);
}).error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
console.log(data);
});
}]);
"test" value is correctly printed in the template
in django log i have: "GET /myapp/myview/ HTTP/1.1" 200 853
but in angular i don't retrieve any data. If i put a break point in error method, i have data empty and status = 0.
Any hints?
Am i missing something?
Been struggling with the same. The problem is with CORS. The solution is here
$http.get('http://localhost:8000/myapp/myview/').success(function(data)
The URL needs to drop the trailing /, then append .json. Like so:
$http.get('http://localhost:8000/myapp/myview.json').success(function(data)
I'm trying to send data to the server and use with AJAX
function stats(e){
jQuery.ajax({
type: "POST",
url:"stats",
data:{'csrfmiddlewaretoken': document.getElementsByName('csrfmiddlewaretoken')[0].value,
'test':{}},
success: function(data) {alert("Congratulations!"+data);},
error: function(data) {
alert("Please report this error: "+data.responseText);}
});
}
function in views.py:
def stats(request):
if request.is_ajax():
if request.user.is_authenticated():
if request.POST:
return HttpResponse(request.POST['test'])
else:
return HttpResponse("post_no_exists")
else:
return HttpResponse("no authenticate")
else:
raise Http404
Django raise MultiValueDictKeyError 'key "test" not found in QueryDict'.
When I change "test":{} -> "test":1 it succeds.
Whats my error?
Here:
...
data: {
'csrfmiddlewaretoken': ...,
'test': {}
}
...
You're trying to send an empty object literal as part of the POST request. jQuery can't figure out what value to send for that (empty object? what would that even mean?), so it simply doesn't send the test parameter at all. Thus, on the server side, trying to access request.POST['test'] throws a KeyError.
When you change the test to a different literal (in this case a number), jQuery can easily encode and send that as the value.
You need return answer as json
payload = {'answer': 'post_no_exists'}
return HttpResponse(json.dumps(payload, cls=LazyEncoder), content_type='application/json')
in js
alert("Congratulations!"+data.answer);