error when parsing value into Model (flask) - python-2.7

Objective is to accept UI multiple parameters and give it to the model (127.0.0.1:5002)using flask API and then the scoring from the model post back to UI (127.0.0.1:5001)
I am getting error (which is posted below at the end) when a model accept the value from the UI.
So i am posting values to 127.0.0.1:5002 where model takes that as 1 json object but i am getting error.
So i post 1 json object from this code (let me know if there is an issue in the code- i am a newbie)
<script>
$(function() {$('#analysis').bind('click', function() {
$.post('http://127.0.0.1:5002/',{
'CK': $('CK').val(),
'OCE': $('OCE').val(),
'range_04': $('range_04').val(),
},
function(data) {
var parsed = JSON.parse(data);
$("#xyz").text(parsed['abc']);
});
return false;
});
});
</script>
Now this code generates the json (and that json object feeds the model)
app = Flask(__name__)
api = Api(app)
parser = reqparse.RequestParser()
parser.add_argument('args.xyz')
class getPredProb(Resource):
def post(self):
args = parser.parse_args()
clf = joblib.load('AO.pkl')
frameToScore = pandas.read_json('args.xyz')
prediction = clf.predict(frameToScore)
probability = clf.predict_proba(frameToScore)
return json.dumps({'Prediction': prediction},{'Probability':probability}), 201, {'Access-Control-Allow-Origin': 'http://127.0.0.1:5001'}
api.add_resource(getPredProb, '/')
if __name__ == '__main__':
#http_server = WSGIServer(('', 5002), app)
#http_server.serve_forever()
app.run(debug=True,port=5002)
Image of ERROR

You're only passing a string, 'args.xyz', to read_json, you should use args['xyz'] (assuming this is the json data, as I don't see anything with an xyz key being passed to the backend).

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.

Unable to get POST or GET form data while using AJAX

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

ionic 2 upload image to django rest

I am trying to upload an image from Ionic 2 app to Django-powered website through Django Rest API.
The API is working and tested through Postman but I always get HTTP 400 BAD Request error in Ionic.
Here is my code in Ionic:
openCamera(){
var options = {
sourceType: Camera.PictureSourceType.CAMERA,
destinationType: Camera.DestinationType.DATA_URL
};
Camera.getPicture(options).then((imageData) => {
this.imageName = imageData;
this.imageURL = 'data:image/jpeg;base64,' + imageData;
}, (err) => {
this.showAlert(err);
});
}
Upload file (I am serving my Django project on my local PC with IP address 192.168.22.4):
transferData(auth){
let headers = new Headers();
headers.append('Authorization', auth);
let formData = new FormData();
formData.append('image', this.imageURL, this.imageName);
this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
let status = res['status'];
if(status == 200){
this.showAlert( "The image was successfully uploaded!");
}else{
this.showAlert("upload error");
}
}, (err) => {
var message = "Error in uploading file " + err
this.showAlert(message);
});
}
On Django, here is my serializer:
class ImageDetailsSerializer(serializers.ModelSerializer):
image = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user') ####status, category has default value
and views.py:
class ImageDetailsViewSet(generics.ListCreateAPIView):
queryset = ImageDetails.objects.all()
serializer_class = ImageDetailsSerializer
I am not sure if my code in uploading file is correct. I am trying to pass the data through Form data since the form works well in my API. Is this method correct? Are there any other methods to get this work?
Note: I have tried to use Transfer Cordova plugin but it is not working.
I finally solved the problem. The HTTP 400 indicates that there is a syntax error somewhere in the code and that is the encoding used in the uploaded photo. Mobile data uses base64 encoding. When sending requests, the file will then be converted to a Unicode string.
On the other hand, Django-Rest uses normal encoding for images, thus by default, it cannot support base64 image. But luckily, this plugin is already available at GitHub.
You just need to install the plugin and import it on your serializers.py:
from drf_extra_fields.fields import Base64ImageField
class ImageDetailsSerializer(serializers.ModelSerializer):
image = Base64ImageField()
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user')
On Ionic side, you have to submit the actual image not the imageURL. In my case I just have to tweak my code to:
transferData(auth){
let headers = new Headers();
headers.append('Authorization', auth);
let formData = new FormData();
formData.append('category', 1);
formData.append('status', 'Y')
formData.append('image', this.imageName);
this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
let status = res['status'];
if(status == 201){
var message = "The image was successfully uploaded!";
this.showAlert(message);
}else{
var message = "upload error";
this.showAlert(message);
}
}, (err) => {
var message = "Error in uploading file " + err;
this.showAlert(message);
});
In order to inspect what's ongoing with the request:
from rest_framework.exceptions import ValidationError
class ImageDetailsViewSet(generics.ListCreateAPIView):
queryset = ImageDetails.objects.all()
serializer_class = ImageDetailsSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if not serializer.is_valid():
print(serializer.errors) # or better use logging if it's configured
raise ValidationError(serialize.errors)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Even without Base64 it is possible using ionic native components for file-transfer and image-picker see here: https://gist.github.com/AndreasDickow/9d5fcd2c608b4726d16dda37cc880a7b

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.

How to output JSON from within Django and call it with jQuery from a cross domain?

For a bookmarklet project I'm trying to get JSON data using jQuery from my server (which is naturally on a different domain) running a Django powered system.
According to jQuery docs: "As of jQuery 1.2, you can load JSON data located on another domain if you specify a JSONP callback, which can be done like so: "myurl?callback=?". jQuery automatically replaces the ? with the correct method name to call, calling your specified callback." And for example I can test it successfully in my Firebug console using the following snippet:
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any& format=json&jsoncallback=?",
function(data){
alert(data.title);
});
It prints the returned data in an alert window, e.g. 'Recent uploads tagged cat'. However when I try the similar code with my server I don't get anything at all:
$.getJSON("http://mydjango.yafz.org/randomTest?jsoncallback=?",
function(data){
alert(data.title);
});
There are no alert windows and the Firebug status bar says "Transferring data from mydjango.yafz.org..." and keeps on waiting. On the server side I have this:
def randomTest(request):
somelist = ['title', 'This is a constant result']
encoded = json.dumps(somelist)
response = HttpResponse(encoded, mimetype = "application/json")
return response
I also tried this without any success:
def randomTest(request):
if request.is_ajax() == True:
req = {}
req ['title'] = 'This is a constant result.'
response = json.dumps(req)
return HttpResponse(response, mimetype = "application/json")
So to cut a long story short: what is the suggested method of returning a piece of data from within a Django view and retrieve it using jQuery in a cross domain fashion? What are my mistakes above?
This seems to work (I forgot to process the callback parameter!):
Server-side Python / Django code:
def randomTest(request):
callback = request.GET.get('callback', '')
req = {}
req ['title'] = 'This is a constant result.'
response = json.dumps(req)
response = callback + '(' + response + ');'
return HttpResponse(response, mimetype="application/json")
Client-side jQuery code to retrieve this data:
$.getJSON("http://mydjango.yafz.org/polls/randomTest?callback=?",
function(data){
alert(data.title);
});
Is there a better way to achieve the same effect (more established way in terms of Python and Django coding)?
From Django 1.7 onwards, you can simply use JsonResponse.
>>> from django.http import JsonResponse
>>> response = JsonResponse({'foo': 'bar'})
>>> response.content
b'{"foo": "bar"}'