Get 400 (empty response) when sending multi-part form to django - django

I'm working on an existing Django app and need to be able to upload a file.
I'm sending it a multi-part form so I can send a file and some fields, but the server I get back a 400, but the server errors silently and keeps running.
How can I allow my view to accept a multi-part form?
My route function definition is simply:
#api_view(['POST'])
def upload(request, pk)
print "hello"
It doesn't get to hello, so somewhere in the magical box of Django this JSON error is occuring. Can anyone give me a clue where to look? I've checked our urls.py file and see nothing that would make this decision or interrupt a request and our init.py file is empty. runserver isn't even a file... I guess it's just more django magic.
(Python: 2.7, Django: 1.10.6)

I was sending the request with a Content-Type header as form multipart, once I removed that header my request was being accepted again.
When I removed the header, a boundary field was added to content-type and I suppose that was necessary for Django to not fail silently.
I'm still not sure why Django failed silently.

Related

Django rest-auth PUT method returning JSON Unexpected token

I've been trying to try to do this for a couple of days for now. I am trying to update the user's data through put method in Django using rest framework. However, I've been receiving this error message in the console.
This is the fetch function that is used to send the data to the backend. As it's shown, I'm even trying to compare it to other fetch methods and I think nothing is wrong with the body of the fetch.
Below are my codes used to update the data.
views.py
serializers.py
urls.py
So, the error is
Unexpected token < in JSON
which means that it tried to parse a response containing a character <. If I had to guess, the response is a HTML document, because it would start with < (<html>...).
For instance, it can be a 404 error page because the URL was not found. The best way to know is, instead of logging response.json(), just log response.text(). Until you do that, hard to know what really happens.

Unity 2017.3 HTTP POST request always empty when it hits web app (Django)

I'm trying to use Unity 2017.3 to send a basic HTTP POST request from Unity scripting. I want to send an image data, which I can access in my script either as file.png or in a byte[]. I am only posting to a local server running Python/Django, and the server does register the POST request coming in - but no matter what I do the request arrives empty of any content, body, files or raw data at my web app.
IEnumerator WriteAndSendPng() {
#extra code that gets bytes from a render texture goes here
#can verify that drawing.png is a valid image for my purposes
System.IO.File.WriteAllBytes("drawing.png", bytes);
List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
formData.Add( new MultipartFormFileSection ("drawing", bytes, "drawing.png", "image/png") );
UnityWebRequest www = UnityWebRequest.Post("http://127.0.0.1:8000/predict/", formData);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) Debug.Log(www.error);
else Debug.Log("Form upload complete!");
}
I'm following the docs and there are a bunch of constructors for MultipartFormFileSection, most of which I feel like I've tried. Also tried UploadHandlers, or the old AddBinaryField WWW API - still the request is always empty when it hits my app... I've read the thorough response to this SO ticket, Sending http requests in C# with Unity. I have tried many of the implementations here but again, Django receives empty requests. Even submitting the simplest possible request from Unity sends empty requests. So weird.
List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
formData.Add (new MultipartFormDataSection ("someVar=something"));
The Python server just sees:
[11/Feb/2018 14:14:12] "POST /predict/ HTTP/1.1" 200 1
>>> print(request.method) # POST
>>> print(request.encoding) # None
>>> print(request.content_type) #multipart/form-data
>>> print(request.POST) # <QueryDict: {}>
>>> print(request.body) # b''
I thought it might be a Django issue, but posting to the same app w/ Postman or from other sources, it sees the incoming data just fine. Anyone done this recently? I thought this would be a piece of cake and many hours into into it I remain stymied. All help appreciated! Thanks, all.
Figured it out courtesy of Unity staffer Aurimas-Cernius on their forums: "The issue most likely is that your Django server does not support HTTP 1.1 chunked transfer. You can either try updating your server, or set chunkedTransfer property on UnityWebRequest to false."
He was right. Setting that flag to false allowed me to start sending simple test case data and receiving it as expected in the Django app - bet I'll be able to get images working in no time. I was also experiencing side effects of using Python 3.5.x (mistakenly assuming I needed to). Upgrading that fixed the chunk issue, too. Cheers!

Why am I getting different mime types on my flask app on localhost and openshift?

I have a dynamic css file which loads fonts using font-face which is generated by a request and I am setting the content headers explicitly. It's all working well as far as mime types are concerned at localhost(text/css in network tab) except that the fonts are not loaded in chrome but works in firefox. But that's a different issue, so now I put the code on openshift and by magic response has a text/html header. What am I missing here ?
resp = make_response(render_template('webfonts.css', fonts=fonts))
resp.headers.add('content-type', 'text/css')
return resp
heres the flask code.
and heres the url
http://flaskexample-diadara.rhcloud.com/api/webfonts?font=LohitGujarati
I had the same issue (with the Flask built-in server) and also came across your question, I found the following:
While adding the header can be found elsewhere as the recommended solution it actually doesn't set one of the properties in the Response object (which actually makes sense if you think about it) making the server still send out a default text/html header.
The way that I found it to work is this:
response = Response(render_template('css/' + filename), mimetype='text/css')
return response
You should also do
from flask import Response

How can I make hoptoad in Django 1.2 log errors to log file as well as send airbrake notifications?

We're using django 1.2.7 and the hoptoad logging middleware (hoptoad.middleware.HoptoadNotifierMiddleware).
When an error occurs, the error message gets sent to airbrake, but it does not seem to get logged to the django log file. It seems like it's intercepted by hoptoad exclusively.
Does anyone know how to also get the errors logged to the local django log file on disk? I couldn't find any such option in the hoptoad documentation.
Is there a custom modification needed to the hoptoad middleware class?

Django-tastypie. Output in JSON to the browser by default

I see 'Sorry, not implemented yet. Please append "?format=json" to
your URL.'. I need always append string "?format=json". Can I make a
output in JSON by default?
Regards,
Vitaliy
From the tastypie cookbook, in order to change the default format, you need to override the determine_format() method on your ModelResource:
class MyResource(ModelResource):
....
def determine_format(self, request):
return 'application/json'
The above link demonstrates alternative methods of determining output format.
Also, I don't think a valid answer is essentially "You don't need this".
Edit
It appears GregM's answer is probably (I haven't tested it) the most correct with the new version of TastyPie, as per documentation putting the following in your settings.py will restrict the serialization output to json.
TASTYPIE_DEFAULT_FORMATS = ['json']
As of tastypie 0.9.13, if you do not need XML support you can disable it globally by setting TASTYPIE_DEFAULT_FORMATS to just ['json'] in your settings.py file. Requests should then default to JSON.
I've tested setting TASTYPIE_DEFAULT_FORMATS to ['json'] but it doesn't prevent the "Sorry not implemented yet" message when viewing the API from a browser.
I am able to make that warning go away by forcing the "Accept" header to 'application/json' in a middleware:
class TastyJSONMiddleware(object):
"""
A Django middleware to make the Tastypie API always output in JSON format
instead of telling browsers that they haven't yet implemented text/html or
whatever.
WARNING: This includes a hardcoded url path for /api/. This is not 'DRY'
because it means you have to edit two places if you ever move your API
path.
"""
api_prefix = '/api/'
def process_request(self, request):
if request.path.startswith(self.api_prefix):
request.META['HTTP_ACCEPT'] = 'application/json'
Tasytpie has the defaults set as 'application/json'. But that is overridden by Browser request.
According to Tastypie, the default is overridden by Request Header ACCEPT and your format specification in GET ie. ?format=json. When you send request from browsers, if you see the Request HTTP Header sent, its something like -
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
The application/xml overrides the default in Tastypie Resource. Therefore, either you can set Browser Header to have 'application/json' (Bad idea) or you just specify in GET.
If you hit the same API url using CURL, you will see the JSON output without specifying that in GET.
To examine/test your REST API, use a Rest client instead of a browser, preferably one that knows how to pretty print JSON. I use the Postman plugin for Google Chrome.
If you want pretty json in command line:
curl https://api.twitter.com/1.1/search/tweets.json | python -m json.tool