• 第1章 章节一

  • 01 内容概要

  • 02 内容回顾

  • 03 路飞学城之加入购物车

  • 04 路飞学城之结算

  • 05 路飞学城之立即支付

  • 06 路飞学城之后续计划

  • 07 Flask框架简介和快速使用

  • 08 FLask框架之用户管理系统示例(一)

  • 09 Flask框架之用户管理系统示例(二)

  • 第2章 章节二

  • 01 内容概要

  • 02 内容回顾

  • 03 Flask框架之配置

  • 04 Flask框架之创建路由的两种方式

  • 05 Flask框架之反向生成URL

  • 06 Flask框架之自定义路由转换器

  • 07 Flask框架之app.route参数

  • 08 Flask框架之获取子域名的路由

  • 09 上述内容总结

  • 10 Flask框架之视图中添加装饰器

  • 11 Flask框架之CBV和FBV

  • 12 Flask框架之请求和响应相关

  • 13 Flask框架之模板引擎

  • 14 Flask框架之session使用和源码流程(一)

  • 15 Flask框架之session使用和源码流程(二)

  • 16 Flask框架之before_request和after_request(一)

  • 17 Flask框架之after_request(二)

  • 18 Flask框架字号常见装饰器

  • 19 上述内容总结

  • 20 Flask之闪现

  • 21 Flask中间件

  • 22 Flask框架之蓝图(一)

  • 23 Flask框架之蓝图(二)

  • 24 拓展知识:pipreqs

  • 25 拓展知识:函数和方法

  • 第3章 章节三

  • 01 内容概要

  • 02 内容回顾

  • 03 threading.local学习

  • 04 自定义Local思路

  • 05 自定义Local对象(基于函数)

  • 06 自定义Local对象(基于面向对象)

  • 07 Flask上下文管理之本质分析

  • 08 Flask上下文管理之请求到处理阶段

  • 09 Flask上下文管理之视图调用阶段

  • 10 Flask上下文管理之视图调动阶段和结束阶段

  • 11 问题来了

  • 12 Flask中的g到底是什么呢?生命周期

  • 13 内容补充:面向对象的私有字段

  • 14 homework

  • 第4章 章节四

  • 01 内容概要

  • 02 内容回顾

  • 03 路飞学城补充:视频播放授权

  • 04 flask-session组件使用和原理(一)

  • 05 flask-session组件使用和原理(二)

  • 06 flask-session组件使用和原理(三)

  • 07 flask-session组件使用和原理(四)

  • 08 基于pymysql实现用户登录

  • 09 基于数据库连接池实现用户登录

  • 10 解决bug(一)

  • 11 解决bug(二)

  • 12 数据库连接池总结

  • 13 WTforms介绍以及用户登录示例

  • 14 WTforms用户注册示例

  • 15 内容总结

  • 16 homework

第1章 章节一

01 内容概要

1.1 路飞购买流程

  • 加入购物车
  • 结算
  • 去支付

1.2 Flask框架

  • 路由
  • 视图
  • 模板
  • session
  • ...

02 内容回顾

2.1 路飞学城项目结构

  2.1.1 前后端分离;

  2.1.2 导师后台+管理后台+主站(本人负责)

2.2 主站的功能

  2.2.1 Vue——兼职、课程列表、详细、深科技

  2.2.2 rest api

  • 课程系列——列表、详细、推荐课程、章节&课时、常见问题、评论
  • 深科技——文章列表、详细、评论、赞、收藏
  • 个人中心——我的账户、个人资料、订单、课程中心
  • 购买流程(复杂)——加入购物车、去结算、立即支付
  • 其他——关于我们、联系我们、意见反馈

2.3 技术点

  2.3.1 rest framework框架——认证组件(用于用户认证) or Django中间件,两者实现的时机不同,认证逻辑无需实现;

  2.3.2 跨域——jsonp(动态生成script标签) cors;

  2.3.3 Redis——购物逻辑,用户session两个场景下使用;

  • 频繁操作;
  • 中间状态;
  • 数据放入内容,速度快;
  • Redis锁

  2.3.4 支付宝支付接口

  • RSA加密;
  • 数字金额有要求,保留小数点后两位;
  • 两个URL;
  • 支付宝公钥和商户私钥;

  2.3.5 微信消息推送

  • 微信企业号
  • 沙箱环境
  • 普通消息和模板消息
  • 关注公众号,生成二维码
  • 通过js生成二维码
  • 唯一标识获取到

  2.3.6 ContenType

  • 参考Django settings
  • 参考Django 中间件

  2.3.7 rest framework分页

  2.3.8 接口写的最多的查询接口;

  2.3.9 视图

  • queryset

  2.3.10 序列化

  • __new__方法;
  • source
  • Method

  2.3.11 Git协同开发

  2.3.12 ORM操作

  • only
  • defer
  • exclude
  • filter

  2.3.13 CRSF

  • 基于中间件做
  • 基于装饰器

  2.3.14 Vue.js基本命令

  • Vue.js的基本命令
  • Router拦截器
  • Ajax——jQuery、axios ——本质都是XMLHttpRequest对象实现;
  • 请求头Content-Type:request.POST
  • json
  • vuex
  • vue-cookies

  2.3.15 面试题总结准备

  2.3.16 组织架构、人员配比、项目周期;

03 路飞学城之加入购物车

3.1 加入购物车

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import json
  4. from django.core.exceptions import ObjectDoesNotExist
  5. from django.conf import settings
  6.  
  7. from rest_framework.views import APIView
  8. from rest_framework.viewsets import ViewSetMixin
  9. from rest_framework.viewsets import ModelViewSet
  10. from rest_framework.response import Response
  11.  
  12. from repository import models
  13.  
  14. from api.serializer.payment import ShoppingCarSerializer
  15. from api.utils.auth.token_auth import LuffyTokenAuthentication
  16. from api.utils.auth.token_permission import LuffyPermission
  17. from api.utils import redis_pool
  18. from api.utils.exception import PricePolicyDoesNotExist
  19.  
  20. class ShoppingCarView(ViewSetMixin, APIView):
  21. """
  22. 购物车接口
  23. """
  24. authentication_classes = [LuffyTokenAuthentication, ]
  25. permission_classes = [LuffyPermission, ]
  26.  
  27. def get(self, request, *args, **kwargs):
  28. """
  29. 根据用户ID获取购物车所有东西
  30. :param request:
  31. :param args:
  32. :param kwargs:
  33. :return:
  34. """
  35. response = {'code': 1000, 'data': None}
  36. try:
  37. product_dict = redis_pool.conn.hget(settings.REDIS_SHOPPING_CAR_KEY, request.user.id)
  38. if product_dict:
  39. product_dict = json.loads(product_dict.decode('utf-8'))
  40. response['data'] = product_dict
  41. except Exception as e:
  42. response['code'] = 1001
  43. response['msg'] = "获取购物车列表失败"
  44.  
  45. return Response(response)
  46.  
  47. def post(self, request, *args, **kwargs):
  48. """
  49. # 根据课程ID获取课程信息以及相关所有价格策略
  50. chopping_car = {
  51. request.user.id:{
  52. course.id:{
  53. title:'xx',
  54. img:'xx',
  55. choice_policy_id:1,
  56. price_policy_dict:{
  57. {id:1,price:'9.9', period:'1个月'},
  58. {id:2,price:'19.9',period:'3个月'},
  59. {id:3,price:'59.9',period:'8个月'},
  60. },
  61. }
  62. },
  63. course.id:[
  64. title:'xx',
  65. img:'xx',
  66. choice_policy_id:1,
  67. price_policy_dict:{
  68. {id:1,price:'9.9', period:'1个月'},
  69. {id:2,price:'19.9',period:'3个月'},
  70. {id:3,price:'59.9',period:'8个月'},
  71. },
  72. ]
  73. }
  74. }
  75. }
  76. :param request:
  77. :param args:
  78. :param kwargs:
  79. :return:
  80. """
  81.  
  82. response = {'code': 1000, 'msg': None}
  83. try:
  84. course_id = int(request.data.get('course_id'))
  85. policy_id = int(request.data.get('policy_id'))
  86.  
  87. # 获取课程信息
  88. course = models.Course.objects.exclude(course_type=2).filter(status=0).get(id=course_id)
  89.  
  90. # 序列化课程信息,并获取其关联的所有价格策略
  91. ser = ShoppingCarSerializer(instance=course, many=False)
  92. product = ser.data
  93.  
  94. # 判断价格策略是否存在
  95. policy_exist = False
  96. for policy in product['price_policy_list']:
  97. if policy['id'] == policy_id:
  98. policy_exist = True
  99. break
  100. if not policy_exist:
  101. raise PricePolicyDoesNotExist()
  102.  
  103. # 设置默认选中的价格策略
  104. product.setdefault('choice_policy_id', policy_id)
  105. # 获取当前用户在购物车中已存在的课程,如果存在则更新,否则添加新课程
  106. product_dict = redis_pool.conn.hget(settings.REDIS_SHOPPING_CAR_KEY, request.user.id)
  107. if not product_dict:
  108. product_dict = {course_id: product}
  109. else:
  110. product_dict = json.loads(product_dict.decode('utf-8'))
  111. product_dict[course_id] = product
  112. # 将新课程写入到购物车
  113. redis_pool.conn.hset(settings.REDIS_SHOPPING_CAR_KEY, request.user.id, json.dumps(product_dict))
  114.  
  115. except ObjectDoesNotExist as e:
  116. response['code'] = 1001
  117. response['msg'] = '视频不存在'
  118. except PricePolicyDoesNotExist as e:
  119. response['code'] = 1002
  120. response['msg'] = '价格策略不存在'
  121. except Exception as e:
  122. print(e)
  123. response['code'] = 1003
  124. response['msg'] = '添加购物车失败'
  125.  
  126. return Response(response)
  127.  
  128. def delete(self, request, *args, **kwargs):
  129. """
  130. 删除购物车中的课程
  131. :param request:
  132. :param args:
  133. :param kwargs:
  134. :return:
  135. """
  136. response = {'code': 1000}
  137. try:
  138. course_id = kwargs.get('pk')
  139. product_dict = redis_pool.conn.hget(settings.REDIS_SHOPPING_CAR_KEY, request.user.id)
  140. if not product_dict:
  141. raise Exception('购物车中无课程')
  142. product_dict = json.loads(product_dict.decode('utf-8'))
  143. if course_id not in product_dict:
  144. raise Exception('购物车中无该商品')
  145. del product_dict[course_id]
  146. redis_pool.conn.hset(settings.REDIS_SHOPPING_CAR_KEY, request.user.id, json.dumps(product_dict))
  147. except Exception as e:
  148. response['code'] = 1001
  149. response['msg'] = str(e)
  150.  
  151. return Response(response)
  152.  
  153. def put(self, request, *args, **kwargs):
  154. """
  155. 更新购物车中的课程的默认的价格策略
  156. :param request:
  157. :param args:
  158. :param kwargs:
  159. :return:
  160. """
  161. response = {'code': 1000}
  162. try:
  163. course_id = kwargs.get('pk')
  164. policy_id = request.data.get('policy_id')
  165. product_dict = redis_pool.conn.hget(settings.REDIS_SHOPPING_CAR_KEY, request.user.id)
  166. if not product_dict:
  167. raise Exception('购物车清单不存在')
  168. product_dict = json.loads(product_dict.decode('utf-8'))
  169. if course_id not in product_dict:
  170. raise Exception('购物车清单中商品不存在')
  171.  
  172. policy_exist = False
  173. for policy in product_dict[course_id]['price_policy_list']:
  174. if policy['id'] == policy_id:
  175. policy_exist = True
  176. break
  177. if not policy_exist:
  178. raise PricePolicyDoesNotExist()
  179.  
  180. product_dict[course_id]['choice_policy_id'] = policy_id
  181. redis_pool.conn.hset(settings.REDIS_SHOPPING_CAR_KEY, request.user.id, json.dumps(product_dict))
  182. except PricePolicyDoesNotExist as e:
  183. response['code'] = 1001
  184. response['msg'] = '价格策略不存在'
  185. except Exception as e:
  186. response['code'] = 1002
  187. response['msg'] = str(e)
  188.  
  189. return Response(response)

04 路飞学城之结算

4.1 结算

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import json
  4. import datetime
  5. from django.conf import settings
  6.  
  7. from rest_framework.views import APIView
  8. from rest_framework.response import Response
  9.  
  10. from api.utils.auth.token_auth import LuffyTokenAuthentication
  11. from api.utils.auth.token_permission import LuffyPermission
  12. from api.utils import redis_pool
  13. from repository import models
  14.  
  15. class PaymentView(APIView):
  16. """
  17. 去结算接口
  18. """
  19. authentication_classes = [LuffyTokenAuthentication, ]
  20. permission_classes = [LuffyPermission, ]
  21.  
  22. def get(self, request, *args, **kwargs):
  23. """
  24. 获取结算列表
  25. :param request:
  26. :param args:
  27. :param kwargs:
  28. :return:
  29. """
  30. response = {'code': 1000}
  31. try:
  32. # 结算商品列表
  33. payment_list = redis_pool.conn.hget(settings.REDIS_PAYMENT_KEY, request.user.id)
  34. if not payment_list:
  35. raise Exception()
  36.  
  37. response['data'] = {
  38. 'payment_list': json.loads(payment_list.decode('utf-8')), # 结算信息(课程、价格和优惠券)
  39. "balance": request.user.balance # 个人贝里账户,可使用贝里金额
  40. }
  41. except Exception as e:
  42. response['code'] = 1001
  43. response['msg'] = "结算列表为空"
  44.  
  45. return Response(response)
  46.  
  47. def post(self, request, *args, **kwargs):
  48. """
  49. 去结算
  50. 方案一(示例):用户提交课程id,去redis购物车中获取其选好的价格策略,再次检测课程和价格策略的合法性。
  51. PS: 直接购买时,需要先加入购物车,再立即去结算
  52.  
  53. 方案二:用户提交课程id和价格策略id,去数据库验证其合法性。
  54. PS: 直接购买时,直接去结算
  55.  
  56. user.id: {
  57. policy_course_dict:{
  58. 课程ID:{
  59. 'course_id': course_id,
  60. 'course_name': product['name'],
  61. 'course_img': product['course_img'],
  62. 'policy_id': product['choice_policy_id'],
  63. 'policy_price': policy_price,
  64. 'policy_': policy_period,
  65. 'coupon_record_list': [
  66. {'id': 0, 'text': '请选择优惠券'},
  67. {'id': 1, 'type':1, 'text': '优惠券1', ..},
  68. {'id': 2, 'type':2, 'text': '优惠券1', ..},
  69. {'id': 3, 'type':3, 'text': '优惠券1', ..},
  70. ],
  71. },
  72. 课程ID:{
  73. 'course_id': course_id,
  74. 'course_name': product['name'],
  75. 'course_img': product['course_img'],
  76. 'policy_id': product['choice_policy_id'],
  77. 'policy_price': policy_price,
  78. 'policy_': policy_period,
  79. 'coupon_record_list': [
  80. {'id': 0, 'text': '请选择优惠券'},
  81. {'id': 1, 'type':1, 'text': '优惠券1', ..},
  82. {'id': 2, 'type':2, 'text': '优惠券1', ..},
  83. {'id': 3, 'type':3, 'text': '优惠券1', ..},
  84. ],
  85. }
  86. },
  87. global_coupon_dict:{
  88. 1:{'type': 0, 'text': "通用优惠券", 'id': 1, ..},
  89. 2:{'type': 0, 'text': "通用优惠券", 'id': 2, ..},
  90. 3:{'type': 0, 'text': "通用优惠券", 'id': 3, ...},
  91. 4:{'type': 0, 'text': "通用优惠券", 'id': 4, ...},
  92. }
  93. }
  94.  
  95. :param request:
  96. :param args:
  97. :param kwargs:
  98. :return:
  99. """
  100. response = {'code': 1001}
  101. try:
  102.  
  103. """
  104. 1. 获取要支付的课程ID
  105. 2. 检查购物车中是否存在,不存在则报错
  106. 循环用户提交的课程ID,去购物车中获取,如果不存在,就报错。
  107.  
  108. """
  109. # 获取用户提交的课程id
  110. course_id_list = request.data.get('course_list')
  111. if not course_id_list or not isinstance(course_id_list, list):
  112. raise Exception('请选择要结算的课程')
  113.  
  114. # 购物车中检查是否已经有课程(应该有课程的)
  115. product_dict = redis_pool.conn.hget(settings.REDIS_SHOPPING_CAR_KEY, request.user.id)
  116. if not product_dict:
  117. raise Exception('购物车无课程')
  118.  
  119. # 购物车中是否有用户要购买的课程
  120. product_dict = json.loads(product_dict.decode('utf-8'))
  121.  
  122. # ###### 课程、价格和优惠券 #######
  123. policy_course_dict = {}
  124.  
  125. for course_id in course_id_list:
  126. course_id = str(course_id)
  127. product = product_dict.get(course_id)
  128. if not product:
  129. raise Exception('购买的课程必须先加入购物车')
  130.  
  131. policy_exist = False
  132. for policy in product['price_policy_list']:
  133. if policy['id'] == product['choice_policy_id']:
  134. policy_price = policy['price']
  135. policy_period = policy['period']
  136. policy_valid_period = policy['valid_period']
  137. policy_exist = True
  138. break
  139. if not policy_exist:
  140. raise Exception('购物车中的课程无此价格')
  141.  
  142. policy_course = {
  143. 'course_id': course_id,
  144. 'course_name': product['name'],
  145. 'course_img': product['course_img'],
  146. 'policy_id': product['choice_policy_id'],
  147. 'policy_price': policy_price,
  148. 'policy_period': policy_period,
  149. 'policy_valid_period': policy_valid_period,
  150. 'coupon_record_list': [
  151. {'id': 0, 'text': '请选择优惠券'},
  152. ],
  153. }
  154. policy_course_dict[course_id] = policy_course
  155.  
  156. # 获取当前所有优惠券
  157. user_coupon_list = models.CouponRecord.objects.filter(account=request.user,
  158. status=0)
  159. # ###### 全局优惠券 #######
  160. global_coupon_record_dict = {}
  161.  
  162. # 课程优惠券添加到课程中;全局优惠券添加到全局
  163. current_date = datetime.datetime.now().date()
  164. for record in user_coupon_list:
  165. # 检查优惠券是否已经过期
  166. begin_date = record.coupon.valid_begin_date
  167. end_date = record.coupon.valid_end_date
  168. if begin_date:
  169. if current_date < begin_date:
  170. continue
  171. if end_date:
  172. if current_date > end_date:
  173. continue
  174. # 全局优惠券
  175. if not record.coupon.content_type:
  176. if record.coupon.coupon_type == 0:
  177. temp = {'type': 0, 'text': "通用优惠券", 'id': record.id,
  178. 'begin_date': begin_date, 'end_date': end_date,
  179. 'money_equivalent_value': record.coupon.money_equivalent_value}
  180. elif record.coupon.coupon_type == 1:
  181. temp = {'type': 1, 'text': "满减券", 'id': record.id,
  182. 'begin_date': begin_date, 'end_date': end_date,
  183. 'minimum_consume': record.coupon.minimum_consume,
  184. 'money_equivalent_value': record.coupon.money_equivalent_value}
  185. elif record.coupon.coupon_type == 2:
  186. temp = {'type': 2, 'text': "折扣券", 'id': record.id,
  187. 'begin_date': begin_date, 'end_date': end_date,
  188. 'off_percent': record.coupon.off_percent}
  189. else:
  190. continue
  191.  
  192. global_coupon_record_dict[record.id] = temp
  193. # 课程优惠券
  194. else:
  195. cid = record.coupon.object_id
  196. if record.coupon.content_type.model == 'course' and cid in policy_course_dict:
  197. # 课程价格:满减,打折,通用
  198. if record.coupon.coupon_type == 0:
  199. temp = {'type': 0, 'text': "通用优惠券", 'id': record.id,
  200. 'begin_date': begin_date, 'end_date': end_date,
  201. 'money_equivalent_value': record.coupon.money_equivalent_value}
  202. elif record.coupon.coupon_type == 1 and policy_course_dict[cid][
  203. 'policy_price'] >= record.coupon.minimum_consume:
  204. temp = {'type': 1, 'text': "满减券", 'id': record.id,
  205. 'begin_date': begin_date, 'end_date': end_date,
  206. 'minimum_consume': record.coupon.minimum_consume,
  207. 'money_equivalent_value': record.coupon.money_equivalent_value}
  208. elif record.coupon.coupon_type == 2:
  209. temp = {'type': 2, 'text': "折扣券", 'id': record.id,
  210. 'begin_date': begin_date, 'end_date': end_date,
  211. 'off_percent': record.coupon.off_percent}
  212. else:
  213. continue
  214. policy_course_dict[cid]['coupon_record_list'].append(temp)
  215.  
  216. user_pay = {
  217. 'policy_course_dict': policy_course_dict,
  218. 'global_coupon_record_dict': global_coupon_record_dict
  219. }
  220. redis_pool.conn.hset(settings.REDIS_PAYMENT_KEY, request.user.id, json.dumps(user_pay))
  221.  
  222. except Exception as e:
  223. response['code'] = 1002
  224. response['msg'] = str(e)
  225.  
  226. return Response(response)

05 路飞学城之立即支付

5.1 立即支付

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import json
  4. import time
  5. import random
  6. import datetime
  7. from django.conf import settings
  8. from django.db import transaction
  9. from django.db.models import F
  10.  
  11. from rest_framework.views import APIView
  12. from rest_framework.response import Response
  13.  
  14. from api.utils.auth.token_auth import LuffyTokenAuthentication
  15. from api.utils.auth.token_permission import LuffyPermission
  16. from api.utils import redis_pool
  17. from api.utils.alipay import AliPay
  18.  
  19. from repository import models
  20.  
  21. def generate_order_num():
  22. """
  23. 生成订单编号, 且必须唯一
  24. :return:
  25. """
  26. while True:
  27. order_num = time.strftime('%Y%m%d%H%M%S', time.localtime()) + str(random.randint(111, 999))
  28. if not models.Order.objects.filter(order_number=order_num).exists():
  29. break
  30. return order_num
  31.  
  32. def generate_transaction_num():
  33. """
  34. 生成流水编号, 且必须唯一
  35. :return:
  36. """
  37. while True:
  38. transaction_number = time.strftime('%Y%m%d%H%M%S', time.localtime()) + str(random.randint(111, 999))
  39. if not models.TransactionRecord.objects.filter(transaction_number=transaction_number).exists():
  40. break
  41. return transaction_number
  42.  
  43. class PayOrderView(APIView):
  44. authentication_classes = [LuffyTokenAuthentication, ]
  45. permission_classes = [LuffyPermission, ]
  46.  
  47. def post(self, request, *args, **kwargs):
  48. """
  49. 去支付,生成订单。
  50. 获取前端提交的购买信息
  51. {
  52. course_price_list:[
  53. {'policy_id':1, '':'course_id':1, 'coupon_record_id':1},
  54. {'policy_id':2, '':'course_id':2, 'coupon_record_id':2},
  55. ],
  56. coupon_record_id:1,
  57. alipay: 99,
  58. balance: 1
  59. }
  60.  
  61. 1. 用户提交
  62. - balance
  63. - alipay
  64. 2. 获取去结算列表
  65.  
  66. 课程
  67. 3. 循环所有课程
  68. - 获取原价
  69. - 抵扣的钱
  70.  
  71. :param request:
  72. :param args:
  73. :param kwargs:
  74. :return:
  75. """
  76. response = {'code': 1000}
  77. try:
  78. # 用户请求验证
  79. policy_course_list = request.data.get('course_price_list')
  80. coupon_record_id = request.data.get('coupon_record_id')
  81. alipay = request.data.get('alipay') # >= 0
  82. balance = request.data.get('balance') # >= 0
  83.  
  84. if balance > request.user.balance:
  85. raise Exception('账户中贝里余额不足')
  86.  
  87. # 检查用户提交的信息在 redis结算列表 中是否存在,如果不存在,则需要用户从购物车中再次去结算
  88. payment_dict_bytes = redis_pool.conn.hget(settings.REDIS_PAYMENT_KEY, request.user.id)
  89. payment_dict = json.loads(payment_dict_bytes.decode('utf-8'))
  90.  
  91. policy_course_dict = payment_dict['policy_course_dict']
  92. global_coupon_record_dict = payment_dict['global_coupon_record_dict']
  93.  
  94. global_coupon_record = {}
  95. # 全局优惠券
  96. if coupon_record_id:
  97. if coupon_record_id not in global_coupon_record_dict:
  98. raise Exception('全局优惠券在缓存中不存在')
  99. global_coupon_record = global_coupon_record_dict[coupon_record_id]
  100.  
  101. # 当前时间
  102. current_date = datetime.datetime.now().date()
  103. current_datetime = datetime.datetime.now()
  104.  
  105. # 原价
  106. total_price = 0
  107. # 总抵扣的钱
  108. discount = 0
  109. # 使用优惠券ID列表
  110. if coupon_record_id:
  111. use_coupon_record_id_list = [coupon_record_id, ]
  112. else:
  113. use_coupon_record_id_list=[]
  114. # 课程和优惠券
  115. buy_course_record = []
  116.  
  117. for cp in policy_course_list:
  118. _policy_id = cp['policy_id']
  119. _course_id = cp['course_id']
  120. _coupon_record_id = cp['coupon_record_id']
  121.  
  122. temp = {
  123. 'course_id': _course_id,
  124. 'course_name': "course",
  125. 'valid_period': 0, # 有效期:30
  126. 'period': 0, # 有效期:一个月
  127. 'original_price': 0,
  128. 'price': 0,
  129. }
  130.  
  131. if str(_course_id) not in policy_course_dict:
  132. raise Exception('课程在缓存中不存在')
  133.  
  134. redis_course = policy_course_dict[str(_course_id)]
  135.  
  136. if str(_policy_id) != str(redis_course['policy_id']):
  137. raise Exception('价格策略在缓存中不存在')
  138.  
  139. # 课程是否已经下线或价格策略被修改
  140. policy_object = models.PricePolicy.objects.get(id=_policy_id) # 价格策略对象
  141. course_object = policy_object.content_object # 课程对象
  142.  
  143. if course_object.id != _course_id:
  144. raise Exception('课程和价格策略对应失败')
  145. if course_object.status != 0:
  146. raise Exception('课程已下线,无法购买')
  147.  
  148. # 选择的优惠券是否在缓存中
  149. redis_coupon_list = redis_course['coupon_record_list']
  150. redis_coupon_record = None
  151. for item in redis_coupon_list:
  152. if item['id'] == _coupon_record_id:
  153. redis_coupon_record = item
  154. break
  155. if not redis_coupon_record:
  156. raise Exception('单课程优惠券在缓存中不存在')
  157.  
  158. # 计算购买原总价
  159. total_price += policy_object.price
  160.  
  161. # 未使用单课程优惠券
  162. if redis_coupon_record['id'] == 0:
  163. temp['price'] = policy_object.price
  164. buy_course_record.append(temp)
  165. continue
  166.  
  167. temp['original_price'] = policy_object.price
  168. temp['valid_period'] = redis_coupon_record['policy_valid_period']
  169. temp['period'] = redis_coupon_record['policy_period']
  170.  
  171. # 缓存中的优惠券是否已经过期
  172. begin_date = redis_coupon_record.get('begin_date')
  173. end_date = redis_coupon_record.get('end_date')
  174. if begin_date:
  175. if current_date < begin_date:
  176. raise Exception('优惠券使用还未到时间')
  177. if end_date:
  178. if current_date > end_date:
  179. raise Exception('优惠券已过期')
  180.  
  181. # 使用的是单课程优惠券抵扣了多少钱;使用的 个人优惠券ID
  182. if redis_coupon_record['type'] == 0:
  183. # 通用优惠券
  184. money = redis_coupon_record['money_equivalent_value']
  185. discount += money
  186. elif redis_coupon_record['type'] == 1:
  187. # 满减券
  188. money = redis_coupon_record['money_equivalent_value']
  189. minimum_consume = redis_coupon_record['minimum_consume']
  190. if policy_object.price >= minimum_consume:
  191. discount += money
  192. elif redis_coupon_record['type'] == 2:
  193. # 打折券
  194. money = policy_object.price * redis_coupon_record['off_percent']
  195. discount += money
  196.  
  197. temp['price'] = policy_object.price - money
  198. buy_course_record.append(temp)
  199. use_coupon_record_id_list.append(redis_coupon_record['id'])
  200.  
  201. # 全局优惠券
  202. print(global_coupon_record)
  203. begin_date = global_coupon_record.get('begin_date')
  204. end_date = global_coupon_record.get('end_date')
  205. if begin_date:
  206. if current_date < begin_date:
  207. raise Exception('优惠券使用还未到时间')
  208. if end_date:
  209. if current_date > end_date:
  210. raise Exception('优惠券已过期')
  211.  
  212. # 使用全局优惠券抵扣了多少钱
  213. if global_coupon_record.get('type') == 0:
  214. # 通用优惠券
  215. money = global_coupon_record['money_equivalent_value']
  216. discount += money
  217. elif global_coupon_record.get('type') == 1:
  218. # 满减券
  219. money = global_coupon_record['money_equivalent_value']
  220. minimum_consume = global_coupon_record['minimum_consume']
  221. if (total_price - discount) >= minimum_consume:
  222. discount += money
  223. elif global_coupon_record.get('type') == 2:
  224. # 打折券
  225. money = (total_price - discount) * global_coupon_record['off_percent']
  226. discount += money
  227.  
  228. # 贝里抵扣的钱
  229. if balance:
  230. discount += balance
  231.  
  232. if (alipay + discount) != total_price:
  233. raise Exception('总价、优惠券抵扣、贝里抵扣和实际支付的金额不符')
  234.  
  235. # 创建订单 + 支付宝支付
  236. # 创建订单详细
  237. # 贝里抵扣 + 贝里记录
  238. # 优惠券状态更新
  239. actual_amount = 0
  240. if alipay:
  241. payment_type = 1 # 支付宝
  242. actual_amount = alipay
  243. elif balance:
  244. payment_type = 3 # 贝里
  245. else:
  246. payment_type = 2 # 优惠码
  247.  
  248. with transaction.atomic():
  249. order_num = generate_order_num()
  250. if payment_type == 1:
  251. order_object = models.Order.objects.create(
  252. payment_type=payment_type,
  253. order_number=order_num,
  254. account=request.user,
  255. actual_amount=actual_amount,
  256. status=1, # 待支付
  257. )
  258. else:
  259. order_object = models.Order.objects.create(
  260. payment_type=payment_type,
  261. order_number=order_num,
  262. account=request.user,
  263. actual_amount=actual_amount,
  264. status=0, # 支付成功,优惠券和贝里已够支付
  265. pay_time=current_datetime
  266. )
  267.  
  268. for item in buy_course_record:
  269.  
  270. detail = models.OrderDetail.objects.create(
  271. order=order_object,
  272. content_object=models.Course.objects.get(id=item['course_id']),
  273. original_price=item['original_price'],
  274. price=item['price'],
  275. valid_period_display=item['period'],
  276. valid_period=item['valid_period']
  277. )
  278. models.Account.objects.filter(id=request.user.id).update(balance=F('balance') - balance)
  279. models.TransactionRecord.objects.create(
  280. account=request.user,
  281. amount=request.user.balance,
  282. balance=request.user.balance - balance,
  283. transaction_type=1,
  284. content_object=order_object,
  285. transaction_number=generate_transaction_num()
  286. )
  287. effect_row = models.CouponRecord.objects.filter(id__in=use_coupon_record_id_list).update(
  288. order=order_object,
  289. used_time=current_datetime)
  290.  
  291. if effect_row != len(use_coupon_record_id_list):
  292. raise Exception('优惠券使用失败')
  293.  
  294. response['payment_type'] = payment_type
  295. # 生成支付宝URL地址
  296. if payment_type == 1:
  297. pay = AliPay(debug=True)
  298. query_params = pay.direct_pay(
  299. subject="路飞学城", # 商品简单描述
  300. out_trade_no=order_num, # 商户订单号
  301. total_amount=actual_amount, # 交易金额(单位: 元 保留俩位小数)
  302. )
  303. pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params)
  304.  
  305. response['pay_url'] = pay_url
  306.  
  307. except IndentationError as e:
  308. response['code'] = 1001
  309. response['msg'] = str(e)
  310.  
  311. return Response(response)

06 路飞学城之后续计划

6.1 后续计划

07 Flask框架简介和快速使用

7.1 Flask Web框架;

7.1.1 Flask的上下文管理;

7.1.2 谈谈你对Python相关的Web框架的理解;

  • Django:大而全,重武器,内部提供:ORM、Admin、中间件、Form、ModelForm、Session、缓存、信号、CSRF;
  • Flask:短小精悍,可拓展强,http://flask.pocoo.org/ 
  • Tornado,短小精悍,可拓展性较之Flask弱一些,但优点是:异步非阻塞;
  • Web.py:比较老的Web框架;
  • bottle.py:微小,1000行左右;
  • Django的请求过来先走wsgiref,然后middleware;
  • Flask中的WSGI是Werkzurg;

7.2 如何证明Flask内部是Werkzeug

  7.2.1 Flask的路由是装饰器;

  1. # -*- coding:utf-8 -*-
  2. # Project: FlaskFull
  3. # Software: PyCharm
  4. # Time : 2018-09-17 10:12
  5. # File : s2.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask
  10.  
  11. app = Flask(__name__)
  12.  
  13. @app.route('/index/')
  14. def index():
  15. return 'Hello World!'
  16.  
  17. if __name__ == '__main__':
  18. app.run()#run_simple(host,port,app)

08 FLask框架之用户管理系统示例(一)

8.1 Flask框架之用户登录程序;

8.2 使用Pycharm安装Flask;

  1. from flask import Flask, render_template, request, redirect, session
  2.  
  3. app = Flask(__name__, template_folder='templates')
  4. # 基于app这个对象设置secret_key的值,任意设置!
  5. app.secret_key = 'nishifdalkj4389!@#$28908'
  6.  
  7. @app.route('/login/', methods=['GET', 'POST'])
  8. def hello_world():
  9. # return 'Hello World!'
  10. if request.method == "GET":
  11. return render_template('login.html')
  12. user = request.form.get('usr')
  13. pwd = request.form.get('pwd')
  14. if user == 'cuixiaozhao' and pwd == '':
  15. # 将用户信息放入session;
  16. session['user_info'] = user
  17. """
  18. RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
  19. 127.0.0.1 - - [17/Sep/2018 21:02:04] "POST /login/ HTTP/1.1" 500 -
  20. """
  21. return redirect('/index/')
  22. else:
  23. # 两种传值方法均可,比Django灵活一些;
  24. # return render_template('login.html', msg='用户名或者密码错误!')
  25. return render_template('login.html', **{'msg': '用户名或者密码错误!'})
  26.  
  27. @app.route('/index/')
  28. def index():
  29. user_info = session.get('user_info')
  30. if not user_info:
  31. return redirect('/login/')
  32. else:
  33. return '欢迎登陆!'
  34.  
  35. @app.route('/logout/')
  36. def logout():
  37. del session['user_info']
  38. return redirect('/login/')
  39.  
  40. if __name__ == '__main__':
  41. app.run()

09 Flask框架之用户管理系统示例(二)

9.1 Flask框架用户登录示例二;

  1. from flask import Flask, render_template, request, redirect, session
  2.  
  3. app = Flask(__name__, template_folder='templates')
  4. # 基于app这个对象设置secret_key的值,任意设置!
  5. app.secret_key = 'nishifdalkj4389!@#$28908'
  6. app.debug = True
  7. USER_DICT = {
  8. '': {'name': '志军', 'age': 18},
  9. '': {'name': '大伟', 'age': 48},
  10. '': {'name': '美凯', 'age': 38}
  11. }
  12.  
  13. @app.route('/login/', methods=['GET', 'POST'])
  14. def hello_world():
  15. # return 'Hello World!'
  16. if request.method == "GET":
  17. return render_template('login.html')
  18. user = request.form.get('usr')
  19. pwd = request.form.get('pwd')
  20. if user == 'cuixiaozhao' and pwd == '':
  21. # 将用户信息放入session;
  22. session['user_info'] = user
  23. """
  24. RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
  25. 127.0.0.1 - - [17/Sep/2018 21:02:04] "POST /login/ HTTP/1.1" 500 -
  26. """
  27. return redirect('/index/')
  28. else:
  29. # 两种传值方法均可,比Django灵活一些;
  30. # return render_template('login.html', msg='用户名或者密码错误!')
  31. return render_template('login.html', **{'msg': '用户名或者密码错误!'})
  32.  
  33. @app.route('/index/')
  34. def index():
  35. user_info = session.get('user_info')
  36. if not user_info:
  37. return redirect('/login/')
  38. return render_template('index.html', user_dict=USER_DICT)
  39.  
  40. @app.route('/detail/')
  41. def detail():
  42. user_info = session.get('user_info')
  43. if not user_info:
  44. return redirect('/login/')
  45. uid = request.args.get('uid')
  46. info = USER_DICT.get(uid)
  47. return render_template('detail.html', info=info)
  48.  
  49. @app.route('/logout/')
  50. def logout():
  51. del session['user_info']
  52. return redirect('/login/')
  53.  
  54. if __name__ == '__main__':
  55. app.run()

10 homework

10.1 Flask装饰器、位置、url起个别名;

10.2 类似于Django中间件的东西,before_request装饰器;

10.3 上下文管理预习;

  • threading.local;

  • functools.wrappers;

  • functools.partial;

  • 面向对象中——__setarrt__;__getattr__;__delatrr__;

第2章 章节二

01 内容概要

1.1 配置文件;

1.2 路由

1.3 视图函数

1.4 请求和响应

1.5 templates模板

1.6 session(默认存储的签名的cookies中)

1.7 flash闪现

1.8 蓝图blueprint

1.9 常见的装饰器before_request

1.10 Flask中间件

02 内容回顾

2.1 装饰器;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 10:45
  5. # File : 1.装饰器.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. import functools
  10. def wapper(func):
  11. @functools.wraps(func)
  12. def inner(*args,**kwargs):
  13. return func(*args,**kwargs)
  14. return inner
  15. '''
  16. 1、执行wapper函数,并将被装饰的函数当做参数。wapper(index)
  17. 2、将第一步的返回值,重新赋值给index = wapper(old index)
  18.  
  19. '''
  20.  
  21. #1、为什么要使用装饰器?在不改变原来函数的基础之上,对函数执行前后进行自定义操作;
  22. @wapper
  23. def index(a1):
  24. return a1 +1000
  25.  
  26. v = index(2)
  27. print(v)
  28. #获取函数名
  29. print("打印函数名:",index.__name__)
  30.  
  31. @wapper
  32. def order(a1):
  33. return a1+1000
  34.  
  35. print(index.__name__)
  36. print(order.__name__)

2.2 带参数的装饰器;

2.3 什么是面向对象,为什么要使用面向对象?

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 11:06
  5. # File : 3.面向对象.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. ""
  10. """
  11. 谈谈你对面向对象的认识?
  12. 封装:
  13. 将同一类方法分为一类,方法封装到类中;
  14. 将方法中的共同的参数封装到对象中,把共同的值封装到对象中;
  15. """
  16.  
  17. # 用户类实现;
  18. class File:
  19. def __init__(self, a1, a2, a3, a4):
  20. self.a1 = a1
  21. self.a2 = a2
  22. self.a3 = a3
  23. self.a4 = a4
  24.  
  25. def file_add(self):
  26. pass
  27.  
  28. def file_del(self):
  29. pass
  30.  
  31. def file_update(self):
  32. pass
  33.  
  34. def file_fetch(self):
  35. pass
  36.  
  37. # 给了一些值,将数据加工,应用场景:Django自定义分页;
  38. class Foo():
  39. def __init__(self, a1, a2, a3, a4, a5, a6, a7):
  40. self.a1 = a1
  41. self.a2 = a2
  42. self.a3 = a3
  43. self.a4 = a4
  44. self.a5 = a5
  45. self.a6 = a6
  46. self.a7 = a7
  47.  
  48. def sum(self):
  49. return self.a1 + self.a2
  50.  
  51. def reduce(self):
  52. return self.a5 - self.a7
  53.  
  54. obj = File(1, 2, 3, 4)
  55. print(obj) # <__main__.File object at 0x10bbf25c0>
  56.  
  57. class A(object):
  58. def __init__(self):
  59. self.age1 = 123
  60. self.a = A()
  61.  
  62. class B(object):
  63. def __init__(self):
  64. self.age2 = 123
  65. self.b = B()
  66.  
  67. class C(object):
  68. def __init__(self):
  69. self.age3 = 123
  70. self.c = C()
  71.  
  72. class D(object):
  73. def __init__(self):
  74. self.age4 = 123
  75. self.d = D()

03 Flask框架之配置

3.1 app.py;

  1. from flask import Flask, render_template, redirect
  2.  
  3. app = Flask(__name__)
  4. # Flask的配置文件这么玩耍;
  5. app.config.from_object("settings.DevelopmentConfig")#settings后面是一个类名;
  6.  
  7. @app.route('/index/', methods=['GET', 'POST'])
  8. def index():
  9. return 'Hello World!'
  10.  
  11. if __name__ == '__main__':
  12. app.run()

3.2 指定settings.py文件;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 11:25
  5. # File : settings.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. class BaseConfig(object):
  10. DEBUG = False
  11. TESTING = False
  12. DATABASE_URI = 'sqllite://:memory:'
  13.  
  14. class ProductionConfig(BaseConfig):
  15. DATABASE_URI = 'mysql://user@production/foo'
  16.  
  17. class DevelopmentConfig(BaseConfig):
  18. DEBUG = True
  19. DATABASE_URI = 'mysql://user@development/foo'
  20.  
  21. class TestingConfig(BaseConfig):
  22. DEBUG = True
  23. DATABASE_URI = 'mysql://user@test/foo'

3.3 Flask配置文件详解;

  1. flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
  2. {
  3. 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式;
  4. 'TESTING': False, 是否开启测试模式;
  5. 'PROPAGATE_EXCEPTIONS': None,
  6. 'PRESERVE_CONTEXT_ON_EXCEPTION': None,
  7. 'SECRET_KEY': None,
  8. 'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
  9. 'USE_X_SENDFILE': False,
  10. 'LOGGER_NAME': None,
  11. 'LOGGER_HANDLER_POLICY': 'always',
  12. 'SERVER_NAME': None,
  13. 'APPLICATION_ROOT': None,
  14. 'SESSION_COOKIE_NAME': 'session',
  15. 'SESSION_COOKIE_DOMAIN': None,
  16. 'SESSION_COOKIE_PATH': None,
  17. 'SESSION_COOKIE_HTTPONLY': True,
  18. 'SESSION_COOKIE_SECURE': False,
  19. 'SESSION_REFRESH_EACH_REQUEST': True,
  20. 'MAX_CONTENT_LENGTH': None,
  21. 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
  22. 'TRAP_BAD_REQUEST_ERRORS': False,
  23. 'TRAP_HTTP_EXCEPTIONS': False,
  24. 'EXPLAIN_TEMPLATE_LOADING': False,
  25. 'PREFERRED_URL_SCHEME': 'http',
  26. 'JSON_AS_ASCII': True,
  27. 'JSON_SORT_KEYS': True,
  28. 'JSONIFY_PRETTYPRINT_REGULAR': True,
  29. 'JSONIFY_MIMETYPE': 'application/json',
  30. 'TEMPLATES_AUTO_RELOAD': None,
  31. }
  32.  
  33. 方式一:
  34. app.config['DEBUG'] = True
  35.  
  36. PS 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
  37.  
  38. 方式二:
  39. app.config.from_pyfile("python文件名称")
  40. 如:
  41. settings.py
  42. DEBUG = True
  43.  
  44. app.config.from_pyfile("settings.py")
  45.  
  46. app.config.from_envvar("环境变量名称")
  47. 环境变量的值为python文件名称名称,内部调用from_pyfile方法
  48.  
  49. app.config.from_json("json文件名称")
  50. JSON文件名称,必须是json格式,因为内部会执行json.loads
  51.  
  52. app.config.from_mapping({'DEBUG':True})
  53. 字典格式
  54.  
  55. app.config.from_object("python类或类的路径")
  56.  
  57. app.config.from_object('pro_flask.settings.TestingConfig')
  58.  
  59. settings.py
  60.  
  61. class Config(object):
  62. DEBUG = False
  63. TESTING = False
  64. DATABASE_URI = 'sqlite://:memory:'
  65.  
  66. class ProductionConfig(Config):
  67. DATABASE_URI = 'mysql://user@localhost/foo'
  68.  
  69. class DevelopmentConfig(Config):
  70. DEBUG = True
  71.  
  72. class TestingConfig(Config):
  73. TESTING = True
  74.  
  75. PS: sys.path中已经存在路径开始写;
  76.  
  77. PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_configTrue,则就是instance_path目录;

04 Flask框架之创建路由的两种方式

4.1 基于@app.route('/index/', methods=['GET', 'POST'])装饰器方式实现;

4.2 通过研究源代码,基于app.add_url_rule('/order/', view_func=order)实现;

  1. from flask import Flask, render_template, redirect
  2.  
  3. app = Flask(__name__)
  4. # Flask的配置文件这么玩耍;
  5. app.config.from_object("settings.DevelopmentConfig")
  6.  
  7. # 添加的第一种方式,推荐使用装饰器的方式;
  8. @app.route('/index/', methods=['GET', 'POST'])
  9. def index():
  10. return '# 添加的第一种方式,推荐使用装饰器的方式;'
  11.  
  12. # 添加路由的另外一种方式;
  13.  
  14. def order():
  15. return '# 添加路由的第二种方式;'
  16.  
  17. app.add_url_rule('/order/', view_func=order)
  18. if __name__ == '__main__':
  19. app.run()
  20.  
  21. if __name__ == '__main__':
  22. app.run()

05 Flask框架之反向生成URL

5.1 Flask框架之反向生成URL,(url_for,endpoint)

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 12:06
  5. # File : 4.反向生成URL.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask, render_template, redirect, url_for
  10.  
  11. app = Flask(__name__)
  12.  
  13. # endpoint&url_for不起别名默认就是函数名;
  14. @app.route('/index/', methods=['GET', 'POST'])
  15. def index():
  16. v1 = url_for('n1')
  17. # v2 = url_for('n1')
  18. # v2 = url_for('n2')
  19. v2 = url_for('login')
  20. v3 = url_for('logout')
  21. print(v1, v2, v3)
  22. return 'Index'
  23.  
  24. @app.route('/login/', methods=['GET', 'POST'], endpoint='n2')
  25. def login():
  26. return 'Login'
  27.  
  28. @app.route('/logout/', methods=['GET', 'POST'], endpoint='n3')
  29. def logout():
  30. return 'Logout'

06 Flask框架之自定义路由转换器

6.1 Flask之自定义路由转换器;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 19:14
  5. # File : 6.Flask框架之app.route参数.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask
  9.  
  10. app = Flask(__name__)
  11.  
  12. # 从旧功能重定向至新功能页面;Js可以做重定向;meta头、js location href
  13. @app.route('/index/', methods=['GET', 'POST'], redirect_to='/new/')
  14. def index():
  15. return '旧的功能'
  16.  
  17. @app.route('/new/', methods=['GET', 'POST'])
  18. def new():
  19. return '新功能'
  20.  
  21. if __name__ == '__main__':
  22. app.run()

6.2 常见的路由系统;

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')
  • @app.route('/post/<path:path>')
  • @app.route('/login', methods=['GET', 'POST'])
  1. DEFAULT_CONVERTERS = {
  2. 'default': UnicodeConverter,
  3. 'string': UnicodeConverter,
  4. 'any': AnyConverter,
  5. 'path': PathConverter,
  6. 'int': IntegerConverter,
  7. 'float': FloatConverter,
  8. 'uuid': UUIDConverter,
  9. }
  1. def auth(func):
  2. def inner(*args, **kwargs):
  3. print('before')
  4. result = func(*args, **kwargs)
  5. print('after')
  6. return result
  7.  
  8. return inner
  9.  
  10. @app.route('/index.html',methods=['GET','POST'],endpoint='index')
  11. @auth
  12. def index():
  13. return 'Index'
  14.  
  15.  
  16. def index():
  17. return "Index"
  18.  
  19. self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
  20. or
  21. app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
  22. app.view_functions['index'] = index
  23.  

  24. def auth(func):
  25. def inner(*args, **kwargs):
  26. print('before')
  27. result = func(*args, **kwargs)
  28. print('after')
  29. return result
  30.  
  31. return inner
  32.  
  33. class IndexView(views.View):
  34. methods = ['GET']
  35. decorators = [auth, ]
  36.  
  37. def dispatch_request(self):
  38. print('Index')
  39. return 'Index!'
  40.  
  41. app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint
  42.  
  43.  
  44. class IndexView(views.MethodView):
  45. methods = ['GET']
  46. decorators = [auth, ]
  47.  
  48. def get(self):
  49. return 'Index.GET'
  50.  
  51. def post(self):
  52. return 'Index.POST'
  53.  
  54. app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint
  55.  
  56. @app.routeapp.add_url_rule参数:
  57. rule, URL规则
  58. view_func, 视图函数名称
  59. defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
  60. endpoint=None, 名称,用于反向生成URL,即: url_for('名称')
  61. methods=None, 允许的请求方式,如:["GET","POST"]
  62.  
  63. strict_slashes=None, URL最后的 / 符号是否严格要求,
  64. 如:
  65. @app.route('/index',strict_slashes=False),
  66. 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
  67. @app.route('/index',strict_slashes=True)
  68. 仅访问 http://www.xx.com/index
  69. redirect_to=None, 重定向到指定地址
  70. 如:
  71. @app.route('/index/<int:nid>', redirect_to='/home/<nid>')

  72. def func(adapter, nid):
  73. return "/home/888"
  74. @app.route('/index/<int:nid>', redirect_to=func)
  75. subdomain=None, 子域名访问
  76. from flask import Flask, views, url_for
  77.  
  78. app = Flask(import_name=__name__)
  79. app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
  80.  
  81. @app.route("/", subdomain="admin")
  82. def static_index():
  83. """Flask supports static subdomains
  84. This is available at static.your-domain.tld"""
  85. return "static.your-domain.tld"
  86.  
  87. @app.route("/dynamic", subdomain="<username>")
  88. def username_index(username):
  89. """Dynamic subdomains are also supported
  90. Try going to user1.your-domain.tld/dynamic"""
  91. return username + ".your-domain.tld"
  92.  
  93. if __name__ == '__main__':
  94. app.run()
  95.  
  96. a.注册路由原理

07 Flask框架之app.route参数

7.1 app.route的常见参数;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 19:14
  5. # File : 4.Flask框架之app.route参数.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask
  9.  
  10. app = Flask(__name__)
  11.  
  12. # 从旧功能重定向至新功能页面;Js可以做重定向;meta头、js location href
  13. @app.route('/index/', methods=['GET', 'POST'], redirect_to='/new/')
  14. def index():
  15. return '旧的功能'
  16.  
  17. @app.route('/new/', methods=['GET', 'POST'])
  18. def new():
  19. return '新功能'
  20.  
  21. if __name__ == '__main__':
  22. app.run()

8 Flask框架之获取子域名的路由

8.1 域名解析之A记录;

8.2 本地域名映射之hosts文件;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 19:14
  5. # File : 7.Flask框架之获取子域名.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask
  9.  
  10. app = Flask(__name__)
  11. app.config['SERVER_NAME'] = 'www.cuixiaozhao.com:5000'
  12.  
  13. # 从旧功能重定向至新功能页面;Js可以做重定向;meta头、js location href
  14. @app.route('/dynamic/', methods=['GET', 'POST'], subdomain='<username>')
  15. def sub_domain(username):
  16. print(username)
  17. return '旧的功能1'
  18.  
  19. if __name__ == '__main__':
  20. app.run()

09 上述内容总结

9.1 url;

9.2 methods;

9.3 endpoint;

9.4 @app.route('/index/<int:nid1>/<int:nid2>');

9.5 url_for;

10 Flask框架之视图中添加装饰器

10.1 Flask框架中添加装饰器的注意事项;

  • @装饰器的顺序

  • 引入functools

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 19:14
  5. # File : 8.添加装饰器.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask
  9. import functools
  10.  
  11. app = Flask(__name__)
  12.  
  13. def wapper(func):
  14. @functools.wraps(func)
  15. def inner(*args, **kwargs):
  16. print('before')
  17. return func(*args, **kwargs)
  18.  
  19. return inner
  20.  
  21. @app.route('/xxxx/', methods=['GET', 'POST'])
  22. @wapper
  23. def index():
  24. return 'Index'
  25.  
  26. @app.route('/xxxx/', methods=['GET', 'POST'])
  27. @wapper
  28. def order():
  29. return 'Order'
  30.  
  31. if __name__ == '__main__':
  32. app.run()

11 Flask框架之CBV和FBV

11.1 CBV与FBV;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 21:57
  5. # File : 9.Flask框架之CBV和FBV.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask, redirect, render_template, views
  9.  
  10. app = Flask(__name__)
  11. import functools
  12.  
  13. def wapper(func):
  14. @functools.wraps(func)
  15. def inner(*args, **kwargs):
  16. print('before')
  17. return func(*args, **kwargs)
  18.  
  19. return inner
  20.  
  21. @app.route('/xxx/', methods=['GET', 'POST'])
  22. @wapper
  23. def index():
  24. return 'Index'
  25.  
  26. class IndexView(views.View):
  27. methods = ['GET']
  28. decorators = [wapper, ]
  29.  
  30. def dispatch_request(self):
  31. print('Index')
  32. return 'Index'
  33.  
  34. app.add_url_rule('/index/', view_func=IndexView.as_view(name='index')) # name == endpoint
  35.  
  36. # CBV方式;
  37. class IndexView(views.MethodView):
  38. methods = ['GET']
  39. decorators = [wapper]
  40.  
  41. def get(self):
  42. return 'Index.GET'
  43.  
  44. def post(self):
  45. return 'Index POST'
  46.  
  47. app.add_url_rule('/index/', view_func=IndexView.as_view(name='index')) # name = endpoint
  48.  
  49. if __name__ == '__main__':
  50. app.run()

12 Flask框架之请求和响应相关

12.1 Flask请求相关之request.xxx;

12.2 Flask响应相关之return和response;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 22:13
  5. # File : 12.请求和响应.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask, render_template, request, redirect, jsonify, make_response
  10.  
  11. app = Flask(__name__)
  12.  
  13. app.config.from_object("settings.DevelopmentConfig")
  14.  
  15. @app.route('/index/', methods=['GET', 'POST'])
  16. def index():
  17. # 请求相关;
  18. request.args
  19.  
  20. # 响应相关;
  21. return ''
  22. return render_template()
  23. return redirect('/index/')
  24. # 返回json数据;
  25. return json.dumps({}) # return jsonify({})
  26.  
  27. if __name__ == '__main__':
  28. app.run()
  29. """
  30. # 请求相关信息;
  31. # request.method
  32. # request.args
  33. # request.form
  34. # request.values
  35. # request.cookies
  36. # request.headers
  37. # request.path
  38. # request.full_path
  39. # request.script_root
  40. # request.url
  41. # request.base_url
  42. # request.url_root
  43. # request.host_url
  44. # request.host
  45. # request.files
  46. # obj = request.files['the_file_name']
  47. # obj.save('/var/www/uploads/' + secure_filename(f.filename))
  48.  
  49. # 响应相关信息;
  50. # return "字符串"
  51. # return render_template('html模板路径',**{})
  52. # return redirect('/index.html')
  53.  
  54. # response = make_response(render_template('index.html'))
  55. # response是flask.wrappers.Response类型;
  56. # response.delete_cookie('key')
  57. # response.set_cookie('key', 'value')
  58. # response.headers['X-Something'] = 'A value'
  59. # return response
  60. """

13 Flask框架之模板引擎

13.1 Flask的templates模板;

13.2 通Django十分类似,具备block继承、extends;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-18 22:23
  5. # File : 13.模板.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask, render_template, redirect, jsonify, make_response, Markup
  9.  
  10. app = Flask(__name__)
  11.  
  12. # 全局模板——每个模板均可调用的函数;
  13. @app.template_global()
  14. def cxz(a1, a2):
  15. return a1 + a2
  16.  
  17. def input(value):
  18. return Markup("<input value:'%s'/>" % value)
  19.  
  20. def gen_input(value):
  21. return Markup("<input value:'%s'/>" % value)
  22.  
  23. @app.route('/computed/', methods=['GET', 'POST'])
  24. def computed():
  25. context = {
  26. 'k1': 123,
  27. 'k2': [11, 22, 33],
  28. 'k3': {'name': 'cuixiaozhao', 'age': 84},
  29. 'k4': lambda x: x + 1, # 用户写简单的函数;
  30. 'k5': gen_input
  31. }
  32. return render_template('index.html', **context)
  33.  
  34. if __name__ == '__main__':
  35. app.run()

layout.html;

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. </head>
  8. <body>
  9. <div>头部</div>
  10. <div>
  11. {% block content %}
  12. {% endblock %}
  13. </div>
  14. <div>底部</div>
  15. </body>
  16. </html>

indexx.html;

  1. {% extends 'layout.html' %}
  2.  
  3. {% block content %}
  4. <h1>{{ k1 }}</h1>
  5. <h1>{{ k2.0 }} {{ k2[0] }}</h1>
  6. <h1>{{ k3.name }} {{ k3['name'] }}{{ k3.get('name',19930911) }}</h1>
  7. <h1>{{ k4 }}</h1>
  8. <h1>{{ k5(99) }}</h1>
  9.  
  10. {% endblock %}

14 Flask框架之session使用和源码流程(一)

15 Flask框架之session使用和源码流程(二)

14.1 & 15.1 之session使用和源码;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 16:37
  5. # File : 1.Flask中的session.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. ""
  9. """
  10. Session的请求流程;
  11. 1、请求刚刚到达;
  12. 2、视图函数;
  13. 3、请求结果;
  14. """
  15. from flask import Flask, session
  16.  
  17. app = Flask(__name__)
  18.  
  19. app.secret_key = 'fdjljfaljfkla'
  20.  
  21. @app.route('/index/')
  22. def index():
  23. session['k1'] = 123
  24. return 'Index'
  25.  
  26. @app.route('/order/')
  27. def order():
  28. print(session['k1'])
  29. return 'Order'
  30.  
  31. if __name__ == '__main__':
  32. app.run()
  33. """
  34. 1、Flask
  35. 2、RequestContext
  36. 3、Request
  37. 4、SecureCookieSessionInterface
  38. 5、SecureCookieSession(dict )
  39. """

16 Flask框架之before_request和after_request(一)

16.1 Flask框架中的内置装饰器之before_request和after_request;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 17:22
  5. # File : 1.Flask中内置的特殊装饰器.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask, render_template, redirect
  9.  
  10. app = Flask(__name__)
  11.  
  12. # before_request和after_request类似于Django中的中间件middleware;
  13. @app.before_request
  14. def before_req():
  15. print('before_request,前')
  16.  
  17. @app.before_request
  18. def before_req1():
  19. print('before_request1,前')
  20.  
  21. # request之前,会添加一个reverse反转;
  22. @app.after_request
  23. def after_req(response):
  24. print('after_request, 后')
  25. return response
  26.  
  27. @app.after_request
  28. def after_req1(response):
  29. print('after_request1, 后')
  30. return response
  31.  
  32. @app.route('/x1/', methods=['GET', 'POST'])
  33. def x1():
  34. print('视图函数X1')
  35. return 'X1'
  36.  
  37. @app.route('/x2/', methods=['GET', 'POST'])
  38. def x2():
  39. print('视图函数X2')
  40. return 'X2'
  41.  
  42. if __name__ == '__main__':
  43. app.run()

17 Flask框架之after_request(二)

17.1 基于before_request的用户登录示例;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 17:22
  5. # File : 2.基于Flask中内置的特殊装饰器做登录验证.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask, render_template, redirect, request, session
  9.  
  10. app = Flask(__name__)
  11. app.secret_key = 'fdsjklfdjaslkjflas'
  12.  
  13. # before_request和after_request类似于Django中的中间件middleware;
  14. @app.before_request
  15. def check_login():
  16. if request.path == '/login/':
  17. return None
  18. user = session.get('user_info')
  19. if not user:
  20. return redirect('/login/')
  21.  
  22. @app.route('/login/', methods=['GET', 'POST'])
  23. def login():
  24. return 'Login'
  25.  
  26. @app.route('/index/', methods=['GET', 'POST'])
  27. def index():
  28. return 'Index'
  29.  
  30. if __name__ == '__main__':
  31. app.run()

18 Flask框架字号常见装饰器

18.1 Flask中其他常见的装饰器;

  • before_first_request
  • before_request
  • after_request
  • teardown_request
  • after_this_request
  • errorhandler(404)
  • ...
  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 17:44
  5. # File : 3.Flask中其他常见的装饰器.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8. from flask import Flask, Request, render_template
  9.  
  10. app = Flask(__name__, template_folder='templates')
  11. app.debug = True
  12.  
  13. @app.before_first_request
  14. def before_first_request1():
  15. print('before_first_request1')
  16.  
  17. @app.before_first_request
  18. def before_first_request2():
  19. print('before_first_request2')
  20.  
  21. @app.before_request
  22. def before_request1():
  23. Request.nnn = 123
  24. print('before_request1')
  25.  
  26. @app.before_request
  27. def before_request2():
  28. print('before_request2')
  29.  
  30. @app.after_request
  31. def after_request1(response):
  32. print('before_request1', response)
  33. return response
  34.  
  35. @app.after_request
  36. def after_request2(response):
  37. print('before_request2', response)
  38. return response
  39.  
  40. @app.errorhandler(404)
  41. def page_not_found(error):
  42. return 'This page does not exist', 404
  43.  
  44. @app.template_global()
  45. def sb(a1, a2):
  46. return a1 + a2
  47.  
  48. @app.template_filter()
  49. def db(a1, a2, a3):
  50. return a1 + a2 + a3
  51.  
  52. @app.route('/')
  53. def hello_world():
  54. return render_template('index.html')
  55.  
  56. if __name__ == '__main__':
  57. app.run()

19 上述内容总结

19.1小结:

  19.1.1配置文件

  19.1.2路由

  19.1.3视图之CBV(class-based views )&FBV(function base view)

  19.1.4request

  19.1.5response = make_response(...)

  19.1.6模板

  19.1.7session

  19.1.8常见的装饰器

20 Flask之闪现

20.1 Flask之消息闪现flask& get_flashed_messages;(内部原理基于session实现)

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 18:03
  5. # File : 1.Flask之消息闪现flush.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask, session, flash, get_flashed_messages
  10.  
  11. app = Flask(__name__)
  12. app.secret_key = 'fdjslkjflkafdaklfjdlakfj'
  13.  
  14. # # 生成session;
  15. # @app.route('/x1/', methods=['GET', 'POST'])
  16. # def login():
  17. # session['mgs'] = 'cuixiaozhao'
  18. # return '视图函数1'
  19. #
  20. #
  21. # # 销毁session;;
  22. # @app.route('/x2/', methods=['GET', 'POST'])
  23. # def index():
  24. # msg = session.pop('msg')
  25. # print(msg)
  26. # return '视图函数2'
  27. # 消息闪现之flask生成session;
  28. @app.route('/x1/', methods=['GET', 'POST'])
  29. def login():
  30. flash('cuixiaozhao', category='x1')
  31. flash('cuixiaozhao', category='x2')
  32. return '视图函数1'
  33.  
  34. # 消息闪现之flask销毁session;;
  35. @app.route('/x2/', methods=['GET', 'POST'])
  36. def index():
  37. data = get_flashed_messages(category_filter=['x1', 'x2'])
  38. print(data)
  39. return '视图函数2'
  40.  
  41. if __name__ == '__main__':
  42. app.run()

21 Flask中间件

21.1 Flask中自定义中间件;

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 18:13
  5. # File : 1.Flask之中间件.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask
  10.  
  11. app = Flask(__name__)
  12. app.secret_key = 'fjaljfdklajfkdasl'
  13.  
  14. @app.route('/x2', methods=['GET', 'POST'])
  15. def index():
  16. return 'x2'
  17.  
  18. class MiddleWare(object):
  19. def __init__(self, old_wsgi_app):
  20. self.old_wsgi_app = old_wsgi_app
  21.  
  22. def __call__(self, *args, **kwargs):
  23. print('before')
  24. obj = self.old_wsgi_app(*args, **kwargs)
  25. print('after')
  26. return obj
  27.  
  28. if __name__ == '__main__':
  29. app.wsgi_app = MiddleWare(app.wsgi_app)
  30. app.run()
  31. """
  32. 1、执行app.__call__方法;
  33. 2、在调用app.wsgi_app方法;
  34. """

22 Flask框架之蓝图(一)

  简单来说,Blueprint 是一个存储操作方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:

  • 一个应用可以具有多个Blueprint;
  • 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名;
  • 在一个应用中,一个模块可以注册多次;
  • Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的;
  • 在一个应用初始化时,就应该要注册需要使用的Blueprint;

22.1 创建Flask项目ProFlask;

22.2 自定义文件存储目录;

__init__.py;

  1. from flask import Flask
  2.  
  3. app = Flask(__name__)
  4.  
  5. # @app.route('/index/')
  6. # def index():
  7. # pass
  8.  
  9. from .views import account
  10. from .views import admin
  11. from .views import user
  12.  
  13. app.register_blueprint(account.ac)
  14. app.register_blueprint(admin.ad)
  15. app.register_blueprint(user.us)

accounts.py;

  1. # -*- coding:utf-8 -*-
  2. # Project: Pro_Flask
  3. # Software: PyCharm
  4. # Time : 2018-09-19 19:08
  5. # File : account.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from flask import Flask, render_template
  10. # 蓝图Blueprint;
  11. from flask import Blueprint
  12.  
  13. ac = Blueprint('ac', __name__)
  14.  
  15. @ac.route('/login/')
  16. def login():
  17. #return 'Login'
  18. return render_template('login.html')
  19.  
  20. @ac.route('/logout/')
  21. def logout():
  22. return 'Logout' 

23 Flask框架之蓝图(二)

23.1 蓝图的三大作用(相当于Django中的app);

  • 目录结构的划分;
  • URL的划分;
  • 给每一类URL添加before_request

24 拓展知识:pipreqs工具

24.1 项目依赖;

24.2 拿到代码启动不起来;

24.3 pip3 install pipreqs;(自动查找项目所需要的依赖包及版本号);

24.4 pipreqs ./ --force 强制生成依赖文件;

24.5 pip3 install -i requirements.txt 安装依赖文件;

25 拓展知识:函数和方法

25.1 什么是函数?

25.2 什么是方法?

  1. # -*- coding:utf-8 -*-
  2. # Project: Day123
  3. # Software: PyCharm
  4. # Time : 2018-09-19 20:40
  5. # File : 1.函数和方法的区别.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from types import MethodType, FunctionType
  10.  
  11. class Foo(object):
  12. def fetch(self):
  13. pass
  14.  
  15. print(isinstance(Foo.fetch, MethodType)) # False
  16. print(isinstance(Foo.fetch, FunctionType)) # True
  17.  
  18. obj = Foo()
  19. print(obj.fetch) # <bound method Foo.fetch of <__main__.Foo object at 0x10bbf2358>>
  20. print(isinstance(obj.fetch, MethodType)) # False
  21. print(isinstance(Foo.fetch, FunctionType)) # True
  22. """
  23. 类、对象、方法、函数可以➕();
  24. 方法和函数的区别:被谁来调用!
  25. """

第3章 章节三

01 内容概要

1.1 Flask提升逼格的时候;

1.2 Flask的上下文管理;

1.3 threading.local;

1.4 数据库连接池;

02 内容回顾

2.1 常用的Linux命令(100+);

2.2 常见算法搞定;

2.3 数据库连接池;

2.4 面向对象的特殊方法;

  • call;
  • new;
  • and;
  • equal;
  • next;
  • dict;

2.5 functools;

  • functools.partial();
  • 装饰器的应用场景;-Flask路由以及before_request、登录认证、Django缓存\CSRF_TOKEN;

2.6 Flask中的蓝图Blueprint;

2.7 Flask中的session;

03 threading.local学习

3.1 threading.local初识;

  1. # -*- coding:utf-8 -*-
  2. # Project: Threading
  3. # Software: PyCharm
  4. # Time : 2018-09-19 22:40
  5. # File : 1.ThreadingLocal.py
  6. # Author : 天晴天朗
  7. # Email : tqtl@tqtl.org
  8.  
  9. from threading import local
  10. from threading import Thread
  11. import time
  12.  
  13. # 特殊的对象;
  14. xiaozhao = local()
  15.  
  16. # xiaozhao = -1
  17.  
  18. def task(arg):
  19. # global xiaozhao
  20.  
  21. xiaozhao.value = arg
  22. time.sleep(2)
  23. print(xiaozhao.value)
  24.  
  25. for i in range(10):
  26. t = Thread(target=task, args=(i,))
  27. t.start()

04 自定义Local思路

05 自定义Local对象(基于函数)

5.1 基于get_ident实现;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:11
  6. # File : 3.自定义Local对象(基于函数).py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. from threading import get_ident, Thread
  11. import time
  12.  
  13. storage = {}
  14.  
  15. def set(k, v):
  16. ident = get_ident()
  17. if ident in storage:
  18. storage[ident][k] = v
  19. storage[ident] = {k: v}
  20.  
  21. def get(k):
  22. ident = get_ident()
  23. return storage[ident][k]
  24.  
  25. def task(arg):
  26. set('val', arg)
  27. print(storage)
  28. time.sleep(2)
  29. v = get('val')
  30. print(v)
  31.  
  32. for i in range(10):
  33. t = Thread(target=task, args=(i,))
  34. t.start()

06 自定义Local对象(基于面向对象)

6.1 基于面向对象basic;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:20
  6. # File : 4.自定义Local对象(基于面向对象).py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from threading import get_ident
  10. from threading import Thread
  11.  
  12. class Local(object):
  13. storage = {}
  14.  
  15. def set(self, k, v):
  16. ident = get_ident()
  17. if ident in Local.storage:
  18. Local.storage[ident][k] = v
  19. else:
  20. Local.storage[ident] = {k: v}
  21.  
  22. def get(self, k):
  23. ident = get_ident()
  24. return Local.storage[ident][k]
  25.  
  26. obj = Local()
  27. def task(arg):
  28. obj.set('val', arg)
  29. v = obj.get('val')
  30. print(v)
  31.  
  32. for i in range(10):
  33. t = Thread(target=task, args=(i,))
  34. t.start()

6.2 基于面向对象优化版;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:20
  6. # File : 5.自定义Local对象(基于面向对象优化版 ).py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from threading import get_ident
  10. from threading import Thread
  11.  
  12. class Local(object):
  13.  
  14. def __setattr__(self, k, v):
  15. # self.storage = {}
  16. object.__setattr__(self, 'storage', {})
  17. ident = get_ident()
  18. if ident in self.storage:
  19. self.storage[ident][k] = v
  20. else:
  21. self.storage[ident] = {k: v}
  22.  
  23. def __getattr__(self, item):
  24. ident = get_ident()
  25. return self.storage[ident][item]
  26.  
  27. obj = Local()
  28. obj1 = Local()
  29.  
  30. def task(arg):
  31. obj.val = arg
  32. obj1.val = arg
  33. print(obj.val)
  34.  
  35. for i in range(10):
  36. t = Thread(target=task, args=(i,))
  37. t.start()

6.3 基于面向对象升级版;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:20
  6. # File : 4.自定义Local对象(基于面向对象).py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from threading import get_ident
  10. from threading import Thread
  11.  
  12. class Local(object):
  13. storage = {}
  14.  
  15. def __setattr__(self, k, v):
  16. ident = get_ident()
  17. if ident in Local.storage:
  18. Local.storage[ident][k] = v
  19. else:
  20. Local.storage[ident] = {k: v}
  21.  
  22. def __getattr__(self, item):
  23. ident = get_ident()
  24. return Local.storage[ident][item]
  25.  
  26. obj = Local()
  27.  
  28. def task(arg):
  29. obj.val = arg
  30. print(obj.val)
  31.  
  32. for i in range(10):
  33. t = Thread(target=task, args=(i,))
  34. t.start()

6.4 基于面向对象greenlet版本;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:20
  6. # File : 7.自定义Local对象(基于greenlet).py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. try:
  11. from greenlet import getcurrent as get_ident
  12. except Exception as e:
  13. from threading import get_ident
  14. from threading import Thread
  15.  
  16. class Local(object):
  17. storage = {}
  18.  
  19. def __setattr__(self, k, v):
  20. ident = get_ident()
  21. if ident in Local.storage:
  22. Local.storage[ident][k] = v
  23. else:
  24. Local.storage[ident] = {k: v}
  25.  
  26. def __getattr__(self, item):
  27. ident = get_ident()
  28. return Local.storage[ident][item]
  29.  
  30. obj = Local()
  31.  
  32. def task(arg):
  33. obj.val = arg
  34. print(obj.val)
  35.  
  36. for i in range(10):
  37. t = Thread(target=task, args=(i,))
  38. t.start()

07 Flask上下文管理之本质分析

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Threading
  4. # Software: PyCharm
  5. # Time : 2018-09-20 09:45
  6. # File : 1.Flask源码分析上下文管理.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from flask import Flask
  10.  
  11. app = Flask(__name__)
  12.  
  13. @app.route('/')
  14. def hello_world():
  15. return 'cuixiaozhao!'
  16.  
  17. if __name__ == '__main__':
  18. app.__call__
  19. app.run()
  20.  
  21. ""
  22. """
  23. 1、第一个阶段:将ctx(request,session)放到Local对象;
  24. 2、第二阶段:视图函数导入:request、session;
  25. 3、请求处理完毕:
  26. -获取session并保存到cookie;
  27. -将ctx删除;
  28. """

08 Flask上下文管理之请求到处理阶段

8.1 Flask中的session是何时创建何时销毁的?request_context,localstack、local;

09 Flask上下文管理之视图调用阶段

9.1 调用阶段;

10 Flask上下文管理之视图调动阶段和结束阶段

10.1 视图调用阶段和结束阶段;

11 问题来了

11.1 Flask中一共有几个Local和Local对象?

都是2个;

12 Flask中的g到底是什么呢?生命周期?

12.1 Flask的g对象范围;

13 内容补充:面向对象的私有字段

13.1 私有字段不建议去调动;

  • obj = Foo()
  • obj._Foo_age(类名前加下划线)

14 homework

14.1 按照组为单位,画图-类的调用关系图;

第4章 章节四

01 内容概要

1.1 flask-session;

1.2 单独模块-数据库连接池DBUtils;

1.3 原生SQL(基于pymysql)还是ORM好?!

1.4 wtforms(任何Django框架都可使用);

1.5 SQLAchemy、flask-sqlachemy;

1.6 flask-script;

1.7 flask-migrate;

02 内容回顾

2.1 谈谈Django和Flask的认识?

2.2 Django的上下文管理机制?

2.3 ctx = RequestContext(request,session)

2.4 Local对象的作用?

  • 看过Local源码,和Threading.local相似但又有不同之处;
  • 不同之处在于,Local中基于greenlet获取唯一表示,颗粒度更细;

2.5 为什么使用Localstack?对Local对象中的数据进行操作。

2.6 上下文管理分为两个-请求上下文和App上下文

2.7 什么是g?一次请求周期内的全局变量。

2.8 获取session和g的流程。

2.9 Flask中的技术点。

  • 反射;
  • 面向对象-封装、继承和多态;
  • __dict__;
  • 线程相关的东西-threading.local;
  • 自己写一个类+列表,实现一个栈(基于Localstack实现栈);

03 路飞学城补充:视频播放授权

4.1 CC视频播放授权;

04 flask-session组件使用和原理(一)

4.1 flask-session;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 16:14
  6. # File : 1.flask_session.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from flask import Flask, session
  10. from flask_session import RedisSessionInterface
  11.  
  12. app = Flask(__name__)
  13. app.secret_key = 'fdahfdafdajfalk'
  14.  
  15. # 默认session保存操作;
  16. # from flask.sessions import SecureCookieSessionInterface
  17.  
  18. # app.session_interface = SecureCookieSessionInterface()
  19.  
  20. # 使用Redis保存session;
  21. from flask.ext.session import Session
  22. from redis import Redis
  23.  
  24. app.config['SESSION_TYPE'] = 'redis'
  25. app.config['SESSION_REDIS'] = Redis(host='192.168.0.94', port='')
  26. app.session_interface = RedisSessionInterface(
  27. redis=Redis(host='127.0.0.1', port=6379),
  28. key_prefix='flaskxxxx'
  29.  
  30. )
  31.  
  32. @app.route('/login/')
  33. def login():
  34. session['k1'] = 123
  35. return 'Login'
  36.  
  37. @app.route('/index/')
  38. def index():
  39. v = session['k1']
  40. print(v)
  41. return 'Index'
  42.  
  43. if __name__ == '__main__':
  44. app.run()

05 flask-session组件使用和原理(二)

5.1 原理难,实现的机制难,使用起来比较容易,但是要想学好, 必须懂原理;

5.2 MTV 和MVC设计模式;

  • MTV-Model、Templates、View;
  • MVC-Model、View、Controller;

5.3 自定义Flask项目Flask_Session;

__init__.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 16:46
  6. # File : __init__.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from flask import Flask
  10. from .views import account
  11. from .views import home
  12.  
  13. def create_app():
  14. app = Flask(__name__)
  15. app.config.from_object('settings.DevelopmentConfig')
  16. app.register_blueprint(account.account)
  17. app.register_blueprint(home.home)
  18. return app

manage.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 16:46
  6. # File : manage.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. from Flask_Session import create_app
  11.  
  12. app = create_app()
  13.  
  14. if __name__ == '__main__':
  15. app.run()

account.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 16:53
  6. # File : account.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. from flask import Blueprint, render_template, request, session, redirect
  11. from uuid import uuid4
  12.  
  13. account = Blueprint('account', __name__)
  14.  
  15. @account.route('/login/', methods=['GET', 'POST'])
  16. def login():
  17. if request.method == "GET":
  18. return render_template("login.html")
  19. user = request.form.get('user')
  20. pwd = request.form.get('pwd')
  21. if user == "cxz" and pwd == "":
  22. uid = str(uuid4())
  23. session.permanent = True
  24. session['user_info'] = {'id': uid, 'name': user}
  25. return redirect('/index/')
  26. else:
  27. return render_template('login.html', msg='用户名或者密码错误!')

home.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 17:33
  6. # File : home.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. from flask import Blueprint, render_template, request, session, redirect
  11.  
  12. home = Blueprint('home', __name__)
  13.  
  14. @home.route('/index/', methods=['GET', 'POST'])
  15. def index():
  16. user_info = session.get('user_info') # {'k1':1,'k2':2}
  17. print("原来的值", user_info)
  18. session['user_info']['k1'] = 19939
  19. user_info = session.get('user_info')
  20. print("修改之后的值", user_info)
  21. # session['modified'] = True,在配置文件中使用SESSION_REFRESH_EACH_REQUEST代替;
  22. return 'Index'
  23.  
  24. @home.route('/test/')
  25. def test():
  26. user_info = session.get('user_info')
  27. print(user_info)
  28. return 'Test'

settings.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 17:28
  6. # File : settings.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from datetime import timedelta
  10.  
  11. class Config(object):
  12. DEBUG = True
  13. TESTING = False
  14. DATABASE_URI = 'sqlite://:memory'
  15. SECRET_KEY = 'fjdksjfdasljflksd'
  16. PERMANENT_SESSION_LIFETIME = timedelta(minutes=20)
  17. SESSION_REFRESH_EACH_REQUEST = True
  18.  
  19. class ProductionConfig(Config):
  20. pass
  21.  
  22. class DevelopmentConfig(Config):
  23. pass
  24.  
  25. class TestingConfig(Config):
  26. pass

06 flask-session组件使用和原理(三)

6.1 将数据存储至Redis;

settings.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 17:28
  6. # File : settings.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from datetime import timedelta
  10. from redis import Redis
  11.  
  12. class Config(object):
  13. DEBUG = True
  14. TESTING = False
  15. DATABASE_URI = 'sqlite://:memory'
  16. SECRET_KEY = 'fjdksjfdasljflksd'
  17. PERMANENT_SESSION_LIFETIME = timedelta(minutes=20)
  18. SESSION_REFRESH_EACH_REQUEST = True
  19. SESSION_TYPE = "redis"
  20. # SESSION_REDIS = Redis(host='127.0.0.1',port='6379')
  21.  
  22. class ProductionConfig(Config):
  23. SESSION_REDIS = Redis(host='127.0.0.1', port='')
  24.  
  25. class DevelopmentConfig(Config):
  26. SESSION_REDIS = Redis(host='127.0.0.1', port='')
  27.  
  28. class TestingConfig(Config):
  29. SESSION_REDIS = Redis(host='127.0.0.1', port='')

__init__.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 16:46
  6. # File : __init__.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. from flask import Flask
  10. from .views import account
  11. from .views import home
  12. # from flask.ext.session import Session
  13. from flask_session import Session
  14.  
  15. def create_app():
  16. app = Flask(__name__)
  17. app.config.from_object('settings.DevelopmentConfig')
  18. app.register_blueprint(account.account)
  19. app.register_blueprint(home.home)
  20. # 将Session替换成Redis;
  21. Session(app)
  22. return app

6.2 Mac版本的Redis可视化工具redis desktop manager的使用;

07 flask-session组件使用和原理(四)

7.1 flask-session的作用:将默认保存的签名cookie中的值保存到Redis、memcached、file、MongoDB、SQLAchemy;

7.2 配置方法;

app.config['SESSION_TYPE'] = 'redis'

app.config['SESSION_REDIS'] = Redis(host = '127.0.0.1',port=6379)

7.3 替换方式;

from flask_session import Session

Session(app)

7.4 注意事项:session中存储的是字典,修改字典内部元素时候,会造成数据不更新;

  • modified = True ,默认值为False
  • SESSION_REFRESH_EACH_REQUEST = True and session.permanent = True (Redis中默认)

08 基于pymysql实现用户登录

8.1 基于pymysql;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 20:13
  6. # File : sql.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. import pymysql
  10.  
  11. class SQLHelper(object):
  12. @staticmethod
  13. def open():
  14. conn = pymysql.connect(host='mysql123.cuixiaozhao.com', port=3306, user='root', passwd='Tqtl911!@%*)',
  15. db='flask_session')
  16. cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
  17. return conn, cursor
  18.  
  19. @staticmethod
  20. def close(conn, cursor):
  21. conn.commit()
  22. cursor.close()
  23. conn.close()
  24.  
  25. @classmethod
  26. def fetch_one(cls, sql, args):
  27. # cursor.execute("select id,name from users where name = %s and pwd = %s", ['cxz', '123', ])
  28. conn, cursor = cls.open()
  29. cursor.execute(sql, args)
  30. obj = cursor.fetchone()
  31. cls.close(conn, cursor)
  32. return obj
  33.  
  34. @classmethod
  35. def fetch_all(cls, sql, args):
  36. conn, cursor = cls.open()
  37. cursor.execute(sql, args)
  38. obj = cursor.fetchall()
  39. cls.close(conn, cursor)
  40. return obj

8.2 pymysql的练习和使用;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-20 19:53
  6. # File : MySQL数据库练习.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. import pymysql
  11.  
  12. conn = pymysql.connect(host='x.x.x.x', port=3306, user='root', passwd='Tqtl911!@%*)', db='flask_session')
  13. cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
  14. cursor.execute("select id,name from users where name = %s and pwd = %s", ['cxz', '', ])
  15. obj = cursor.fetchone()
  16. conn.commit()
  17. cursor.close()
  18.  
  19. conn.close()
  20.  
  21. print(obj)

09 基于数据库连接池实现用户登录(出bug)

9.1 DBUtils模块初识;

  DBUtils是Python的一个用于实现数据库连接池的模块。

pool.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-21 10:26
  6. # File : pool.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9. import time
  10. import pymysql
  11. import threading
  12. from DBUtils.PooledDB import PooledDB, SharedDBConnection
  13. from manage import app
  14.  
  15. POOL = PooledDB(
  16. creator=pymysql, # 使用链接数据库的模块;
  17. maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数;
  18. mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建;
  19. maxcached=5, # 链接池中最多闲置的链接;
  20. maxshared=3,
  21. # 链接池中最多共享的链接数量,0和None表示全部共享。PS: Useless无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
  22. blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错;
  23. maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制;
  24. setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
  25. ping=0,
  26. # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
  27. host='mysql.cuixiaozhao.com',
  28. port=3306,
  29. user='root',
  30. password='Tqtl911!@%*)',
  31. database='flask_session',
  32. charset='utf8'
  33. )

9.2 模式一:模式一:为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭。

  1. POOL = PersistentDB(
  2. creator=pymysql, # 使用链接数据库的模块
  3. maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
  4. setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
  5. ping=0,
  6. # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
  7. closeable=False,
  8. # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
  9. threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
  10. host='127.0.0.1',
  11. port=3306,
  12. user='root',
  13. password='',
  14. database='pooldb',
  15. charset='utf8'
  16. )
  17.  
  18. def func():
  19. conn = POOL.connection(shareable=False)
  20. cursor = conn.cursor()
  21. cursor.execute('select * from tb1')
  22. result = cursor.fetchall()
  23. cursor.close()
  24. conn.close()
  25.  
  26. func()

9.3 模式二:模式二:创建一批连接到连接池,供所有线程共享使用。

  1. import time
  2. import pymysql
  3. import threading
  4. from DBUtils.PooledDB import PooledDB, SharedDBConnection
  5. POOL = PooledDB(
  6. creator=pymysql, # 使用链接数据库的模块
  7. maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
  8. mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
  9. maxcached=5, # 链接池中最多闲置的链接,0和None不限制
  10. maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
  11. blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
  12. maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
  13. setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
  14. ping=0,
  15. # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
  16. host='127.0.0.1',
  17. port=3306,
  18. user='root',
  19. password='',
  20. database='pooldb',
  21. charset='utf8'
  22. )
  23.  
  24. def func():
  25. # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常
  26. # 否则
  27. # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。
  28. # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。
  29. # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。
  30. # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。
  31. conn = POOL.connection()
  32.  
  33. # print(th, '链接被拿走了', conn1._con)
  34. # print(th, '池子里目前有', pool._idle_cache, '\r\n')
  35.  
  36. cursor = conn.cursor()
  37. cursor.execute('select * from tb1')
  38. result = cursor.fetchall()
  39. conn.close()
  40.  
  41. func()

9.4 补充说明; 如果没有连接池,使用pymysql来连接数据库时,单线程应用完全没有问题,但如果涉及到多线程应用那么就需要加锁,一旦加锁那么连接势必就会排队等待,当请求比较多时,性能就会降低了。

10 解决bug(一)

11 解决bug(二)

12 数据库连接池总结

12.1 每一个线程创建一个连接,关闭(默认不关闭),线程终止时,才关闭连接;

12.2 创建共享连接池;

12.3 应用;只要写原生sql,使用了pymysql就得使用数据库连接池DBUtils;

13 WTforms介绍以及用户登录示例

13.1 WTform安装;

13.2 WTform的使用;

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from flask import Flask, render_template, request, redirect
  4. from wtforms import Form
  5. from wtforms.fields import core
  6. from wtforms.fields import html5
  7. from wtforms.fields import simple
  8. from wtforms import validators
  9. from wtforms import widgets
  10.  
  11. app = Flask(__name__, template_folder='templates')
  12. app.debug = True
  13.  
  14. class LoginForm(Form):
  15. name = simple.StringField(
  16. label='用户名',
  17. validators=[
  18. validators.DataRequired(message='用户名不能为空.'),
  19. validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
  20. ],
  21. widget=widgets.TextInput(),
  22. render_kw={'class': 'form-control'}
  23.  
  24. )
  25. pwd = simple.PasswordField(
  26. label='密码',
  27. validators=[
  28. validators.DataRequired(message='密码不能为空.'),
  29. validators.Length(min=8, message='用户名长度必须大于%(min)d'),
  30. validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
  31. message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
  32.  
  33. ],
  34. widget=widgets.PasswordInput(),
  35. render_kw={'class': 'form-control'}
  36. )
  37.  
  38. @app.route('/login', methods=['GET', 'POST'])
  39. def login():
  40. if request.method == 'GET':
  41. form = LoginForm()
  42. return render_template('login.html', form=form)
  43. else:
  44. form = LoginForm(formdata=request.form)
  45. if form.validate():
  46. print('用户提交数据通过格式验证,提交的值为:', form.data)
  47. else:
  48. print(form.errors)
  49. return render_template('login.html', form=form)
  50.  
  51. if __name__ == '__main__':
  52. app.run()
  53.  
  54. app.py

index.html;

  1. !DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>登录</h1>
  9. <form method="post">
  10. <!--<input type="text" name="name">-->
  11. <p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p>
  12.  
  13. <!--<input type="password" name="pwd">-->
  14. <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
  15. <input type="submit" value="提交">
  16. </form>
  17. </body>
  18. </html>

14 WTforms用户注册示例

14.1 基于WTforms做用户注册验证;

app.py;

  1. #!/usr/bin/python3
  2. # -*- coding:utf-8 -*-
  3. # Project: Flask_Session
  4. # Software: PyCharm
  5. # Time : 2018-09-21 15:11
  6. # File : register.py
  7. # Author : 天晴天朗
  8. # Email : tqtl@tqtl.org
  9.  
  10. from flask import Flask, render_template, request, redirect, Blueprint
  11. from wtforms import Form
  12. from wtforms.fields import core
  13. from wtforms.fields import html5
  14. from wtforms.fields import simple
  15. from wtforms import validators
  16. from wtforms import widgets
  17.  
  18. app = Flask(__name__, template_folder='templates')
  19. app.debug = True
  20.  
  21. class RegisterForm(Form):
  22. name = simple.StringField(
  23. label='用户名',
  24. validators=[
  25. validators.DataRequired('用户名不能为空!')
  26. ],
  27. widget=widgets.TextInput(),
  28. render_kw={'class': 'form-control'},
  29. default='alex'
  30. )
  31.  
  32. pwd = simple.PasswordField(
  33. label='密码',
  34. validators=[
  35. validators.DataRequired(message='密码不能为空.')
  36. ],
  37. widget=widgets.PasswordInput(),
  38. render_kw={'class': 'form-control'}
  39. )
  40.  
  41. pwd_confirm = simple.PasswordField(
  42. label='重复密码',
  43. validators=[
  44. validators.DataRequired(message='重复密码不能为空.'),
  45. validators.EqualTo('pwd', message="两次密码输入不一致")
  46. ],
  47. widget=widgets.PasswordInput(),
  48. render_kw={'class': 'form-control'}
  49. )
  50.  
  51. email = html5.EmailField(
  52. label='邮箱',
  53. validators=[
  54. validators.DataRequired(message='邮箱不能为空.'),
  55. validators.Email(message='邮箱格式错误')
  56. ],
  57. widget=widgets.TextInput(input_type='email'),
  58. render_kw={'class': 'form-control'}
  59. )
  60.  
  61. gender = core.RadioField(
  62. label='性别',
  63. choices=(
  64. (1, '男'),
  65. (2, '女'),
  66. ),
  67. coerce=int
  68. )
  69. city = core.SelectField(
  70. label='城市',
  71. choices=(
  72. ('bj', '北京'),
  73. ('sh', '上海'),
  74. )
  75. )
  76.  
  77. hobby = core.SelectMultipleField(
  78. label='爱好',
  79. choices=(
  80. (1, '篮球'),
  81. (2, '足球'),
  82. ),
  83. coerce=int
  84. )
  85.  
  86. favor = core.SelectMultipleField(
  87. label='喜好',
  88. choices=(
  89. (1, '篮球'),
  90. (2, '足球'),
  91. ),
  92. widget=widgets.ListWidget(prefix_label=False),
  93. option_widget=widgets.CheckboxInput(),
  94. coerce=int,
  95. default=[1, 2]
  96. )
  97.  
  98. def __init__(self, *args, **kwargs):
  99. super(RegisterForm, self).__init__(*args, **kwargs)
  100. self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球'))
  101.  
  102. def validate_pwd_confirm(self, field):
  103. """
  104. 自定义pwd_confirm字段规则,例:与pwd字段是否一致
  105. :param field:
  106. :return:
  107. """
  108. # 最开始初始化时,self.data中已经有所有的值
  109.  
  110. if field.data != self.data['pwd']:
  111. # raise validators.ValidationError("密码不一致") # 继续后续验证
  112. raise validators.StopValidation("密码不一致") # 不再继续后续验证
  113.  
  114. @app.route('/register', methods=['GET', 'POST'])
  115. def register():
  116. if request.method == 'GET':
  117. form = RegisterForm(data={'gender': 1})
  118. return render_template('register.html', form=form)
  119. else:
  120. form = RegisterForm(formdata=request.form)
  121. if form.validate():
  122. print('用户提交数据通过格式验证,提交的值为:', form.data)
  123. else:
  124. print(form.errors)
  125. return render_template('register.html', form=form)
  126.  
  127. if __name__ == '__main__':
  128. app.run()
  129.  
  130. # app.py

register.html;

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>用户注册</h1>
  9. <form method="post" novalidate style="padding:0 50px">
  10. {% for item in form %}
  11. <p>{{item.label}}: {{item}} {{item.errors[0] }}</p>
  12. {% endfor %}
  13. <input type="submit" value="提交">
  14. </form>
  15. </body>
  16. </html>

15 内容总结

15.1 WTforms总结;

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。

16 homework

16.1 补充了路飞学城CC授权播放;

16.2 flask-session的用法以及Redis的使用;

16.3 pymysql以及数据库连接池DBUtils;

16.4 WTforms;

16.5 Flask的上下文管理以及源码

16.6 flask-session;

Flask Web开发从入门到放弃(一)的更多相关文章

  1. 三 Flask web开发快速入门

    1:会话: from flask import Flask, url_for, request, render_template, session from werkzeug.utils import ...

  2. 《Flask Web开发实战:入门、进阶与原理解析(李辉著 )》PDF+源代码

    一句话评价: 这可能是市面上(包括国外出版的)你能找到最好的讲Flask的书了 下载:链接: https://pan.baidu.com/s/1ioEfLc7Hc15jFpC-DmEYBA 提取码: ...

  3. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)

    目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构   前言 学习Python也有一个半月时间了,学到现在感觉 ...

  4. 学习参考《Flask Web开发:基于Python的Web应用开发实战(第2版)》中文PDF+源代码

    在学习python Web开发时,我们会选择使用Django.flask等框架. 在学习flask时,推荐学习看看<Flask Web开发:基于Python的Web应用开发实战(第2版)> ...

  5. Flask web开发 请求拦截和预处理

    我们在开发WEB应用时,往往会需要对所有的url请求进行拦截,做些预处理,比如权限处理.日志等统一处理. 本文介绍一下Flask中的处理机制.我们通过一个简单的例子来说明. 1.编写一个简单应用 ru ...

  6. Flask web开发 处理Session

    本文我们在上篇文章<Flask web开发  处理POST请求(登录案例)>的基础上,来讲述Flask对session的支持. 在上面案例上,我们需要修改和新增如下功能 1.登录成功后的 ...

  7. Mr.聂 带你成为web开发大牛——入门篇(上)

    作为一名IT届的后生,当初也经历过懵懂无知的实习期,对那种无力感深有体会.在这,希望能用我这几年的开发经验,让各位即将踏入或者刚刚踏入web开发领域的新人们少走些弯路.鉴于这是入门篇,下面我就从零为大 ...

  8. 【ZZ】Web开发的入门指导 | 菜鸟教程

    Web开发的入门指导 http://www.runoob.com/w3cnote/a-beginners-guide-to-web-development.html

  9. Laravel 教程 - Web 开发实战入门 ( Laravel 5.5 )购买链接

      Laravel 教程 - Web 开发实战入门 ( Laravel 5.5 )购买链接: 推荐给你高品质的实战课程 https://laravel-china.org/courses?rf=158 ...

随机推荐

  1. html下载文件和上传文件(图片)(java后台(HttpServlet))打开保存路径和选择文件录取+(乱码UTF-8)+包

    下载文件: //通过路径得到一个输入流 String path = "获取需要下载的文件路径"; //path.lastIndexOf(".")+1可以获取文件 ...

  2. Android学习笔记_39_tween动画的实现(Animation和Frame)

    一.Animation动画的实现及特点: 1.Tween动画,通过对 View 的内容进行一系列的图形变换 (包括平移.缩放.旋转.改变透明度)来实现动画效果.   动画效果的定义可以采用XML来做也 ...

  3. ES6 基础概念汇总

    let const命令 声明变量 let 声明的变量  没有变量提升的效果 1  let声明的变量只在代码块内有效 for循环的计数器 2  不存在变量提升 要在声明后使用 let bar = 2 3 ...

  4. PL/SQL dev 工具连接远程服务器oracle注意点

    由于Oracle的庞大,有时候我们需要在只安装Oracle客户端如plsql.toad等的情况下去连接远程数据库,可是没有安装Oracle就没有一切的配置文件去支持. 最后终于发现一个很有效的方法,O ...

  5. idea常用技巧

    1.如何设置,使IntelliJ IDEA智能提示忽略大小写 打开设置(CTRL+ALT+S)搜索editor,找到“Code Completion”->点击Case sensitive com ...

  6. iOS | TableView的优化

    TableView是iOS组件中最常见.最重要的组件之一,在开发中常常用到,所以对其进行优化是一项必不可少的基本功. 主要从几个最常用的方面来对其优化: 1.重用机制 重用机制是cell最基础的一项优 ...

  7. JavaScript-语法专题

    一.数据类型的转换 概述 JavaScript是一种动态语言,变量没有类型限制,可以随时赋予任意值 强制转换:主要是值Number(),String(),Boolean三个函数 Number函数,可以 ...

  8. Vue组件:组件的动态添加与删除

    一.实现效果 二.实现代码 HelloWorld.vue <template> <div class="hello"> <child-page v-f ...

  9. tomcat6添加服务

    Mysql在导入大量数据的时候就要把tomcat添加成服务 添加服务 在DOS界面下,进入Tomcat解压目录的bin目录 service.bat install

  10. LVS、keepalived原理及配置

    使用LVS实现负载均衡原理及安装配置详解 ​ 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负 ...