VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 带你认识 flask 后台作业(4)

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
import jsonfrom flask import render_templatefrom app.email import send_email
# ...
def export_posts(user_id):    try:        # ...
        send_email('[Microblog] Your blog posts',                sender=app.config['ADMINS'][0], recipients=[user.email],                text_body=render_template('email/export_posts.txt', user=user),                html_body=render_template('email/export_posts.html', user=user),                attachments=[('posts.json', 'application/json',                              json.dumps({'posts': data}, indent=4))],                sync=True)    except:        # ...

 

只是其实对send_email()函数的调用。附件被定义为一个元组,其中有三个元素被传递给瓶邮件的Message对象的attach()方法。元组中的第三个元素是附件内容,它是用Python中的json.dumps()函数生成的。

这里引用了一对新模板,它们以纯文本和HTML格式提供电子邮件正文的内容。这是文本模板的内容:

app / templates / email / export_posts.txt:更新用户动态文本邮件模板

  •  
  •  
  •  
  •  
  •  
  •  
  •  
Dear {{ user.username }},
Please find attached the archive of your posts that you requested.
Sincerely,
The Microblog Team

这是HTML版本的邮件模板:

app / templates / email / export_posts.html:更新用户动态HTML邮件模板

  •  
  •  
  •  
  •  
<p>Dear {{ user.username }},</p><p>Please find attached the archive of your posts that you requested.</p><p>Sincerely,</p><p>The Microblog Team</p>

12

应用中的导出功能

 

剩下的就是将这个功能连接到应用,刹车用户发起请求并通过电子邮件发送用户动态给他们

下面是新的export_posts视图函数:

app / main / routes.py:导出用户动态路由和视图函数

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
@bp.route('/export_posts')@login_requireddef export_posts():    if current_user.get_task_in_progress('export_posts'):        flash(_('An export task is currently in progress'))    else:        current_user.launch_task('export_posts', _('Exporting posts...'))        db.session.commit()    return redirect(url_for('main.user', username=current_user.username))

该功能首先检查用户是否有未完成的任务,并在这种情况下只是闪现消息。对同一用户同时执行两个发起任务是没有意义的,可以避免。我可以使用前面实现的get_task_in_progress()方法来检查这种情况

如果一个用户没有正在运行的导出任务,则调用launch_task()来启动它。第一个参数是将传递给RQ worker的函数的名称,改为为app.tasks.。第二个参数只是一个友好的文本描述,将会显示给用户。这两个值都会被写入数据库中的任务对象。该函数以重定向到用户个人主页结束

我认为最合适的地方是在用户个人主页,只有在用户查看他们自己的主页时,链接在“编辑个人资料”链接下面显示:

app / templates / user.html:用户个人主页的导出链接

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
...<p>    <a href="{{ url_for('main.edit_profile') }}">        {{ _('Edit your profile') }}    </a></p>{% if not current_user.get_task_in_progress('export_posts') %}<p>    <a href="{{ url_for('main.export_posts') }}">        {{ _('Export your posts') }}    </a></p>...{% endif %}

此链接的渲染是有条件的,因为我不希望它在用户已经有发起任务执行时出现。

如果你想尝试一下,你可以按如下方式启动应用和RQ worker:

  • 确保Redis正在运行

  • :一个终端窗口,启动至少一个RQ worker实例。本处你可以运行命令rq worker microblog-tasks

  • 再打开另一个终端窗口,使用flask run (记得先设置  FLASK_APP变量)命令启动Flask应用

13

进度通知

 

为了完善这个功能,我想在后台任务运行时提醒用户任务完成的进度。在浏览Bootstrap组件选项时,我决定在导航栏的下方使用一个Alert组件。横条。我用蓝色的警报框来渲染闪现的消息。现在我要添加一个绿色的警报框来显示任务进度。样式如下:

 

 

 

app / templates / base.html基础模板中的导出进度Alert组件

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
...{% block content %}    <div class="container">        {% if current_user.is_authenticated %}        {% with tasks = current_user.get_tasks_in_progress() %}        {% if tasks %}            {% for task in tasks %}            <div class="alert alert-success" role="alert">                {{ task.description }}                <span id="{{ task.id }}-progress">{{ task.get_progress() }}</span>%            </div>            {% endfor %}        {% endif %}        {% endwith %}        {% endif %}        ...{% endblock %}...

 

外部条件在用户未登录时跳过所有与Alert相关的标记。而对于已登录的用户,我通过称为创建的get_tasks_in_progress()方法来获取当前的任务列表。在当前版本的应用中,我最多只能得到一个结果,因为我可以多个替换任务同时执行,但将来我可能要支持可以共存的其他类型的任务,所以以通用的方式渲染Alert可以节省我以后的时间。

对于每项任务,我都会在页面上渲染一个警报元素。警报的颜色由第二个CSS样式控制,本处是alert-success,而在闪现消息是alert-info引导文档所有游戏有关警报的HTML结构的详细信息。警报文本包括存储在Task模型中的description细分,后面跟着完成百分比。

被百分比封装在具有id属性的<span>元素中。原因是我要在收到通知时用的JavaScript刷新百分比。我给任务ID附加末尾-progress来构造id属性。当有通知到达时,通过其中的任务ID,我可以很容易地使用#<task.id>-progress选择器找到正确的<span>元素来更新。

如果您此时进行尝试,则每次导航到新页面时都会看到“静态”的进度更新。您可以注意到,在启动导出任务后,您可以自由导航到应用程序的不同页面,正在运行的任务的状态始终都会展示出来

为了对span>元素的百分比的动态更新做准备,我将在JavaScript端编写一个辅助函数:

app / templates / base.html:动态更新任务进度的辅助函数

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
...{% block scripts %}    ...    <script>        ...        function set_task_progress(task_id, progress) {            $('#' + task_id + '-progress').text(progress);        }