Mohammadhzp Mohammadhzp - 4 months ago 35
HTTP Question

upload files through http post in Pyside/PyQt

I'm trying to send a file and other POST variables to a xfilesharing script(which is in perl) on my customer server.

There are no good resources on Google and the code samples I've found don't work.(actually they were in c++ and I couldn't get them work)

server is using Apache for webserver

I ask a question before and I got a pretty good answer,so I'm using that uploader in here,code just not work for uploading file through http post

so can anyone first of all tell me what I need to do to upload file through HTTP post and then it would be great if you could give me a sample (simple code to upload on a localhost will be enough,I just want to see how to do that and how uploading works)

Answer

This question appears surprisingly difficult. There is indeed no complete examples on this topic.

PyQt

In PyQt4 I managed to run example provided in the QHttpMultiPart documentation. Adaptated Python version (requires Qt 4.8):

from PyQt4 import QtGui, QtCore, QtNetwork
import sys
import time

def finished(reply):
  print "Finished: ", reply.readAll()
  app.quit()

def construct_multipart(data, files):
  multiPart = QtNetwork.QHttpMultiPart(QtNetwork.QHttpMultiPart.FormDataType)
  for key, value in data.items():
    textPart = QtNetwork.QHttpPart()
    textPart.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader,
      "form-data; name=\"%s\"" % key)
    textPart.setBody(value)
    multiPart.append(textPart)

  for key, file in files.items():
    imagePart = QtNetwork.QHttpPart()
    #imagePart.setHeader(QNetworkRequest::ContentTypeHeader, ...);
    fileName = QtCore.QFileInfo(file.fileName()).fileName()
    imagePart.setHeader(QtNetwork.QNetworkRequest.ContentDispositionHeader,
      "form-data; name=\"%s\"; filename=\"%s\"" % (key, fileName))
    imagePart.setBodyDevice(file);
    multiPart.append(imagePart)
  return multiPart

app = QtGui.QApplication(sys.argv)
file1 = QtCore.QFile('/tmp/1.txt')
file1.open(QtCore.QFile.ReadOnly)
url = QtCore.QUrl('http://localhost:3000/qwertytest1');
data = { 'text1': 'test1', 'text2': 'test2' }
files = {'file1': file1 }
multipart = construct_multipart(data, files)
request_qt = QtNetwork.QNetworkRequest(url)
request_qt.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader,
  'multipart/form-data; boundary=%s' % multipart.boundary())
manager = QtNetwork.QNetworkAccessManager()
manager.finished.connect(finished)
request = manager.post(request_qt, multipart)

sys.exit(app.exec_())

PySide

PySide implementation has QHttpMultiPart missing. The only way is to construct post data contents manually. Luckily, Python has its own libraries to create multipart HTTP requests. Here is what I've written:

import sys
from PySide import QtCore, QtGui, QtNetwork
import requests

def finished(reply):
  print "Finished: ", reply.readAll()
  app.quit()

app = QtGui.QApplication(sys.argv)
url = 'http://localhost:3000/qwertytest1'
data = { 'text1': 'test1', 'text2': 'test2' }
files = {'file1': open('/tmp/1.txt') }
request = requests.Request('POST', url, data=data, files=files).prepare()
request_qt = QtNetwork.QNetworkRequest(url)
for header, value in request.headers.items():
  request_qt.setRawHeader(header, value)
manager = QtNetwork.QNetworkAccessManager()
manager.finished.connect(finished)
request = manager.post(request_qt, request.body)

sys.exit(app.exec_())

Note that this method loads all file content in the memory. It's unacceptable if you're dealing with large files. python-requests module itself supports sending large files dynamically, but there is no way to use this functionality with Qt. You can just use python-requests without Qt if that is the case.

Comments