Flask Web开发实战 勘误

抱歉为你带来不便!如果你发现了书中的错误,可以创建Issue反馈,或是直接联系我,谢谢!

第 2 次印刷版本勘误表

位置 错误 正确 备注/时间
2.2 P30 请求报文示例表格 URL /hello 改为 http://helloflask.com/hello?name=Grey 19.2.2
2.2 P30 请求报文示例表格 去掉主体一栏的内容 19.2.2
2.2 P30 请求报文示例表格下方正文 如果 URL 中包含查询字符串,或是提交了表单,那么报文主体将会是查询字符串和表单数据。 如果提交了表单,那么报文主体将会是表单数据(查询字符串通常会直接通过 URL 传递)。 19.2.2
2.2 P31 命令行输出 /hello /hello?name=Grey 19.2.2
3.2.4 2.自定义测试器 P86下方 我们创建了一个没有意义的baz过滤器 我们创建了一个没有意义的baz测试器 笔误 19.1.9
4.3.1 P115 第 2 小节的代码块第 5 行 Length(8, 128) Length(6, 128) 前后不一致(1-3 重印时需要反过来调整另外 3 处),18.12.28
5 P139 第 1 个代码块 $ flask run 上面添加一行 $ flask initdb # 初始化数据库,后面会详细介绍 疏漏 19.1.5
5.4.2 P153 代码清单 5-5 删掉第 3 行,最后一行删除括号中的, form=form 代码未更新 18.12.24
5.4.2 P155 代码清单 5-8 第 3 行 DeleteForm() DeleteNoteForm() 代码未更新 18.12.24
P164 第 2 段第 2 行和第 3 行两处 backref() 函数 db.backref() 函数 优化 19.3.7
P164 第一个代码块第 3 行 backref=backref(...) backref=db.backref(...) 错误 19.3.7
7.3.1 P207 3.7.1节中最后一段话中 bootstrap_load_js() bootstrap.load_js() 笔误 18.11.17
7.4.3 P213 最后 1 个附注段落 bootstrap.bundle.min.css bootstrap.bundle.min.js 笔误 18.12.5
7.5 P214 该页(节)最后 2 个代码块的最后 1 行 两处均向左缩进 4 格,和上面对齐 排版错误 18.12.6
8.2.1 P237 代码清单 8-8 倒数第 3 行 删除这一行 后续内容前置 19.1.13
P263 代码清单 8-29 第 2 行 {{ comments|length }} Comments {{ pagination.total }} Comments <!-- 使用 pagination.total 获取分页条目总数 --> 优化 19.3.5
8.3.5 P264 图 8-8 上的代码块第2行 {{ comment.replied.author.name }} {{ comment.replied.author }} 笔误 18.12.6
8.3.7 P268 第1行 photo show_post 笔误 18.12.6
8.4.1 P273 纸书该页第 2 个代码块,电子书 8.4.2 上面倒数第 2 个代码块。第 5、7 行 check_password validate_password 笔误 18.12.6
8.5.3 P278 代码清单8-37代码块第1行 from flask_login import logout_user from flask_login import logout_user, login_required 代码错误 18.12.6
8.7.1.2 P288 代码清单8-42代码块倒数第2行 .show_post blog.show_post 笔误 18.12.6
8.7.1.3 P290 第1个代码块倒数第5行 .show_post blog.show_post 笔误 18.12.6
8.7.2 P292 代码清单8-44代码块倒数第1行 .show_post blog.show_post 笔误 18.12.6
9.1.1 P301 该页最后 1 行,电子书该节第 2 个代码块最后一行 向左缩进 4 格 排版错误 18.12.6
9.1.1 P302 9.1.2 标题上面的代码块 bluelog myapp 笔误 18.12.6
P309 代码清单 9-2 倒数第 6 行 field.data field.data.lower() 优化 19.3.5
9.3.2.1 P312 第二个代码块上正文倒数第1行 Operations字典中 Operations类中 笔误 18.12.10
9.3.2.2 P314 代码清单9-6代码块最后1行 url_for('.reset_confirmation') url_for('.reset_confirm_email') 笔误 18.12.12
9.4.4 P324 代码清单9-14代码块第4-5行 两处均向左缩进 4 格 排版错误 18.12.10
P332 图 9-4 下面第 2 行 dropzone_upload 视图 upload 视图 错误 19.3.5
9.5.3 P334 9.6 小节上面的代码块最后一行模板字符串 home/upload.html main/upload.html 遗留代码未更新 18.12.17
9.5.3 P334 9.6 小节上面的代码块 代码中的 400 和 800 分别替换为配置变量 current_app.config['ALBUMY_PHOTO_SIZE']['small']current_app.config['ALBUMY_PHOTO_SIZE']['medium'] 遗留代码 18.12.17
P360 代码清单 9-41 倒数第 2 行和倒数第 8 行两处 self.collected Collect.query.with_parent(self) 错误 19.3.5
P363 代码清单9-45 倒数第 6 行 collections collects 错误 19.3.5
P363 代码清单9-45 第 3 行 ... import user_card with context %} ... import user_card %} 提前 19.3.5
P367 正文第 3 行 if_following() is_following() 错误 19.3.5
P368 第 2 段第 2 行 去掉“和 is_followed_by()” 多余内容 19.3.5
9.8.3 P363 代码清单9-45代码块倒数第6行 {% if collections %} {% if collects %} 笔误 18.12.10
9.9.4 P371 代码清单9-53的路径 albumy/templates/profile_popup.html albumy/templates/main/profile_popup.html 笔误 18.12.21
9.9.4 P375 代码清单 9-56 下面的代码块第二行 id="followers-count" id="followers-count-{{ user.id }}" 笔误 18.12.21
9.11.2 P388 最后一行 渲染avatar.html模板 渲染change_avatar.html模板 笔误 18.12.10
9.11.2 P389 第一个代码块下正文第1行 avatar.html模板继承自settings.html模板 change_avatar.html模板继承自settings/base.html模板 笔误 18.12.10
9.11.2 P389 代码清单9-71代码块第1行 {% extends 'user/settings.html' %} {% extends 'user/settings/base.html' %} 笔误 18.12.10
9.11.6 P397 代码清单9-79代码块倒数第5行 current_user current_user._get_current_object() 笔误 18.12.10
9.11 P385 代码清单9-66倒数第9行 {{ render_nav_item('user.notification_setting', 'Notification and Privacy') }} {{ render_nav_item('user.notification_setting', 'Notification') }} {{ render_nav_item('user.privacy_setting', 'Privacy') }} 代码与实际项目不符 18.12.24
9.11.2 P389 代码清单9-71倒数第4行 {{ render_form(crop_form) }} {{ render_form(crop_form, action=url_for('.crop_avatar')) }} 笔误 18.12.24
P395 第 1 个代码块第 3 行 show_collections public_collections 错误 19.3.5
P396 提示段落 show_collections public_collections 错误 19.3.5
P406 代码清单 9-85 第 3 行 在这一行最后紧跟着括号添加(注意不要漏掉开始的英文句点) .strip() 优化,避免输入空格作为搜索词 19.3.5
P412 代码清单 9-90 倒数第 3 行 field.data field.data.lower() 优化 19.3.5
P417 文件目录树倒数第 6 行 app.py todo.py 错误 19.3.5
10.1.1 P420 第 2 小节第一个代码块第 7 行 {{ url_for('todo.clear_item') }}; {{ url_for('todo.clear_items') }}; 笔误 18.12.27
10.1.4 P425 第一个代码块第 6 行 jsonify(message='Invalid item body.'), 400 return jsonify(message='Invalid item body.'), 400 笔误 19.1.20
10.3.3 P447 第 1 小节/该页最后一个代码块 ... import api ... import api_v1 笔误 18.12.28
10.3.3 P447 第 1 小节/该页最后一个代码块 csrf.exempt(api) csrf.exempt(api_v1) 笔误 18.12.28
10.3.3 P453 代码清单10-13第一行中的methods参数 methods=['GET', 'POST'] methods=['GET'] 与原定的方法不一致 18.12.28
10.3.3 P453 代码清单10-13第二行中的第一个参数 '/token' '/oauth/token' 与实际项目不一致 18.12.28
10.3.3 P453 代码清单10-13第二行中的methods参数 methods=['GET'] methods=['POST'] 与实际项目不一致 18.12.28
10.3.5 P462 代码清单10-20倒数第4行 item.author, item.author.username, 笔误 18.12.28
11.3.2 P483 代码清单11-4倒数第2行 花括号"}"后添加一个逗号"," 笔误 18.12.28
11.3.2 P484 代码清单11-5第2行 $('message') $('.messages') 笔误 18.12.28
11.4.1 P491 该节最后一段正文的第1行 views包 blueprints包 笔误 18.12.29
11.4.3 P498 附注段落下方正文第2行 provide_name provider_name 笔误 18.12.29
11.4.3.5 P503 最后一个代码块 access_token = resp.get('access_token') access_token = response.get('access_token') 笔误 18.12.29
11.4.3.6 P505 提示段落上方的代码块 @oauth_bp.route(...) @auth_bp.route(...) 笔误 18.12.29
11.4.4 P506 第二个代码块 所有 resp 改为 response 笔误 18.12.29
11.4.4 P506 第二个代码块 增加if response is not None:... else:...语句,具体参考源码 笔误 18.12.29
11.5.1 P508 代码清单11-12 '_messages.html' 'chat/_messages.html' 笔误 18.12.29
11.5.1 P509 代码清单11-13第5行 position === 0&& socket.nsp! == '/anonymous' position === 0 && socket.nsp !== '/anonymous' 审校错误,空格错误 18.12.29
11.5.1 P510 代码清单11-13倒数第6行 toast('No more messages.'); alert('No more messages.'); 此项目中未定义toast函数 18.12.29
11.5.4 P516 代码清单11-15第3行 'message' 'new message' 笔误 18.12.29
11.5.4 P516 代码清单11-15第6行 document.title = '(' + message_count + ') ' + document.title; document.title = '(' + message_count + ') ' + 'CatChat'; 消息数量会随着事件多次发生而不断追加在原标题前 18.12.29
11.5.5 P517 代码清单11-17第6行 data.name data.nickname 笔误 18.12.30
11.5.5 P517 代码清单11-17第7行 icon: ... icon: data.gravatar 笔误 18.12.30
11.5.5 P518 最后1个代码块第5行 '_message.html' 'chat/_message.html' 笔误 18.12.30
11.5.5 P518 最后1个代码块第6行 message_body html_message 笔误 18.12.30
12.3.1 P526 代码清单12-1 setUp方法最后面追加一行代码self.client = app.test_client() 代码缺失 19.01.05
12.3.2 P527 提示段落下方的正文第3行 assertEqual() assertTrue() 笔误 19.01.05
12.3.2 P527 代码清单12-3 test_404_page方法的注释 # 测试 400 错误页面 # 测试 404 错误页面 笔误 19.01.05
12.3.3 P534 代码清单12-6最后1个导入语句 from bluelog.models import User from bluelog.models import Admin 笔误 19.01.06
13.1.2 P550 代码清单13-1 @app.after_app_request @app.after_request 笔误 19.01.06
13.1.2 P550 代码清单13-1 两处current_app改为app 笔误 19.01.06
13.3 P557 命令行命令 $ cd cache $ cd assets 笔误 19.01.06
14.3.1 P567 第二个代码块第2行 token_urlsafe(16) secrets.token_urlsafe(16) 笔误 18.11.28
14.3.4 P569 代码清单14-1 register_logger函数缺少app参数 register_logging() register_logging(app) 笔误 18.11.28
14.4.7 P584 倒数第2个代码块上方段落第5行 放在/etc/supervisord.conf路径下 放在/etc/supervisor/conf.d路径下 笔误 18.11.28
14.3.4.1 P569 代码清单14-1上方正文 register_logger() register_logging() 与实际源码不符 19.01.21
14.3.4.1 P569 代码清单14-1 register_logger() register_logging(app) 与实际源码不符 19.01.21
14.3.4.1 P569 代码清单14-1 RotatingFileHandler的第一个参数 os.path.join(basedir, 'logs/bluelog.log') 与实际源码不符 19.01.21
14.3.4.2 P570 代码块 register_logger() register_logging(app) 与实际源码不符 19.01.21
14.3.4.3 P571 代码清单14-2 register_logger() register_logging(app) 与实际源码不符 19.01.21
14.3.4.3 P571 代码清单14-3 register_logger() register_logging(app) 与实际源码不符 19.01.21
14.3.4.3 P571 代码清单14-3 5处os.getenv() app.config[] 与实际源码不符 19.01.21
14.4.3.1 P576 提示段落第二行 C/Users/Administrator/.ssh C:\Users\Administrator.ssh 错误 19.01.21
15.5 P611 正文第5行 在模板中提供load()方法资源。 在模板中提供load()方法加载静态资源。 句子不完整 19.01.21
15.5.1 P612 页面中部代码块 def load(css_url=None, js_url=None): def load(css_url=None, js_url=None, serve_local=False): 与实际源码不符 19.01.21
15.5.1 P612 页面中部代码块 if current_app.config['SHARE_SERVE_LOCAL']: if serve_local or current_app.config['SHARE_SERVE_LOCAL'] 与实际源码不符 19.01.21
15.5.1 P612 页面中部代码块最后1行中的filename参数 filename='js/share.min.js' filename='js/social-share.min.js' 笔误 19.01.21
15.6.1 P614 代码清单15-8中Share类的init_app方法中的blueprint Blueprint缺少static_folder和static_url_path参数 见代码清单15-5或项目源码 笔误 19.01.21
15.6.1 P614 代码清单15-8中Share类的init_app方法 没有将扩展添加到模板上下文 添加代码app.jinja_env.globals['share'] = self 代码缺少 19.01.21
15.6.1 P614 代码清单15-8中Share类的init_app方法最后1行第2个参数 True False 与实际源码不符 19.01.21
15.6.1 P615 代码清单15-7和代码清单15-8中Share类的create方法参数 addition_class=None addition_class='' 与实际项目不符 19.01.21
16.2.4 P639 最后1个段落的第2行 在不基于线程、greenlet或单进程实现的并发服务器上 在不基于线程、Greenlet 或进程实现并发的服务器上 笔误 18.12.31
16.4.2 P649 最后1行 Flask.route()是Flask类的类方法 Flask.route()是Flask类的实例方法 笔误 19.1.1
16.4.3 2. 堆栈与LocalStack P659 第1段第3行 并将数据的字典名称设为'stack'。 并将储存上下文对象的列表名称设为'stack' 笔误 19.1.4
16.4.5 P672 第一段第一行 对传入的请求对象调用 对传入的响应对象调用 笔误 19.2.8

P412 添加 validate_username() 方法定义(同时添加到 1-1 勘误):

def validate_username(self, field):
    if field.data != self.user.username and User.query.filter_by(username=field.data).first():
        raise ValidationError('The username is already in use.')

P363 正文第 1 段,原文:

我们在第 3 章曾经介绍过 Jinja2 的上下文机制,因为 user_card 宏里使用了 Flask-Login 提供的 current_user 变量,所以我们需要在导入时使用 with context 指令显式声明包含上下文:

改为:

根据第 3 章介绍的 Jinja2 上下文机制,因为 user_card 宏后面会使用 Flask-Login 提供的 current_user 变量,到时你需要为相关的导入语句追加 with context 指令显式声明包含上下文:

P393 代码清单9-74 从该页第 3 行到第 8 行,原文为:

    if form.validate_on_submit() and current_user.validate_password(form.old_password.data):
        current_user.set_password(form.password.data)  # 重设密码
        db.session.commit()
        flash('Password updated.', 'success')
        return redirect(url_for('.index', username=current_user.username))

修改为:

    if form.validate_on_submit():  # 验证表单是否通过验证
        if current_user.validate_password(form.old_password.data):  # 验证旧密码
            current_user.set_password(form.password.data)  # 设置新密码
            db.session.commit()  # 提交数据库会话
            flash('Password updated.', 'success')
            return redirect(url_for('.index', username=current_user.username))
        else:
            flash('Old password is incorrect.', 'warning')  # 旧密码不对则显示提示

P409 代码清单 9-88 在第 2 行和第 10 行(@permission 开头的两行)上面分别插入新的一行,内容为 @login_required,比如:

@admin_bp.route('/lock/user/<int:user_id>', methods=['POST'])
@login_required
@permission_required('MODERATE')

P275 8.5 小节标题上面添加提示段落:

提示 在 fakes.py 脚本里的 fake_admin() 函数中,我们需要在 admin 对象创建后,为虚拟用户记录设置密码:admin.set_password('helloflask')。

不重要勘误

有一些不重要的勘误没有在这里列出,详情访问勘误源码查看。