I'm trying to upload a file into my web service (written using DJango REST framework). I have written the following code but I get data can not be converted to utf-8 error
with open('/images/img.jpg', 'rb') as imgFile:
content = imgFile.read ()
json = { 'fileName': 'img.jpg', 'img': content}
json_data = simplejson.dumps(json)
reqURL = urllib2.Request("http://localhost:8000/uploadfile/",json_data)
opener = urllib2.build_opener()
f = opener.open(reqURL)
What is the right way of passing file content over JSON?
You don't send files like this. File contents are sent by embedding them inside the request body.
You may be better of by using the beautiful python-request library. Check out the file upload section.
Related
i have post request to my python code. in the json body I need to send 1 parameter. and then I need to upload csv file.
I have 2 questions: 1. how to upload the csv from postman side 2. how to get it in my python code.
attached my post request and my python code.
post request screen shot
my code in python.
#cherrypy.tools.json_in()
#cherrypy.tools.json_out()
#cherrypy.tools.accept(media='application/json')
def POST(self):
body = cherrypy.request.json
If you want to use JSON to upload data. You need to convert csv file in to base64 string before you post your data. Because JSON format does not support file.
If you just want to get your data, you can select "form-data" in postman.
Code for 'form-data':
import cherrypy
#cherrypy.expose
#cherrypy.tools.json_out()
def uploadcsv(self, img=None, other=None):
print(img)
print(other)
return 'ok'
cherrypy.quickstart(HelloWorld())
Image of postman setting:
I am using
storages.backends.s3boto3.S3Boto3Storage
storage backend to upload files in my django project.
field declaration in model:
document = models.FileField(upload_to=s3_directory_path.user_directory_path)
user_directory_path
def user_directory_path(instance, filename):
# TODO: Try to include this along with check filetype on the request object
document = instance.document
mime = magic.from_buffer(document.read(), mime=True)
extension = mimetypes.guess_extension(mime, strict=False)
file_name = str(uuid.uuid4()) + extension
document.seek(0)
return os.path.join("users", str(instance.user.id), file_name)
The saving of the document works perfectly fine, but the link which is generated force downloads the file. How can i avoid that?
Have a look at this answer to a general question about forcing file downloads via HTTP response headers. See also the MDN docs about Content-Disposition.
Can you show us the response headers you get when visiting the document URL?
It would be interesting to see how S3 delivers your files.
If you cannot change the headers in S3, you have the option to write a Django view that proxies the file download. Alternatively, configure your webserver (i.e. NGINX) to act as a proxy and set the required headers).
For Django, this section of the docs will show you how to set the headers.
response = HttpResponse(
document,
headers={
'Content-Type': mimetype,
'Content-Disposition': f'attachment; filename="{document.name}"',
}
)
I want to develop a simple web server using python to handle some simple http request. I have learn how to response the request, such as transferring html pages or transferring some other file. When I transfer a image file, a client use a browser to get the file, the url is like below:
http://114.212.82.104:8080/1.png
I set 'Content-Type = application/x-png'. But the browser directly download the file, and can not display in the browser. Not like the image below
https://www.baidu.com/img/bd_logo1.png
it can display in the browser. How to display the image in the browser?
Can someone help me?
and i know i can encode the image file into html page to fix it. code like below:
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
path = os.getcwd()+ self.path
if os.path.isfile(path):
with open(path,'rb') as fileTrans:
content = fileTrans.read().encode('base64').replace('\n','')
#self.sendContent(200, content)
self.send_response(200)
page = "<p>\"fef\"</p><img src=\"data:image/jpg;base64,{0}\"/>"
contentPage = page.format(content)
self.send_header('Content-Type', 'text/html')
self.send_header("Content-Length", str(len(contentPage)))
self.end_headers()
self.wfile.write(contentPage)
else:
self.sendContent(404,"file do not exists")
But I know there must be another way, i see the source code of URL(https://www.baidu.com/)
it just use
<img hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129"></div><a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})">
different from my page:
<p>"fef"</p><img src="data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAcIAAAJYCAIAAAB+b3GqAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAvppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTMyIDc5LjE1OTI4NCwgMjAxNi8wNC8xOS0xMzoxMzo0MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODg3NkM1Njg1MzVFMTFFNkE0NkJFNTEzMUFCNzc4RTMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODg3NkM1Njc1MzVFMTFFNkE0NkJFNTEzMUFCNzc4RTMiIHhtcDpDcmVhdG9yVG9vbD0iOC4xLjMiPiA8eG1wTU06RG......
OK,I think I have solved this problem.
Just set the attribute - 'Content-Type' of header as 'image/png' instead of 'application/x-png'.
I am trying to unit test my file uploading REST API. I found online some code generating the image with Pillow but it can't be serialized.
This is my code for generating the image :
image = Image.new('RGBA', size=(50, 50), color=(155, 0, 0))
file = BytesIO(image.tobytes())
file.name = 'test.png'
file.seek(0)
Then I try to upload this image fille :
return self.client.post("/api/images/", data=json.dumps({
"image": file,
"item": 1
}), content_type="application/json", format='multipart')
And I get the following error:
<ContentFile: Raw content> is not JSON serializable
How can I transform the Pillow image so it's serializable?
I wouldn't recommend submitting your data as JSON in this case, as it complicates the issue. Just make a POST request with the parameters and files you want to submit. Django REST Framework will handle it just fine without you needing to serialise it as JSON.
I wrote a test for uploading a file to an API endpoint a while back which looked like this:
def test_post_photo(self):
"""
Test trying to add a photo
"""
# Create an album
album = AlbumFactory(owner=self.user)
# Log user in
self.client.login(username=self.user.username, password='password')
# Create image
image = Image.new('RGB', (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
image.save(tmp_file)
# Send data
with open(tmp_file.name, 'rb') as data:
response = self.client.post(reverse('photo-list'), {'album': 'http://testserver/api/albums/' + album.pk, 'image': data}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
In this case, I used the tempfile module to store an image generated using Pillow. The with syntax used in the example allows you to pass the content of the file in the request body comparatively easily.
Based on this, something like this should work for your use case:
image = Image.new('RGBA', size=(50, 50), color=(155, 0, 0))
file = tempfile.NamedTemporaryFile(suffix='.png')
image.save(file)
with open(file.name, 'rb') as data:
return self.client.post("/api/images/", {"image": data, "item": 1}, format='multipart')
Incidentally, depending on your use case it might be more convenient to accept the image data as a base 64 encoded string.
You converted the file to bytes, which is not JSON serializable.
Without knowing what your API expects to receive, I'll have to take a guess that you have to encode file as a string: "image": file.decode('utf-8').
While there are many solutions to your general issue of unit testing image uploads to a REST API
I followed the steps in media/upload. I wrote this function in python
def upload_media(self,access_token,image_url):
client = self.get_client(access_token)
message = {'media' : image_url}
encoded_status = urllib.urlencode(message)
url = "https://upload.twitter.com/1.1/media/upload.json?"+ encoded_status
resp, content = client.request(url,'post')
return content
And I got this :
{"request":"\/1.1\/media\/upload.json","error":"media type unrecognized."}
As far as I can tell, the error is in trying to upload a URL. The Twitter API requires you to upload a base64-encoded image.
See: https://dev.twitter.com/rest/reference/post/media/upload
So instead of the image's URL, it should be the file content:
with open('example.jpg', 'rb') as f:
data = f.read()
message = {'media':data}
Optionally (I still haven't figured out whether this is required or not, as different people give different answers), you could encode the image in base-64 encoding:
with open('example.jpg', 'rb') as f:
data = f.read()
data = data.encode('base64')
message = {'media':data}