can't call django json view with angularjs - django

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)

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.

POST 400: Bad request - Using Django REST API and React

I'm pretty new to web development so please forgive me in advance for my ignorance.
I'm using React to try to post data to server endpoint managed by Django using this method:
sendData(data) {
const url = "http://127.0.0.1:8080/api/filtros/1/";
const requestOptions = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
};
fetch(url, requestOptions);
}
On the onClick of a NavDropdown React component:
<NavDropdown.Item
key={item.id}
onClick={() =>
this.sendData({
id: 0,
dimension_id: dimension.id,
item_id: item.id,
usuario_id: 1
})
}
>
{item.descripcion}
</NavDropdown.Item>
This is how I register the url on the router using Django:
router.register('api/filtros/1', FiltroUsuariosViewSet, 'filtro')
My Django ModelViewSet looks like this:
class FiltroUsuariosViewSet(viewsets.ModelViewSet):
queryset = FiltroUsuarios.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = FiltroUsuariosSerializers
And my Django Serializer looks like this:
class FiltroUsuariosSerializers (serializers.ModelSerializer):
class Meta:
model = FiltroUsuarios
fields = ('id', 'dimension_id', 'item_id', 'usuario_id')
def create(self, validated_data):
post = FiltroUsuarios.objects.create(**validated_data)
When I click on the Component I get this:
POST http://127.0.0.1:8080/api/filtros/1/ 400 (Bad Request)
and apparently the error is on the fetch request.
Do you guys have any idea on whats the problem?
Thanks a lot in advance!
The best way to understand and get rid of 400 Bad Request errors when wiring Django and React, is to run Django in development mode and then fire up your browser's Network tab while sending the request.
Switch into the Network -> Response tab and call sendData(). Since you are running on Django's development server, you will get the specific exception on your 400 Bad Request error. To simulate this, see the screenshot below and notice:
{"user": ["Incorrect type. Expected pk value, received str."]}
Back to your problem, you have the following in your .sendData():
x = {
id: 0,
dimension_id: dimension.id,
item_id: item.id,
usuario_id: 1
}
Which you then call JSON.stringify() on. If dimension.id and item_id are both integer (a reasonable assumption), then you're passing the following as a payload:
JSON.stringify(x)
# returns:
"{"id":0,"dimension_id":1,"item_id":2,"usuario_id":3}"
Your Django Model for FiltroUsuarios defined these columns / fields, so you now need to check both your models and FiltroUsuariosSerializers that these are expected value / value types mapping to these columns.

How to properly return Json reponse to template for ajax/jquery?

Here I am trying to search with the help of ajax and jquery with my django view. When I try to search like this by returning the JsonReponse instead of html_template it doesn't return data below the corresponding id in html
But When I return html from django view and create the new html for this searching results and including this template in the original template works perfectly but I find this a longer process So I tried to return json reponse from view and use that json objects in the template like this but it is not working.
How can I solve this ? I think I need to work on the ajax part .
def search_users(request):
q = request.GET.get('q')
if q:
users = get_user_model().objects.filter(is_active=True).filter(profile__full_name__icontains=q)
data = {'users': users}
else:
users = get_user_model().objects.filter(is_active=True)
data = {'users':users}
return JsonResponse(data)
ajax
$(function() {
$('#search_users').keyup(function() {
$.ajax({
type: "GET",
url: "{% url 'dashboard:search_users' %}",
data: {
'q' : $('#search_users').val(),
},
success: searchSuccess,
dataType: 'json'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search_users_results').json(data) #doing html instead of json works after returning html from django view
}
In the terminal
TypeError: Object of type QuerySet is not JSON serializable
[15/Mar/2020 14:02:53] "GET /admin/dashboard/search/users/?q=tyj HTTP/1.1" 500 22660
You have to extract values out of the query before sending it across instead of sending the model instance as it can't be serialized, is what the exception is saying.
So, you can just append .values() in the end and put in the list as below -
data = {'users': list(users.values())}
You may refer to it here.

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

Django : Calling a Url with get method

I have the url and corresponding view as follows.
url(r'^(?P<token>.*?)/ack$', views.api_ACK, name='device-api_ack')
def api_ACK(request, token):
"""
Process the ACK request comming from the device
"""
logger.info('-> api_ACK', extra={'request': request, 'token' : token, 'url': request.get_full_path()})
logger.debug(request)
if request.method == 'GET':
# verify the request
action, err_msg = api_verify_request(token=token, action_code=Action.AC_ACKNOWLEDGE)
return api_send_answer(action, err_msg)
I want to call api_ACK function with request method as GET from another view api_send_answer
I am creating one url in /device/LEAB86JFOZ6R7W4F69CBIMVBYB9SFZVC/ack in api_send_answer view as follows..
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
response = api_ACK(request=url,token=last_action.next_token) # This is wrong
Now from api_send_answer it is redirecting to api_ACK view, but how to call api_ACK with request method as GET?
Please help..Any suggestions would be helpful to me
This line
response = api_ACK(request=url,token=last_action.next_token) is wrong because view expects HttpRequest object and you give him url instead.
if you need to return view response to user, you can use redirect:
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
return HttpResponseRedirect(url)
if you need to do something else with view response you have to use HttpRequest object not url as parameter.