• 文件上传与邮件发送


    # 文件上传与邮件发送
    
    ### 原生实现
    
    - 模板文件
    
      ```html
      <form method="post" enctype="multipart/form-data">
          <input type="file" name="photo" /><br />
          <input type="submit" value="上传" />
      </form>
      ```
    
    - 视图函数
    
      ```python
      import os
    
      # 配置上传文件保存目录
      app.config['UPLOADED_FOLDER'] = os.path.join(os.getcwd(), 'static/upload')
    
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          if request.method == 'POST':
              # 获取上传对象
              photo = request.files.get('photo')
              if photo:
                  # 拼接保存路径名
                  pathname = os.path.join(app.config['UPLOADED_FOLDER'], photo.filename)
                  # 保存上传文件
                  photo.save(pathname)
                  return '上传成功'
              else:
                  return '上传失败'
          return render_template('upload.html')
      ```
    
    - 上传限制设置
    
      ```python
      # 允许上传的文件后缀
      ALLOWED_SUFFIX = set(['png', 'jpg', 'jpeg', 'gif'])
    
      # 判断是否是允许的后缀
      def allowed_file(filename):
          return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_SUFFIX
          
      # 限制请求大小
      app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 8
    
      # 展示上传的图片
      @app.route('/uploaded/<filename>')
      def uploaded(filename):
          return send_from_directory(app.config['UPLOADED_FOLDER'], filename)
        
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          img_url = None
    
          if request.method == 'POST':
              # 获取上传对象
              photo = request.files.get('photo')
              if photo and allowed_file(photo.filename):
                  # 拼接保存路径名
                  pathname = os.path.join(app.config['UPLOADED_FOLDER'], photo.filename)
                  # 保存上传文件
                  photo.save(pathname)
                  # 构造上传文件的url
                  img_url = url_for('uploaded', filename=photo.filename)
          return render_template('upload.html', img_url=img_url)
      ```
    
    ### flask-uploads
    
    - 说明:极大的的简化了文件上传相关的操作,使用非常方面。
    
    - 安装:`pip install flask-uploads`
    
    - 使用:
    
      - 配置
    
      ```python
      from flask_uploads import UploadSet, IMAGES
      from flask_uploads import configure_uploads
      from flask_uploads import patch_request_class
      import os
    
      app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd()
      app.config['MAX_CONTENT_LENGTH'] = 8 * 1024 * 1024
      # 创建上传对象
      photos = UploadSet('photos', IMAGES)
      # 配置上传对象
      configure_uploads(app, photos)
      # 配置上传文件大小,默认为64M,
      # 若设置为None,则以MAX_CONTENT_LENGTH配置为准
      patch_request_class(app, size=None)
      ```
    
      - 视图函数
    
      ```python
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          img_url = None
          if request.method == 'POST':
              # 获取上传对象
              photo = request.files.get('photo')
              if photo:
                  # 保存上传文件,返回文件名
                  filename = photos.save(photo)
                  # 根据文件名获取上传文件的URL
                  img_url = photos.url(filename)
          return render_template('upload.html', img_url=img_url)
      ```
    
    ### 综合使用
    
    - 要求:结合flask-bootstrap、flask-wtf、flask-uploads等完成文件上传
    
    - 使用:
    
      - 配置
    
      ```python
      from flask_wtf import FlaskForm
      from flask_wtf.file import FileField, FileAllowed, FileRequired
      from wtforms import SubmitField
      from flask_uploads import UploadSet, IMAGES
      from flask_uploads import configure_uploads
      from flask_uploads import patch_request_class
      from flask_bootstrap import Bootstrap
      import os
    
      bootstrap = Bootstrap(app)
    
      app.config['SECRET_KEY'] = '123456'
      app.config['MAX_CONTENT_LENGTH'] = 8 * 1024 * 1024
      app.config['UPLOADED_PHOTOS_DEST'] = os.path.join(os.getcwd(), 'static/upload')
    
      photos = UploadSet('photos', IMAGES)
      configure_uploads(app, photos)
      patch_request_class(app, size=None)
    
      class UploadForm(FlaskForm):
          photo = FileField('头像', validators=[FileRequired(message='请选择文件'), 
                                              FileAllowed(photos, message='只能上传图片文件')])
          submit = SubmitField('上传')
      ```
    
      - 视图函数
    
      ```python
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          img_url = None
          form = UploadForm()
          if form.validate_on_submit():
              photo = form.photo.data
              filename = photos.save(photo)
              img_url = photos.url(filename)
          return render_template('upload.html', form=form, img_url=img_url)
      ```
    
      - 模板文件
    
      ```html
      {% extends 'bootstrap/base.html' %}
    
      {% from 'bootstrap/wtf.html' import quick_form %}
    
      {% block title %}完整的文件上传{% endblock %}
    
      {% block content %}
          <div class="container">
              {% if img_url %}
                  <img src="{{ img_url }}">
              {% endif %}
              {{ quick_form(form) }}
          </div>
      {% endblock %}
      ```
    
      - 生成随机文件名
    
      ```python
      def random_string(length=32):
          import random
          base_str = 'abcdefghijklmnopqrstuvwxyz1234567890'
          return ''.join(random.choice(base_str) for i in range(length))
        
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          。。。
              # 提取文件后缀
              suffix = os.path.splitext(photo.filename)[1]
              # 生成随机文件名
              filename = random_string() + suffix
              # 保存文件
              photos.save(photo, name=filename)
          。。。
      ```
    
      - 生成缩略图:PIL模块(只支持py2,要支持py3需要安装pillow)
    
      ```python
      from PIL import Image
    
      @app.route('/upload/', methods=['GET', 'POST'])
      def upload():
          ...
              # 拼接完整文件路径名
              pathname = os.path.join(app.config['UPLOADED_PHOTOS_DEST'], filename)
              # 打开文件
              img = Image.open(pathname)
              # 设置大小
              img.thumbnail((64, 64))
              # 保存图片
              img.save(pathname)
          ...
      ```
    
    
    ### flask-mail
    
    - 说明:专门用于邮件发送的扩展库,使用非常方便。
    
    - 安装:`pip install flask-mail`
    
    - 使用:
    
      ```python
      from flask_mail import Mail, Message
      import os
    
      # 邮件发送配置,一定要放在创建Mail对象之前
      app.config['MAIL_SERVER'] = 'smtp.1000phone.com'
      # 用户名
      app.config['MAIL_USERNAME'] = 'lijie@1000phone.com'
      # 密码
      app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD', '123456')
    
      # 创建发送邮件的对象
      mail = Mail(app)
    
      @app.route('/send/')
      def send():
          # 创建邮件消息对象
          msg = Message('账户激活',
                        recipients=['shuai_fmzj@163.com'],
                        sender=app.config['MAIL_USERNAME'])
          msg.html = '恭喜你,中奖了!!!'
          # 发送邮件
          mail.send(msg)
          return '邮件已发送'
      ```
    
    - 封装函数发送邮件
    
      ```python
      def send_mail(subject, to, template, *args, **kwargs):
          if isinstance(to, list):
              recipients = to
          elif isinstance(to, str):
              recipients = to.split(',')
          else:
              raise Exception('邮件接收者参数类型有误')
          # 创建邮件消息对象
          msg = Message(subject,
                        recipients=recipients,
                        sender=app.config['MAIL_USERNAME'])
          # 将邮件模板渲染后作为邮件内容
          msg.html = render_template(template, *args, **kwargs)
          # 发送邮件
          mail.send(msg)
      ```
    
    - 异步发送邮件
    
      ```python
      from flask import current_app
    
      # 异步发送邮件任务
      def async_send_mail(app, msg):
          # 邮件发送必须在程序上下文
          # 新的线程中没有上下文,因此需要手动创建
          with app.app_context():
              mail.send(msg)
              
      # 封装函数发送邮件
      def send_mail(subject, to, template, *args, **kwargs):
          if isinstance(to, list):
              recipients = to
          elif isinstance(to, str):
              recipients = to.split(',')
          else:
              raise Exception('邮件接收者参数类型有误')
          # 创建邮件消息对象
          msg = Message(subject,
                        recipients=recipients,
                        sender=app.config['MAIL_USERNAME'])
          # 将邮件模板渲染后作为邮件内容
          msg.html = render_template(template, *args, **kwargs)
          # 异步发送邮件
          # current_app是app的代理对象
          # 根据代理对象current_app找到原始的app
          app = current_app._get_current_object()
          # 创建线程
          thr = Thread(target=async_send_mail, args=(app, msg))
          # 启动线程
          thr.start()
          # 返回线程
          return thr        
      ```
    
    
    ###环境变量
    
    - windows:
      - 设置:`set 环境变量名=值`
      - 获取:`set 环境变量名`
    - linux:
      - 导出:`export 环境变量名=值`
      - 获取:`echo $环境变量名`
    - 代码:
      - `os.getenv('环境变量名', '123456')`
  • 相关阅读:
    资源
    p/invoke碎片,对结构体的处理
    p/invoke碎片--对数组的封送处理
    p/invoke碎片--对类的封送处理
    CSS--background
    在Main方法中设置异常的最后一次捕捉
    记一次WinForm中屏蔽空格键对按钮的作用
    记一次WinForm程序中主进程打开子进程并传递参数的操作过程(进程间传递参数)
    知识点
    安卓N特性
  • 原文地址:https://www.cnblogs.com/liangliangzz/p/10221980.html
Copyright © 2020-2023  润新知