7 Stimmen

Datei mit Python-Anforderungen hochladen

Ich habe versucht, eine Datei mithilfe der Box v2 API mit Anfragen hochzuladen.

Bisher hatte ich jedoch wenig Glück. Vielleicht kann mir hier jemand helfen, zu sehen, was ich tatsächlich falsch mache.

file_name = "%s%s" % (slugify(sync_file.description), file_suffix)
file_handle = open(settings.MEDIA_ROOT + str(sync_file.document), 'rb')
folder_id = str(sync_file.patient.box_patient_folder_id)

r = requests.post(
    files_url,
    headers=headers,
    files={
        file_name: file_handle,
        "folder_id": folder_id,
    },
)

Meine Authentifizierung funktioniert, denn ich erstelle kurz davor einen Ordner mit denselben Daten.

Eine Antwort sieht ungefähr so aus:

{
    u'status': 404, 
    u'code': u'not_found', 
    u'help_url': u'http://developers.box.com/docs/#errors', 
    u'request_id': u'77019510950608f791a0c1', 
    u'message': u'Not Found', 
    u'type': u'error'
}

Vielleicht ist hier jemand auf ein ähnliches Problem gestoßen.

7voto

MikeHunter Punkte 4074

Sie müssen 2 Python-Wörterbücher übergeben, Dateien und Daten. Dateien sind {uniqFileName:openFileObj} und Daten sind {uniqFileName:filename}. Unten finden Sie die Upload-Methode aus meiner Box-Klasse. Und denken Sie daran, einen abschließenden Eintrag in den Daten hinzuzufügen, 'folder_id': destination_id.

def uploadFiles(self, ufiles, folid):
    '''Lädt 1 oder mehr Dateien in der ufiles-Liste von Tupeln hoch, die
    (src voller Pfad, Zielname) enthalten. folid ist die ID des Ordners, in den
    hochgeladen werden soll.'''

    furl = URL2 + 'files/data'
    data, files = {}, {}
    for i, v in enumerate(ufiles):
        ff = v[0]
        fn = v[1]
        # Kopiere bei Bedarf in neue, umbenannte Datei im tmp-Ordner
        # kann keinen Weg finden, dies mit der API zu tun
        if os.path.basename(ff) != fn:
            dest = os.path.join(TMP, fn)
            shutil.copy2(ff, dest)
            ff = dest

        f = open(ff, 'rb')
        k = 'filename' + str(i)
        data[k] = fn
        files[k] = f

    data['folder_id'] = folid

    res = self.session.post(furl, files=files, data=data)

    for k in files:
        files[k].close()

    return res.status_code

Hier ist ein Beispielaufruf:

destFol = '406600304'

ret = box.uploadFile((('c:/1temp/hc.zip', 'hz.zip'),), destFol)

Wie gesagt, die obige Funktion ist eine Methode einer Klasse, mit einem Instanz-Attribut, das eine Requests-Sitzung enthält. Aber Sie können requests.post anstelle von self.session.post verwenden, und es wird genauso funktionieren. Denken Sie nur daran, die Header mit Ihrem API-Schlüssel und Token hinzuzufügen, wenn Sie es außerhalb einer Sitzung tun.

Laut Dokumentation sollte es möglich sein, die Datei umzubenennen, indem Sie ihr einen neuen Namen im data-Dictionary geben. Aber ich kann das nicht zum Laufen bringen, außer indem ich die Quelldatei in ein temporäres Verzeichnis mit dem gewünschten Namen kopiere und das hochlade. Es ist ein bisschen unkonventionell, aber es funktioniert.

Viel Glück, Mike

1voto

Wurzelgogerer Punkte 193

Da jemand meine Implementierung angefordert hat, dachte ich, ich würde sie hier für jeden veröffentlichen, der versucht, etwas Ähnliches zu erreichen.

files_url = "%s/files/content" % (settings.BOX_API_HOST)
headers = {"Authorization": "BoxAuth api_key=%s&auth_token=%s" % 
              (settings.BOX_API_KEY, self.doctor.box_auth_token)
          }

file_root, file_suffix = os.path.splitext(str(self.document))
filename = "%s%s" % (slugify(self.description), file_suffix)
files = {
        'filename1': open(settings.MEDIA_ROOT + str(self.document), 'rb'),
        }
data = {
        'filename1': filename,
        'folder_id': str(self.patient.get_box_folder()),
       }

r = requests.post(files_url,
                  headers=headers,
                  files=files,
                  data=data)

file_response = simplejson.loads(r.text)

try:
    if int(file_response['entries'][0]['id']) > 0:
        box_file_id = int(file_response['entries'][0]['id'])

        #Update the name of file
        file_update_url = "%s/files/%s" % (settings.BOX_API_HOST, box_file_id) 
        data_update = {"name":  filename}
        file_update = requests.put(file_update_url,
                                   data=simplejson.dumps(data_update),
                                   headers=headers)

        LocalDocument.objects.filter(id=self.id).update(box_file_id=box_file_id)
except:
    pass

Im Grunde genommen musste ich die Datei senden und die ID der neu aktualisierten Datei abrufen und eine weitere Anfrage an Box senden. Persönlich mag ich es auch nicht, aber es funktioniert für mich und ich konnte keine anderen Implementierungen finden, die die richtige Benennung von Anfang an durchführen.

Hoffentlich kann jemand von diesem Auszug profitieren.

0voto

tufelkinder Punkte 1034

Meine Lösung mit Requests:

def upload_to_box(folder_id, auth_token, file_out):
    headers = { 'Authorization' : BOX_AUTH.format(auth_token) }
    url = 'https://api.box.com/2.0/files/content'
    files = { 'filename': (new_file_name, open(file_out,'rb')) }
    data = { 'folder_id': folder_id }
    response = requests.post(url, params=data, files=files, headers=headers)

Es wäre schön, wenn Sie den Parameter new_copy angeben könnten, aber dafür gibt es keine Dokumentation und es scheint nicht zu funktionieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X