10.1 最近的礼物

我们的首页会显示最近的赠送书籍列表。这个列表有三个限制条件: 1.数量不超过30 2.按照时间倒序排列,最新的排在最前面 3.去重,同一本书籍的礼物不重复出现

1.首先编写复杂SQL对应的ORM代码

由于是最近的礼物,所以应该编写在models/gift.py中

@classmethod
def recent(cls):
# 链式调用 主体是Query ,遇到all(),first()就会终止生成一条sql
# 建造者模式
# select distinct * from gift group by isbn order by create_time limit 30
recent_gifts = Gift.query\
.filter_by(launched=False)\
.group_by(Gift.isbn)\
.order_by(Gift.create_time)\
.limit(30)\
.distinct().all()
return recent_gifts
复制代码

为什么要定义成类方法呢。

  • 对象代表一个礼物,是具体的
  • 类代表礼物这个事物,他是抽象的,不是具体的一个

2.业务的四种编写方案

1.编写在models的对应的gift.py里。 2.编写在视图函数里。(看你认为当前这段的业务有没有意义) 3.在models里建立新的RecentGift模块。 4.建立service层。(不推荐,Service层全都是静态方法,没有理解面向对象的意义)

3.编写视图函数

我们编写的recent函数获取到的gift列表里的每一个gift,都只有isbn编号。但是我们需要把图书的信息都返回回去。这就需要拿isbn编号去YushBook可去查询出书籍的详情信息然后再使用BookViewModel进行封装。

但是上面这段逻辑,不应该写在视图函数的for循环中,他是Gift的行为,应该封装到Gift的模型中去。

@property
def book(self, isbn):
yushu_book = YuShuBook()
yushu_book.search_by_isbn()
return yushu_book.first
复制代码

不能在Gift模型中直接返回BookViewModel,因为我们的模型只负责处理原始数据,所有的处理ViewModel都应该放到视图函数里面进行。

web/main.py

@web.route('/')
def index():
recent_gifts = Gift.recent()
books = [BookViewModel(gift.book) for gift in recent_gifts]
return render_template('index.html', recent=books)
复制代码

之所以能够在调用的地方用一个很简单的列表推导式就完成了这么复杂的逻辑,就是因为我们封装的非常良好。这里面涉及到了几个对象的相互调用-bookviewmodel,gift,yushubook;这才是在真正的写面向对象的代码,面向对象就是几个对象在相互调用,各自的逻辑是非常清晰的(单一职责模式)

良好的封装是优秀代码的基础


10.2 我的礼物(赠送清单)

1.业务逻辑分析

赠送清单的业务逻辑如下

其中复杂在于第二点,实现有以下两种思路

如果循环次数可以控制,比如10次,100次,那么我们还可以接受,但是这个循环次数是掌握在用户手里的,所以第一种方案是不能够接受的。我们采取第二种方案

2.代码编写

models/gift.py 对原始数据的获取

@classmethod
def get_user_gifts(cls, uid):
gifts = Gift.query \
.filter_by(uid=uid, launched=False) \
.order_by(desc(Gift.create_time)) \
.all()
return gifts@classmethod
def get_wish_counts(cls, isbn_list):
# 根据传入的一组isbn编号,到Wish表中计算出某个礼物的Wish心愿数量
# select count(id),isbn from wish
# where launched = false and isbn in ('','') and status =1 group by isbn
count_list = db.session.query(func.count(Wish.id), Wish.isbn).filter(
Wish.launched == False,
Wish.isbn.in_(isbn_list),
Wish.status == 1).group_by(
Wish.isbn).all()
# 不要将tuple返回到外部,应该返回有意义的字典或者对象
count_list = [{'count': w[0], 'isbn':w[1]} for w in count_list]
return count_list
复制代码

view_model/gift.py 对原始数的裁剪包装

class Gifts:def __init__(self, gifts_of_mine, wish_count_list):
self.gifts = []
self.__gifts_of_mine = gifts_of_mine
self.__wish_count_list = wish_count_listself.gifts = self.__parse()def __parse(self):
temp_gifts = []
for gift in self.__gifts_of_mine:
my_gift = self.__matching(gift)
temp_gifts.append(my_gift)
# 不应该在函数内部对对象的属性进行修改,应该返回给外部,在外部进行复制
# 这是因为如果函数比较复杂,我们根本不知道对象的属性是在哪个函数中修改的
return temp_giftsdef __matching(self, gift):
count = 0
for wish_count in self.__wish_count_list:
if gift.book == wish_count['isbn']:
count = wish_count.count
r = {
'wishes_count': count,
'book': BookViewModel(gift.book),
'id': gift.id
}
return r
复制代码

web/gift.py 对视图函数进行组装

@web.route('/my/gifts')
@login_required
def my_gifts():
uid = current_user.id
gifts_of_mine = Gift.get_user_gifts(uid)
isbn_list = [gift.isbn for gift in gifts_of_mine]
wish_count_list = Gift.get_wish_counts(isbn_list)
view_model = Gifts(gifts_of_mine, wish_count_list)
return render_template('my_gifts.html', gifts=view_model.gifts)
复制代码

上面获取原始数据,是对两张表分别查询,再组装,我们也可以进行连表查询,下面是两种方式

# 直接进行sql查询
@classmethod
def get_user_gifts_by_sql(cls, uid):
sql = 'select a.id,a.isbn,count(b.id)' \
'from gift a left join wish b on a.isbn = b.isbn ' \
'where b.uid = %s and a.launched = 0 and b.launched = 0 ' \
'and a.status = 1 and b.status = 1 ' \
'group by a.id,a.isbn order by a.create_time desc'.replace('%s', str(uid))
gifts = db.session.execute(sql)
gifts = [{'id': line[0], 'isbn': line[1], 'count':line[2]} for line in gifts]
return gifts
# 使用SQLAlchemy提供的多表查询的方式
@classmethod
def get_user_gifts_by_orm(cls, uid):
gifts = db.session\
.query(Gift.id, Gift.isbn, func.count(Wish.id))\
.outerjoin(Wish, Wish.isbn == Gift.isbn)\
.filter(
Gift.launched == False,
Wish.launched == False,
Gift.status == 1,
Wish.status == 1,
Gift.uid == uid)\
.group_by(Gift.id, Wish.isbn)\
.order_by(desc(Gift.create_time))\
.all()
gifts = [{'id': line[0], 'isbn': line[1], 'count':line[2]} for line in gifts]
return gifts复制代码

10.3 我的心愿(心愿清单)

我的心愿的代码可以说是我的礼物的镜像代码,只是改下名字。

但是考虑view_models,gift和wish的view_model 可以合并成一个MyTrade。实际上Trade应该是gift和wish的基类,在我们这里他们之间没有行为差异,之间用一个即可,如果他们有了行为差异,就应该分别继承Trade实现自己的业务逻辑

class MyTrade:def __init__(self, trades_of_mine, trades_count_list):
self.trades = []
self.__trades_of_mine = trades_of_mine
self.__trades_count_list = trades_count_listself.trades = self.__parse()def __parse(self):
temp_trades = []
for trade in self.__trades_of_mine:
my_trade = self.__matching(trade)
temp_trades.append(my_trade)
return temp_tradesdef __matching(self, trade):
count = 0
for trade_count in self.__trades_count_list:
if trade.isbn == trade_count['isbn']:
count = trade_count['count']
r = {
'wishes_count': count,
'book': BookViewModel(trade.book),
'id': trade.id
}
return r
复制代码

慕课网Flask高级编程实战-10.鱼书业务处理相关推荐

  1. 慕课网Flask高级编程实战-7.静态文件、模板、消息闪现与Jinja2

    7.1 静态文件访问原理 1.默认访问方法 Flask访问静态文件非常简单,只需要在项目根目录建立static文件夹.将静态资源文件放入static下即可.访问的时候访问http://ip:port/ ...

  2. 《C#多线程编程实战(原书第2版)》——第3章 使用线程池 3.1 简介

    本节书摘来自华章出版社<C#多线程编程实战(原书第2版)>一书中的第3章,第3.1节,作者(美)易格恩·阿格佛温(Eugene Agafonov),黄博文 黄辉兰 译,更多章节内容可以访问 ...

  3. 《C#多线程编程实战(原书第2版)》——3.2 在线程池中调用委托

    本节书摘来自华章出版社<C#多线程编程实战(原书第2版)>一书中的第3章,第3.2节,作者(美)易格恩·阿格佛温(Eugene Agafonov),黄博文 黄辉兰 译,更多章节内容可以访问 ...

  4. 《C#多线程编程实战(原书第2版)》——3.6 在线程池中使用等待事件处理器及超时...

    本节书摘来自华章出版社<C#多线程编程实战(原书第2版)>一书中的第3章,第3.6节,作者(美)易格恩·阿格佛温(Eugene Agafonov),黄博文 黄辉兰 译,更多章节内容可以访问 ...

  5. c#高级编程第11版 pdf网盘_c#高级编程_c#高级编程 目录 微盘_c#高级编程第10版 pdf...

    c#高级编程 C#高级编程(第9版)-C# 5.0 & .NET 4.5.1是由.NET专家的梦幻组合编写,包含开发人员使用C#所需的所有内容.C#是编写.NET应用程序的一种语言,本书适合于 ...

  6. vue2.5 去哪网慕课网从入门到实战

    第一章 课程介绍 课程简介 (mvvm什么意思下面有解释) 基于vue 的框架,nuxt 可以来编写服务器端,weex 可以编写原生的组件 第二章  vue起步 课程学习方法 看官方的文档,结合视频教 ...

  7. flask高级编程-循环引用

    16. 路径加了<>,就会被识别为一个参数,而不是固定的url字符串 16.1 编程原则:视图函数里面要尽可能间接,函数要见名知意,不能将细节全部写到视图函数里面,那样是强迫让所有看代码的 ...

  8. flask高级编程 LocalStack 线程隔离

    转:https://www.cnblogs.com/wangmingtao/p/9372611.html 30.LocalStack作为线程隔离对象的意义 30.1 数据结构 限制了某些能力 30.2 ...

  9. 慕课网 javascript深入浅出编程练习

    任务 请在index.html文件中,编写arraysSimilar函数,实现判断传入的两个数组是否相似.具体需求: 1. 数组中的成员类型相同,顺序可以不同.例如[1, true] 与 [false ...

最新文章

  1. Python使用matplotlib可视化散点图、并在可视化图像的底部和右边添加边缘直方图、自定义边缘直方图的色彩(Marginal Histogram)
  2. JAVA单线程以及java多线程的实现方式
  3. lamda list 分组_java8lambda表达式对集合分组并且排序(记一次性能优化案例)
  4. 向js中添加静态方法与属性方法
  5. [Swift]LeetCode326. 3的幂 | Power of Three
  6. 计算机如何实现共享接入,局域网内电脑实现共享设置方法
  7. 石油化工行业需要怎样的工作流平台?
  8. python map zip_Python学习笔记(九) map、zip和filter函数
  9. [android] AndroidManifest.xml - 【 manifest - permission】
  10. C语言无符号整数和有符号整数的比较
  11. 6.高性能MySQL --- 查询性能优化(1)
  12. 孤岛惊魂4服务器稳定吗,《孤岛惊魂5》究竟好不好玩 让我来告诉你(缺点)
  13. 自动控制原理5.1---频率特性
  14. IT基础架构规划方案
  15. CTF基础-MISC篇
  16. uniapp:广告API使用总结
  17. html5中abbr,HTML 5 abbr 标签 - HTML 参考手册
  18. mysql frm怎么打开_frm 文件怎么打开?
  19. dbeaver连接hive3.1.2,不需添加驱动
  20. Unable to load DLL 'xxx.dll': 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)

热门文章

  1. “神经+符号”:从知识图谱角度看认知推理的发展
  2. 观点 | 港科大张潼教授最新发言:对人工智能发展的一些思考
  3. SAP WM LQ02 为供应商寄售库存去K的时候,如果有Open TO单,则不能成功为物料去K?
  4. 分享丨李飞飞、吴恩达、Bengio等人的顶级深度学习课程
  5. latex中的\label标签的作用
  6. 神经网络为大脑如何运作提供新见解
  7. 15℃!人类首次实现高压下室温超导,研究登上Nature封面
  8. 人工智能的发展与障碍 | 麦肯锡
  9. 3D芯片大脑:在芯片上培养脑细胞,还能用来测试新药
  10. 【技术趋势】2020 五大技术趋势:无人驾驶发展、机器视觉崛起、区块链实用化、人类增强技术、超自动化...