Django - Passing a json or an array in URL for an API call - django

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

Related

Cannot get values from request in Django - Empty QueryDict

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.

Sending Django requests to NextJS with data

I am looking at integrating NextJS into an existing Django project. The project makes heavy use Django templates for most of its pages and I am looking at modernising the project by taking advantage of React and building out a design / component system. The idea is that we would look at replacing Django with NextJS eventually.
I have been able to use Django to proxy a request through to NextJS, and it works great! I have also been able to send data directly to the NextJS route so that I do not have to call back to Django to get data. This approach annoyingly has the limitation of only sending key/value data.
Here is the working code.
# django
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": "world"}
response = make_request("http://localhost:3000", data=data)
return HttpResponse(response)
//nextjs
import parse from "urlencoded-body-parser";
export async function getServerSideProps(context) {
const { req } = context;
const props = await parse(req);
return { props };
};
So with this in mind, is there a better way to achieve sending data to a NextJS route without having to do a callback?
After some research I was able to achieve this by using application/json content type.
class NextJsView(WhiteLabelMixin, View):
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": {"dark": "world"}}
response = make_request("http://localhost:3000", json=json.dumps(data))
return HttpResponse(response)
import getRawBody from "raw-body";
export async function getServerSideProps(context) {
const { req } = context;
let props = {};
if (req.method == "POST") {
const body = await getRawBody(req);
props = JSON.parse(JSON.parse(body));
}
return { props };
}

How to access get request data in django rest framework

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')

AngularJS/Django Post Response Data

I'm using AngularJS for the front-end and Django for the backend of a web app I'm working on. Right now I'm working on logging in users and I'm having a strange problem. Heres the relevant Angular code:
app.factory('AuthService', ["$http", "$q", "Session", "URL", function($http, $q, Session, URL) {
return {
login: function(credentials) {
var deferred = $q.defer();
$http.post(URL.login, credentials)
.then(function(data, status, headers, config) {
data=data.data; //WHY DOES THIS WORK?
if (data.success == true) {
alert("logged in");
Session.create(credentials.username, data.api_key);
deferred.resolve();
}
else {
deferred.reject("Login failed!");
}
}, function(data, status, headers, config) {
deferred.reject("Login failed!");
});
return deferred.promise
},
And here is the corresponding Django view:
def login_user(request):
'''
Given a username and password, returns the users API key.
'''
if request.method == 'POST':
username = request.POST.get('username',None)
password = request.POST.get('password',None)
user = authenticate(username=username,password=password)
if user is not None:
api_key = ApiKey.objects.get(user=user)
response_data = {}
response_data["api_key"] = str(api_key).split(" ")[0]
response_data["success"] = True
return HttpResponse(json.dumps(response_data), content_type="application/json")
else:
return HttpResponse(json.dumps({"username":username,"success":False}),content_type="application/json")
return HttpResponseBadRequest()
When the user logs in a POST request is sent and handled by the above Django code. The response is then picked up by the AngularJS code above. As you can see the then() method in the Angular code takes the usual four parameters: data, status, config and headers. I expect to see data contain the dictionary output from the Django code, appropriately serialized into a JSON object.
However what happens is that the only parameter of the then() method which is not undefined is data, and this contains EVERYTHING; headers, data, status code,etc.
The line commented 'WHY DOES THIS WORK' fixes the problem, by accessing the data inside. However, I want to know why this is happening and if there is any way to avoid this. My best guess is that it has something to do with the way Django serializes a response but I'm not sure.
I'm using Django 1.6.5.
That is actually how Angular promises work according to the docs. Here is the relevant quote.
Since the returned value of calling the $http function is a promise,
you can also use the then method to register callbacks, and these
callbacks will receive a single argument – an object representing the
response. See the API signature and type info below for more details.
The emphasis was mine.

django - passing data from server to js function via class based view

Django 1.6.3 +
Need to pass data to a class based view. where I want my jquery function to handle the data passed from the server. How would that be done ?
1.
Create a javascript/jquery function in your view which makes an $.ajax({options}); call to the url you want to send & receive data from (See #4 for an example).
2.
Have your views.py file import the json & HttpResponse module.
import json
from django.http import HttpResponse
3.
Add a function in your views.py to handle the request
def ExampleHandler(request):
Within this function, you can access parameters like request.POST['paramname'] or request.GET['paramname']. See https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.GET for more information.
To return data to the ajax call, store your data in a dictionary like this:
result = {
'success': True,
'foo': bar,
'more': data
}
and return the json like this:
return HttpResponse(json.dumps(result), content_type="application/json")
4.
Your original javascript function will look similar to this now:
function exampleRequest() {
$.ajax({
type: 'POST',
url: '/url-mapped-to-your-view',
data: {data: 'some-data-to-send-to-views'}, // May need to add a CSRF Token as post data (eg: csrfmiddlewaretoken: "{{ csrf_token }}")
error: function() {
alert('There was an issue getting the data...');
},
success: function(data) {
// Accessing data passed back from request, handle it how you wish.
alert(data.foo);
alert(data.more);
}
)};
}
5.
Ensure the url you make the ajax call to is correctly mapped in urls.py
You can probably pass data via args or kwargs
in views.py
class YourView(TemplateView):
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context['yourdata'] = self.kwargs['data']
return context
in urls.py
url(r'(?P<data>\w+)$', YourView.as_view()),