Maison  >  Article  >  interface Web  >  Comment implémenter la fonction de téléchargement de fichiers dans Django

Comment implémenter la fonction de téléchargement de fichiers dans Django

php中世界最好的语言
php中世界最好的语言original
2018-04-11 17:17:143200parcourir

Cette fois, je vais vous montrer comment implémenter la fonction de téléchargement de fichiers dans Django. Quelles sont les précautions pour implémenter la fonction de téléchargement de fichiers dans Django. un cas pratique. Jetons un coup d'oeil une fois.

Si un site Web construit sur Django fournit une fonction de téléchargement de fichiers, le moyen le plus simple est de transmettre les fichiers statiques à Nginx pour traitement. Cependant, parfois, en raison de la logique du site Web lui-même, cela est nécessaire. pour fournir la fonction de téléchargement via Django, telle que la fonction d'exportation de données de page (télécharger des fichiers générés dynamiquement), vérifier les autorisations de l'utilisateur avant de télécharger des fichiers, etc. Il est donc nécessaire d’étudier l’implémentation de la fonction de téléchargement de fichiers dans Django.

La mise en œuvre de la fonction de téléchargement de fichiers la plus simple

Placez simplement le flux de fichiers dans l'objet HttpResponse, tel que :

def file_download(request):
  # do something...
  with open('file_name.txt') as f:
    c = f.read()
  return HttpResponse(c)

Cette méthode est simple et grossière, adaptée au téléchargement de petits fichiers, mais si le fichier est très volumineux, cette méthode occupera beaucoup de mémoire et provoquera même le crash du serveur

Fonction de téléchargement de fichiers plus raisonnable

L'objet HttpResponse de Django permet de transmettre des itérateurs en tant que paramètres. En remplaçant le paramètre entrant c dans le code ci-dessus par un itérateur, la fonction de téléchargement ci-dessus peut être optimisée pour convenir aux fichiers petits et grands et Django va encore plus loin ; recommande d'utiliser l'objet StreamingHttpResponse pour remplacer l'objet HttpResponse. L'objet StreamingHttpResponse est utilisé pour envoyer un flux de fichiers au navigateur. Il est très similaire à l'objet HttpResponse. Pour la fonction de téléchargement de fichiers, il est plus raisonnable d'utiliser l'objet StreamingHttpResponse.

Par conséquent, une fonction de téléchargement de fichier plus raisonnable devrait d'abord écrire un itérateur pour pour traiter le fichier , puis transmettre cet itérateur en tant que paramètre à l'objet StreaminghttpResponse, tel que :

from django.http import StreamingHttpResponse
def big_file_download(request):
  # do something...
 
  def file_iterator(file_name, chunk_size=512):
    with open(file_name) as f:
      while True:
        c = f.read(chunk_size)
        if c:
          yield c
        else:
          break
 
  the_file_name = "file_name.txt"
  response = StreamingHttpResponse(file_iterator(the_file_name))
 
  return response

La fonction de téléchargement de fichiers a été à nouveau optimisée

Le code ci-dessus a terminé le transfert des fichiers du serveur vers le navigateur via le streaming de fichiers. Cependant, le flux de fichiers est généralement affiché dans le navigateur sous une forme tronquée au lieu d'être téléchargé sur le disque dur. Par conséquent, certaines optimisations doivent être effectuées. Laissez le flux de fichiers être écrit sur le disque dur. L'optimisation est très simple. Attribuez simplement les valeurs suivantes aux champs Content-Type et Content-Disposition de l'objet StreamingHttpResponse, telles que :

response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="test.pdf"'

Le code complet est le suivant :

from django.http import StreamingHttpResponse
def big_file_download(request):
  # do something... 
  def file_iterator(file_name, chunk_size=512):
    with open(file_name) as f:
      while True:
        c = f.read(chunk_size)
        if c:
          yield c
        else:
          break
 
  the_file_name = "big_file.pdf"
  response = StreamingHttpResponse(file_iterator(the_file_name))
  response['Content-Type'] = 'application/octet-stream'
  response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) 
  return response

Format de fichier d'export spécifique

Exporter le tableau Excel

1. Tout d'abord, exportez directement le tableau Excel

Récupérez d’abord les données à exporter et enregistrez-les sous forme de liste.

Les données sont ensuite écrites dans Excel et renvoyées sur la page pour être téléchargées en continu.

import xlwt
import io
import json
from django.http import HttpResponse
def set_style(name, height, bold=False):
  style = xlwt.XFStyle() # 初始化样式
  font = xlwt.Font() # 为样式创建字体
  font.name = name # 'Times New Roman'
  font.bold = bold
  font.color_index = 000
  font.height = height
  style.font = font
  # 设置单元格边框
  # borders= xlwt.Borders()
  # borders.left= 6
  # borders.right= 6
  # borders.top= 6
  # borders.bottom= 6
  # style.borders = borders
  # 设置单元格背景颜色
  # pattern = xlwt.Pattern()
  # 设置其模式为实型
  # pattern.pattern = pattern.SOLID_PATTERN
  # 设置单元格背景颜色
  # pattern.pattern_fore_colour = 0x00
  # style.pattern = pattern
  return style
def write_excel(data, name, header):
  # 打开一个Excel工作簿
  file = xlwt.Workbook()
  # 新建一个sheet,如果对一个单元格重复操作,会引发异常,所以加上参数cell_overwrite_ok=True
  table = file.add_sheet(name, cell_overwrite_ok=True)
  if data is None:
    return file
  # 写标题栏
  row0 = [u'业务', u'状态', u'北京', u'上海', u'广州', u'深圳', u'状态小计']
  for i in range(0, len(row0)):
    table.write_merge(0, 0, i, i, row0[i], set_style('Times New Roman', 220, True))
  table.write_merge(0, 2, 7, 9, "单元格合并", set_style('Times New Roman', 220, True))
  """
  table.write_merge(x, x + m, y, w + n, string, sytle)
x表示行,y表示列,m表示跨行个数,n表示跨列个数,string表示要写入的单元格内容,style表示单元格样式。其中,x,y,w,h,都是以0开始计算的。
  """
  l = 0
  n = len(header)
  # 写入数据
  for line in data:
    for i in range(n):
      table.write(l, i, line[header[i]])
    l += 1
  # 直接保存文件
  # file.save("D:/excel_name.xls")
  # 写入IO
  res = get_excel_stream(file)
  # 设置HttpResponse的类型
  response = HttpResponse(content_type='application/vnd.ms-excel')
  from urllib import parse
  response['Content-Disposition'] = 'attachment;filename=' + parse.quote("excel_name") + '.xls'
  # 将文件流写入到response返回
  response.write(res)
  return response
def get_excel_stream(file):
  # StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
  excel_stream = io.BytesIO()
  # 这点很重要,传给save函数的不是保存文件名,而是一个BytesIO流(在内存中读写)
  file.save(excel_stream)
  # getvalue方法用于获得写入后的byte将结果返回给re
  res = excel_stream.getvalue()
  excel_stream.close()
  return res

2. Exporter le fichier json

L'exportation de fichiers json n'est pas aussi compliquée qu'Excel. Il vous suffit de fusionner les données au format json. Il est toujours très simple d'exporter directement vers le local. Mais lors de l'exportation vers une page Web, comment pouvez-vous renvoyer directement le flux sans l'enregistrer. le local aime exporter Excel ?

def write_json(data):
  try:
    json_stream = get_json_stream(data)
    response = HttpResponse(content_type='application/json')
    from urllib import parse
    response['Content-Disposition'] = 'attachment;filename=' + parse.quote("test") + '.json'
    response.write(json_stream)
    return response
  except Exception as e:
    print(e)
def get_json_stream(data):
  # 开始这里我用ByteIO流总是出错,但是后来参考廖雪峰网站用StringIO就没问题
  file = io.StringIO()
  data = json.dumps(data)
  file.write(data)
  res = file.getvalue()
  file.close()
  return res

3. Exporter le package compressé

Étant donné que l'exportation de deux fichiers ne peut pas les renvoyer tous les deux en même temps, envisagez de placer les deux fichiers dans un package, puis de renvoyer le package sous forme de flux.

pense? Ce qui est exporté en ce moment est dans un package zip. Comment puis-je écrire ces deux flux de fichiers dans le package zip? Cela semble un peu déraisonnable. Plus tard, sous la direction du patron, les fichiers à empaqueter ont été enregistrés localement, et après avoir été empaquetés dans zip, les fichiers locaux ont été supprimés, puis le flux du fichier zip a été lu, écrit dans la réponse et renvoyé dans le zip. flux de fichiers.

def write_zip(e_data, j_data, export_name):
  try:
    # 保存到本地文件
    # 返回文件名,注意此时保存的方法和前面导出保存的json、excel文件区别
    j_name = write_json(j_data, export_name[1])
    e_name = write_excel(e_data, export_name[1])
    # 本地文件写入zip,重命名,然后删除本地临时文件
    z_name='export.zip'
    z_file = zipfile.ZipFile(z_name, 'w')
    z_file.write(j_name)
    z_file.write(e_name)
    os.remove(j_name)
    os.remove(e_name)
    z_file.close()
    # 再次读取zip文件,将文件流返回,但是此时打开方式要以二进制方式打开
    z_file = open(z_name, 'rb')
    data = z_file.read()
    z_file.close()
    os.remove(z_file.name)
    response = HttpResponse(data, content_type='application/zip')
    from urllib import parse
    response['Content-Disposition'] = 'attachment;filename=' + parse.quote(z_name)
    return response
  except Exception as e:
    logging.error(e)
    print(e)

Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !

Lecture recommandée :

Explication détaillée des étapes d'utilisation de la bibliothèque de fonctions xe-utils avec vue

vue2.0 le routage n'est pas affiché Comment gérer la vue du routeur

Comment Native utilise fetch pour implémenter la fonction de téléchargement d'image

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn