chaoz的杂货铺

生命有息、学无止境、折腾不止

0%

python-Flask框架-鱼书网站实践

Flask Fish 鱼书项目

确定访问的 url 路径问题

无非就是 url 使用时是否在地址最后加上 斜杠 。

监听代码修改,热启动

开启Flask 调试模式

python fisher.py

注册路由:

1、用装饰器来注册路由。

2、app.add_url_rule

1
2
3
4
5
#@app.route("/hel1o')
def hel1o():
#基于类的视图(即插视图)return'Hel1o,QiYue'
app.add_url_rule("/hello',view_func=hel1o)
app.run(debug=True)

配置 pycharm 全局访问路径、端口

app.run(host='0.0.0.0', debug=True,port=81)

部署的话该怎么处理

debug 简单修改的不是太好,调试模式下使用的是默认的Flask自带的服务器,性能不太好,以及后端出现错误的话,网页端会显示出来。

方法:

加一个 config.py 的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fish.py

from flask import Flask author='七月
o a@p=Flask(_name__)
app.config.from_object('config')
@app.route("/hello's def hello():#基于类的视图(即插视图)return'Hello,QiYue'
#字典dict子类
#app.add_urlrule("/hello',view_func=hel1o)
app.run(host='0.0.e.e',debug=app.config['DEBUG'],port=81)

config.py

__author_='七月'
DEBUG = True

注意 config.py 无论是在配置里面还是在应用里面导入,都需要将参数全部大写。

真正理解 if name == ‘main‘:

1
2
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)

在实际生产环境中需要 nginx+uwsgi 来搭配使用作为服务器。

作用:不会在实际生产环境中同时启用 nignx 和 flask 自带的服务器。

搜索功能的实现

区分数字:

按照数字进行搜索

区别书名:

识别传入的是书名,对书名进行搜索

1
2
3
4
5
6
7
8
9
10
11
def is_isbn_or_key(word):
isbn_or_key = 'key'
if len(word) == 13 and word.isdigit():
isbn_or_key = 'isbn'
short_q = word.replace('-', '')
if '-' in word and len(short_q) == 10 and short_q.isdigit:
# 条件判断的原则,提高代码的运行效率
# 先把很大概率出现假的 条件放在前面
# 把查询数据库这种非常耗时的消耗放在后面
isbn_or_key = 'isbn'
return isbn_or_key

使用 API

如何调用 api :
如何设计 api :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class YuShuBook:
isbn_url = 'http://t.yushu.im/v2/book/isbn/{}'
keyword_ur1 = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'

# {} 代表动态数据
@classmethod
def search_by_isbn(cls, isbn):
url = cls.isbn_url.format(isbn)
# url = self.isbn_url # 链式查找
result = HTTP.get(url)
return result

@classmethod
def search_by_keyword(cls, keyword, page=1):
print(1)
url = cls.keyword_ur1.format(keyword, current_app.config['PER_PAGE'], cls.calculate_start(page))
result = HTTP.get(url)
return result

@staticmethod
def calculate_start(page):
return (page - 1) * current_app.config['PER_PAGE']

三元表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在Python中的三元表达式的写法和大部分的语言是不同的

现在有 x, y,如果 x大于y的话返回x否则返回y

绝大部分语言中的写法:
条件判断 ? 条件为真时返回的结果 : 条件为假时返回的结果

x > y ? x : y
1
Python中的写法
先看一个伪代码:条件为真时返回的结果 if 条件判断 else 条件为假时的返回结果

x =1
y =2
r = x if x > y else y
---------------------
输出:
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
判断调用 API 返回的值为 error

class HTTP:
def get(url, return_json=True):
r = requests.get(url)
# restful
# json
if r.status_code != 200:
return {} if return_json else ''
return r.json() if return_json else r.text
# if r.status_code ==200:
# if return_json:
# return r.json()
# else:
# return r.text
# else:
# if return_json:
# return {}
# else:
# return ''

建议在 多个 if else 中的代码单独提取为一个函数,以及增加 return ,提前减少分支。

staticmethod 与 classmethod

python的staticmethod,classmethod和装饰器以及闭包的爱恨情仇

笔记:

类的实例化:

类是指:描述一种事物的定义,是个抽象的概念
实例指:该种事物的一个具体的个体,是具体的东西
打个比方:
“人”是一个类。“张三”是人类的一个具体例子
在编程时也是同样的道理,你先自己定义一个“类”,当你需要用时,用“类”的定义来创造一个具体的例子。
用类的定义来创建一个实例,就叫做类的实例化。

两个方法之间的去别:

@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。

什么是硬编码

什么叫“硬编码”?“硬”,顾名思义,就是死板,一次性的意思。其定义也就是“将可变变量用一个固定数值表示”,这种方式在编码的过程中会导致变量很难修改。因此通常采用的方式都是软编码的方式,也即通过一个标记取代变量名称,而这个标记的值是可以不断变化的。但标记名称却是不变的,从而实现了“以不变应万变“。

1
2
3
4
5
eg: int a=2,b=2;   
硬编码:if(a==2) return false;   
非硬编码 if(a==b) return true;   (就是把数值写成常量而不是变量 )
一个简单的版本:如求圆的面积 的问题 PI(3.14)   
那么3.14*r*r 就是硬编码,而PI*r*r 就不是硬编码。

复习装饰器、闭包

装饰器:

优点像 JAVA 继承,就是在使用某个函数的时候,感觉这个函数功能不能满足自己的使用,同时不能在原函数上进行修改,于是乎装饰器诞生。

闭包:

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
参考链接:博客园

object 的继承问题

知乎:Python 为什么要继承 object 类?

笔记:class Http(object): 这个 object 有时候可以继承也可不继承,有什么区别?
答:python3没有区别,python2有区别。

python 2 : 经典类和新式类

python 3 : 默认新式类

链式查找是个啥????

方法链(method chaining)是面向对象的编程语言中的一种常见语法,可以让开发者在只引用对象一次的情况下,对同一个对象进行多次方法调用。

Python中方法链的使用方法

定制类里用到了

参考教程:
Python简化类例五:实现链式写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
eg:

#Python简化类例五:实现链式写法
def ClassTest5():
'''链式写法只要是类语言都可以实写'''
def p() :pass
p.x=0
p.y=0
def o():pass

def printPos():
print("当前坐标是(%d, %d)"%(p.x,p.y))

def moveLeft():
p.x-=1
printPos()
return o
o.moveLeft=moveLeft;del moveLeft

def moveTop():
p.y+=1
printPos()
return o
o.moveTop=moveTop;del moveTop

def moveRight():
p.x+=1
printPos()
return o
o.moveRight=moveRight;del moveRight

def moveBottom():
p.y-=1
printPos()
return o
o.moveBottom=moveBottom;del moveBottom
return o

t5=ClassTest5()
t5.moveTop().moveLeft().moveBottom().moveRight()

# coding=utf-8
class Bar(object):
pass


class Foo(object):
"""类的描述文本"""
def __init__(self):
pass

def __getattr__(self, item):
print(item,end=" ")
#注意:返回的是对象自身
return self

#重写str()方法
def __str__(self):
return ""

print(Foo().think.different.itcast)

定制类

看到类似slots这种形如xxx的变量或者函数名就要注意,这些在Python中是有特殊用途的。

slots我们已经知道怎么用了,
_ len _()方法我们也知道是为了能让class作用于len()函数。

除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。

廖雪峰官方教程-面向对象高级编程

python 中 self 到底是个什么玩意

一篇文章让你彻底搞清楚Python中self的含义

python中self参数的作用

笔记:self代表类的实例,而非类。
self在定义时需要定义,但是在调用时会自动传入。
self的名字并不是规定死的,但是最好还是按照约定是用self
self总是指调用时的类的实例。

类中函数定义需要加self,类外函数定义不需要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
eg:

class Foo(object):
#类中方法加入了self参数
def say_someThing(self,str):
print(str)

#类外方法不需要加入self参数
def say_hello():
print('hello')

#类外函数使用
say_hello()

#类内函数使用,不需要加入self相关参数
foo=Foo()
foo.say_someThing("hi")

import http 爬坑

http.client使用奇怪问题:
ImportError: No module named ‘http.client’; ‘http’ is not a package。

解决:你的代码文件应该叫http.py了吧,这样引用变成引用自己了。改个名吧!!!!!

No module named ‘urllib2’:

Python 3.3之后,urllib2改为urllib.response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Python 2.7 代码:

import urllib2
response = urllib2.urlopen('http://www.baidu.com/')
html = response.read()
print html


Python 3.3+ 代码应该为:

import urllib.request
response=urllib.request.urlopen('http://www.baidu.com')
html=response.read()
print(html)

dict 是什么

可变的字典:

不可变的字典:
两种方法:
1、自己继承dict 的数据结构
2、直接用 flask 提供的方法

不可变字典转换为普通字典:
a = request.args.to_dict()

字典是无序的。

1
2
3
4
5
6
7
8
9
10
11
12
13
dict()
作用:dict() 函数用于创建一个字典。返回一个字典。

语法:

class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
参数说明:

**kwargs -- 关键字
mapping -- 元素的容器。
iterable -- 可迭代对象
1
2
3
4
5
6
7
8
9
10
eg:
>>>dict() # 创建空字典
{}
>>> dict(a='a', b='b', t='t') # 传入关键字
{'a': 'a', 'b': 'b', 't': 't'}
>>> dict(zip(['one', 'two', 'three'], [1, 2, 3])) # 映射函数方式来构造字典
{'three': 3, 'two': 2, 'one': 1}
>>> dict([('one', 1), ('two', 2), ('three', 3)]) # 可迭代对象方式来构造字典
{'three': 3, 'two': 2, 'one': 1}
>>>
Set

dict的作用是建立一组 key 和一组 value 的映射关系,dict的key是不能重复的。

有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set就派上用场了。

set 持有一系列元素,这一点和 list 很像,但是set的元素没有重复,而且是无序的,这点和 dict 的 key很像。

1
2
3
4
5
6
7
8
创建 set 的方式是调用 set() 并传入一个 list,list的元素将作为set的元素:

>>> s = set(['A', 'B', 'C'])
可以查看 set 的内容:

>>> print s
set(['A', 'C', 'B'])
请注意,上述打印的形式类似 list, 但它不是 list,仔细看还可以发现,打印的顺序和原始 list 的顺序有可能是不同的,因为set内部存储的元素是无序的。

注意:set 里面含有中括号。

深入了解flask路由、蓝图

了解路由的设计,路由的分配,404、301

老师原话:每一个url都会对应一个视图函数,但是不仅仅是这样。每一个url还会对应一个endpoint端点,用于反向构建URL。

Flask路由与蓝图Blueprint

Flask源码复习之路由

Request 对象的使用

官方教程 - 初级

官方教程 - 高级

验证器

1
2
3
4
# 内置的验证器
class SearchForm(Form):
q = StringField(validators=[DataRequired(),Length(min=1,max=30)])#最大值,最小值,消息
page = IntegerField(validators=[NumberRange(min=1,max=99)],default=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@web.route('/book/search')
def search():
form = SearchForm(request.args)
if form.validate():
q = form.q.data.strip()
print(q)
page = form.page.data
print(page)
isbn_or_key = is_isbn_or_key(q)
print('isbn_or_key')
if isbn_or_key == 'isbn':
result = YuShuBook.search_by_isbn(q)
else:
result = YuShuBook.search_by_keyword(q,page)
return jsonify(result)
else:
return jsonify(form.errors)

validators 是个啥,为什么里面可以传多个函数

validator.py是一个数据验证工具,确保数据符合一定的规则。一个validation是一个字典,对于字典中的每一个键,包含一个规则列表。

Github地址

简书教程:Python数据验证库(二)validator

创建数据表的方式

1、Model First
利用建模工具

2、Database Firs:
手动创建,传统方式

3、Code First

sqlalchemy、WTFORMS 适用于各个 python 的框架

Flask_SQLALchemy 适用于Flask,可以提供更方便的API
Flask_WTFORMS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
eg:

db = SQLAlchemy()
class Book(db.Model):
id = Column(Integer, primary_key=True, autoincrement=True)
# 第一个参数指明传入的类型,传两个关键字属性,一个主键,一个自增长
title = Column(String(50), nullable=False)
# 第二个参数关键字参数,意思是不可以为空
author = Column(String(30), default='佚名')
isbn = Column(String(15))
price = Column(String(20))
binding = Column(String(20)) # 是否为精装
publisher = Column(String(50))
pages = Column(Integer) # 页数
isbn = Column(String(15), nullable=False, unique=True)
# unique 唯一的 不是重复的
summary = Column(String(1000)) # 简介
image = Column(String(50))

Flask 核心机制

上下文

1
2
3
4
5
6
7
8
9
from flask import Flask,current_app,request,Request app=Flask(name_)
#应用上下文对象Flask
#请求上下文对象Request
#Flask AppContext
#Request RequestContext
#离线应用、单元测试
ctx=app.app kontext()
ctx.push()I a=current_app d=current_app.config['DEBUG']
ctx.pop()

栈:后进先出
队列:先进先出

Flask 的核心就是玩队列的感觉。

先实例化,每一次调用函数都是可以理解为出栈、入栈。每一次 flask 会自动检查你这次的动作所需的参数,在栈里面是不是为空,如果是空的,那就自动执行入栈,用完再出栈。

什么是上下文

python黑魔法—上下文管理器(contextor)

笔记:

什么是句柄

什么是句柄?为什么会有句柄?HANDLE

笔记:

with 语句是怎么用的。它的意义是什么

博客园:with 关键字学习

1
2
3
4
5
6
7
8
9
10
eg:简化代码

with app.app_context():
a = current_app
d = current_app.config['DEBUG']
#实现了上下文协议的对象使用with
#上下文管理器
# __enter__ __exit__
#上下文表达式必须要返回一个上下文管理器
#t with
with 语句时用于对try except finally 的优化
1
2
3
4
5
6
7
f=open('file_name','r')
try:
r=f.read()
except:
pass
finally:
f.close()

用with的实现:

1
2
with open('file_name','r') as f:
r=f.read()

这条语句就好简洁很多,当with里面的语句产生异常的话,也会正常关闭文件

自己定义可以给with调用的上下文管理器
1
2
3
4
5
6
7
8
9
10
class MyResource: 
def __enter__(self):
print(' connect to resource')
return self
def __exit__(self, exc_type, exc_value, tb):
print(' close resource connection')
def query(self):
print(' query data')
with MyResource() as resource:
resource. query()

笔记:懒人代码,让你少写几个关闭(收尾)代码。

遇到问题,学习再源码中找方法

1
2
3
4
5
6
7
8
9
10
def create_app(): 
app=Flask(_name)
app. config. from_object(' app. secure')
app. config. from_object(' app. setting')
register_blueprint(app)

db. init_app(app)
with app.app_context():
db. create_all()
return app
1
2
3
db. init_app(app)
db. create_a11(app=app)
return app

Flask 中的多线程和线程隔离技术

使用线程隔离的意义在于:使当前线程能够正确引用到他自己所创建的对象,而不是引用到其他线程所创建的对象

pthon 的多线程

python 的 GIL

Local 使用字典的方式实现的线程的隔离

什么是封装

LocalStack 的用法

push、pop、top
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
s=LocalStack()
s.push(1)
print(s.top)
print(s.top)
print(s.pop())
print(s.top)
s.push(1)
s.push(2)
#栈后进先出
print(s.top)I
print(s.top)
print(s.pop())
print(s.top)

结果:

1
1
1
None
2
2
2
1

栈与数组

构造函数

getattr 与 setattr 方法

线程隔离对象与被线程隔离对象

书籍详情页面的构建

ViewModel 的基本概念、以及数据处理

伪面向对象:面向过程

什么是面向过程

重构鱼书核心对象

从json序列化看代码解释权反转

单页面与网站区别

静态文件、模板、消息闪现与Jinja2

Flask 静态文件访问原理

模板文件的位置与修改方案

jianjia2

流程控制语句

模板继承

过滤器与管道命令

反向构建 URL

消息闪现、SecretyKey与变量作用域

显示搜索结果页面、与页面结构解析

喜欢这篇文章?打赏一下作者吧!

欢迎关注我的其它发布渠道