Téléchargement de fichiers implémenté avec Python + Bottle

Bottle est le cadre d'application Web léger de Python. Les applications Web génèrent parfois des fichiers côté serveur et les téléchargent. Cette fois, j'écrirai sur l'implémentation du téléchargement de fichiers dans Bottle.

Répertoire de fichiers statiques

Dans les applications Web, je pense que vous créez souvent un répertoire qui collecte des fichiers images / CSS / JS tels que / static /, mais dans de tels cas, vous ne pouvez pas créer de gestionnaires de requêtes un par un avec la fonction route, donc Il est pratique d'utiliser la fonction «static_file» de «bouteille» comme suit.

Dans cet exemple, accéder à http: // localhost: 8080 / static / hoge.txt fournira le contenu de hoge.txt dans. / Static comme vu depuis le répertoire courant au moment de l'exécution.

Dans le déploiement en production de nombreuses applications Web, je pense que le répertoire qui collecte les fichiers statiques est généralement livré directement depuis nginx ou apache. Cependant, si vous prenez en charge les applications Python écrites en bouteille, vous pourrez lire des fichiers statiques pendant le développement local. (Par rapport à notre entreprise)

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static')


run(host='localhost', port=8080)

En regardant Bottle source, il semble que les principaux formats de fichiers soient déduits par le paquet mimetypes par extension. est. Les fichiers communs tels que les images, les fichiers css et zip / gz sont susceptibles d'avoir le type MIME correct dans l'en-tête HTTP Content-Type.

Je veux qu'il soit téléchargé au lieu d'être affiché ...

Définissons l'option download de la fonction static_file sur True.

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static', download=True)


run(host='localhost', port=8080)

Si vous souhaitez séparer le nom du fichier à lire et le nom du fichier à enregistrer par le navigateur, définissez le nom du fichier à enregistrer dans le navigateur dans l'option télécharger. Les détails seront décrits plus loin dans la section "Arguments / options de la fonction Static_file".

Motif 1. Un petit fichier qui tient en mémoire

Vous pouvez utiliser la fonction static_file telle quelle.

# -*- coding: utf-8 -*-
from bottle import route, run, static_file


@route('/sample_image.png')
def sample_image():
    return static_file('./my_sample_image.png', root='.')


run(host='localhost', port=8080)

S'il est implémenté avec HTTPResponse, ce serait comme suit. Cela semble utile lorsque vous devez éditer le contenu du fichier au moment de l'exécution et faire des choses délicates telles que la distribution. Cependant, si vous souhaitez simplement télécharger un fichier existant, il est fondamentalement simple et fiable d'utiliser la fonction static_file. Vous pouvez utiliser la fonction static_file pour prendre en charge des détails tels que l'estimation du type MIME et la création d'une réponse 404 lorsque le fichier n'existe pas.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    response.set_header('Content-Length', str(len(content)))
    return content


run(host='localhost', port=8080)

Maintenant, lorsque vous accédez à http: // localhost: 8080 / sample_image.png, l'image sera affichée.

Le gestionnaire de la requête HTTP appelée à partir de Bottle utilise la propriété selon laquelle la valeur de retour du gestionnaire devient le corps de la réponse telle quelle. L'en-tête de la réponse HTTP est modifié en modifiant l'objet de réponse du package de bouteille tel quel. Personnellement, je préfère assembler et renvoyer explicitement un objet HTTPResponse comme celui ci-dessous.

# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse


@route('/sample_image.png')
def sample_image():
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    resp = HTTPResponse(status=200, body=content)
    resp.content_type = 'image/png'
    resp.set_header('Content-Length', str(len(content)))
    return resp


run(host='localhost', port=8080)

Si la valeur de retour du gestionnaire est HTTPResponse, le gestionnaire de la requête HTTP appelée depuis Bottle renverra la réponse en fonction du contenu de l'objet HTTPResponse. Pour plus d'informations sur HTTPResponse, reportez-vous à Objet Requête / Réponse de Mastering Bottle.

Modèle 2. Fichiers volumineux qui ne tiennent pas dans la mémoire

Les fichiers volumineux qui ne tiennent pas dans la mémoire doivent être lus petit à petit à partir du fichier et écrits sur le socket. Même dans de tels cas, static_file peut être utilisé. static_file n'est pas une réponse dans laquelle tout le contenu du fichier est lu, mais une implémentation qui lit et distribue petit à petit le fichier en interne.

Après enquête, il semble que lorsque le gestionnaire de bouteilles devient un générateur, chaque élément généré par le générateur est envoyé au client sous la forme d'un fragment fragmenté du corps. Même dans la [Source] de static_file (https://github.com/bottlepy/bottle/blob/master/bottle.py#L2725), le contenu est lu petit à petit par la fonction de générateur _file_iter_range et il devient la réponse. Et il semble.

Si vous l'implémentez vous-même, ce sera comme suit.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    bufsize = 1024  # 1KB
    with open('./my_sample_image.png', 'rb') as fh:
        while True:
            buf = fh.read(bufsize)
            if len(buf) == 0:
                break  # EOF
            yield buf


run(host='localhost', port=8080)

Vous n'avez pas à vous souvenir de cette méthode car il y a un static_file? Il y a aussi une histoire, Je pense qu'il peut y avoir une implémentation telle que la lecture à partir de la base de données à la volée sans passer par un fichier, le traiter dans un format de fichier CSV et l'envoyer au client. En fait, j'ai trouvé comment le faire dans un tel cas, alors j'espère que cela aidera quelqu'un d'autre.

Si vous souhaitez implémenter l'objet HTTPResponse sous la forme de return, définissez le générateur sur le corps de l'objet HTTPResponse.

# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse


@route('/sample_image.png')
def sample_image():
    resp = HTTPResponse(status=200)
    resp.content_type = 'image/png'

    def _file_content_iterator():
        bufsize = 1024  # 1KB
        with open('./my_sample_image.png', 'rb') as fh:
            while True:
                buf = fh.read(bufsize)
                if len(buf) == 0:
                    break  # EOF
                yield buf

    resp.body = _file_content_iterator()
    return resp


run(host='localhost', port=8080)

Cependant, cette méthode peut également être un peu désagréable car elle est difficile à comprendre à première vue, comme la définition d'une fonction à l'intérieur d'une fonction. Ceci est votre préféré.

L'implémentation du générateur peut être difficile à comprendre pour ceux qui ne connaissent pas Python, mais j'ai écrit un article sur les itérateurs / générateurs Python itérateurs et générateurs Python. Jetez un œil si vous le souhaitez.

Je veux le télécharger au lieu de l'afficher en ligne

Il s'agit plus de HTTP que de Bottle, mais vous pouvez le faire avec l'en-tête Content-Disposition. Si vous souhaitez utiliser la fonction static_file, vous pouvez définir l'option download sur True comme décrit ci-dessus. Ici, je présenterai l'implémentation de l'interaction en utilisant HTTPResponse.

# -*- coding: utf-8 -*-
from bottle import route, run, template, response


@route('/sample_image.png')
def sample_image():
    response.content_type = 'image/png'
    with open('./my_sample_image.png', 'rb') as fh:
        content = fh.read()
    response.set_header('Content-Length', str(len(content)))
    download_fname = 'hoge.png'
    response.set_header('Content-Disposition', 'attachment; filename="%s"' % download_fname.encode('utf-8'))
    return content


run(host='localhost', port=8080)

Maintenant, lorsque vous accédez à http: // localhost: 8080 / sample_image.png, l'image sera enregistrée avec le nom de fichier hoge.png.

Explication des arguments et des options de la fonction static_file

La signature de la fonction static_file est la suivante.

def static_file(filename, root,
                mimetype='auto',
                download=False,
                charset='UTF-8'):
    ....

--filename: Le nom du fichier dans root qui contient le contenu que vous voulez livrer. --root: Le répertoire contenant le fichier filename qui contient le contenu que vous voulez livrer. -- type mime: facultatif. Par défaut, il est automatiquement deviné par le package mimetypes. --download: facultatif. Si vous souhaitez télécharger sous la forme d'une boîte de dialogue d'enregistrement ou enregistrer automatiquement dans le dossier de téléchargement, spécifiez True ou le nom lors de l'enregistrement côté client sous forme de chaîne de caractères. «False» pour l'affichage en ligne. La valeur par défaut est «False» -- charset: facultatif. Si mimetype commence par text / ou est ʻapplication / javascript, ; charset = (value of charset) ʻest ajouté à l'en-tête HTTP Content-Type.

Lien de référence

Recommended Posts

Téléchargement de fichiers implémenté avec Python + Bottle
Télécharger le fichier csv avec python
Lire le fichier CSV avec python (Télécharger et analyser le fichier CSV)
Authentification BASIC avec bouteille Python
Dessiner un fichier netCDF avec python
Implémentation de SMO avec Python + NumPy
Extraire le fichier xz avec python
[Python] Ecrire dans un fichier csv avec Python
[Automatisé avec python! ] Partie 1: fichier de configuration
Sortie vers un fichier csv avec Python
Téléchargez le fichier déployé avec appcfg.py
Télécharger Python
[Automatisé avec python! ] Partie 2: Fonctionnement des fichiers
Créer un fichier power simple avec Python
Contrôle exclusif avec fichier de verrouillage en Python
Type de téléchargement de partage HTTP réalisé avec Python
Vérifier l'existence du fichier avec python
Créez rapidement un fichier Excel avec Python #python
Téléchargez les données de cours des actions japonaises avec Python
Lisons le fichier RINEX avec Python ①
Télécharger des fichiers sur le Web avec Python
[Python] Une application web rapide avec Bottle!
Créer un fichier Excel avec Python + matrice de similarité
Enregistrer avec Python → Enregistrer le fichier (périphérique sonore + wave)
Téléchargez facilement des mp3 / mp4 avec python et youtube-dl!
Téléchargez le fichier avec PHP [En construction]
Écraser le fichier de téléchargement pour python selenium Chrome
J'ai créé un fichier de configuration avec Python
[Automation] Lire le courrier (fichier msg) avec Python
Télécharger et télécharger des fichiers wav sur X-Server par FTP avec Python
Fichier python de script
FizzBuzz en Python3
Grattage avec Python
Statistiques avec python
Grattage avec Python
Python avec Go
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
Traitement de fichiers Python
Téléchargez le fichier en spécifiant la destination de téléchargement avec Python & Selemiun & Chrome (version Windows)
AES256 avec python
Testé avec Python
python commence par ()
avec syntaxe (Python)
Bingo avec python
Zundokokiyoshi avec python
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
Diviser le fichier mol2 avec python (-> 2016.04.17 prend également en charge le fichier sdf)
nginxparser: essayez d'analyser le fichier de configuration nginx avec Python
Comment lire un fichier CSV avec Python 2/3
Rechercher et télécharger automatiquement des vidéos YouTube avec Python
[Python] Comment lire des fichiers Excel avec des pandas
Convertir un fichier svg en png / ico avec Python
Lire les données de la table dans un fichier PDF avec Python
[Python] Automatisation implémentée pour la copie de fichiers Excel
Développer des applications Windows avec Python 3 + Tkinter (fichier exe)