from flask_sqlalchemy import SQLAlchemy
# 创建
app = Flask(__name__, static_folder='../static')
ctx = app.app_context() # 解决RuntimeError: Working outside of application context.
ctx.push()
# 配置
# app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/egl_flask'
# 一般用下面这个带pymysql的,因为上面的在高版本flask会报错
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]:3306/mydb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 5
app.config['SQLALCHEMY_POOL_SIZE'] = 20
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 5
app.secret_key = 'Terraria'
app = Flask(__name__, static_folder='./static')
# 创建db对象
db = SQLAlchemy(app)
# 数据模型...
# 测试
if __name__ == '__main__':
# 重置数据库
db.drop_all()
# 新建
db.create_all()
# 生成数据
user1 = User(username='90217', password='123abc', status=1)
user2 = User(username='Azir', password='123abc', status=0)
user3 = User(username='demanwei', password='123abc')
user4 = User(username='90219', password='123abc')
# 把数据提交给用户会话
db.session.add_all([user1, user2, user3, user4])
# 提交事务
db.session.commit()
class User(db.Model):
# 表名
__tablename__ = 'user'
# 字段
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
username = db.Column(db.String(256), unique=True ,nullable=False)
password = db.Column(db.String(256), nullable=False)
status = db.Column(db.Integer, nullable=False, default=1)
create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)
# 描述信息,类似于JavaBean的toString()
def __repr__(self):
desc = self.__class__.__name__ + '{'
for field in self.keys():
desc += '{}={},'.format(field, getattr(self, field))
desc += '}'
return desc
参数 | 说明 | DB对应类型 |
---|---|---|
db.BigInteger |
长整型,一般做主键 | bitint |
db.Integer |
整形 | int |
db.String(n) |
字符型,使用时需要指定长度,区别于Text类型 | varchar(n) |
db.Text |
文本型 | text |
db.LONGTEXT |
长文本型 | longtext |
db.Float |
浮点型 | float |
db.Double |
双精度浮点型 | double |
db.Boolean |
布尔型 | tinyint |
db.Decimal(a,b) |
具有小数点而且数值确定的数值,一般用于存储金钱 | decimal |
db.Enum |
枚举类型 | |
db.DateTime |
日期时间类型 | datetime |
db.Date |
日期类型,传递datetime.date() |
date |
db.Time |
时间类型,传递datetime.time() |
time |
参数 | 说明 |
---|---|
primary_key |
是否为主键 |
autoincrement |
是否自动增长 |
unique |
是否唯一 |
default |
默认值 |
nullable |
是否允许为空 |
index |
是否创建索引 |
onupdate |
更新的时候执行的函数 |
name |
该属性在数据库中的字段映射 |
对于实体属性的修改,只能采用entity.field = value
的方式:
user = User.query.get('1')
# 正确方式
user.status = 0
# 错误方式
user['status'] = 0
user.'status' = 0
假如现在有一个接口是修改用户信息,前端传来的字段至少有user_id
,但其他字段是不确定的。此时一般想到会这样做:
# 动态修改user字段, 如user.status=0,user.password=123456
for field, value in request.json.items():
eval('user.{} = {}'.format(field, value))
但不知什么原因,会报如下错误。并且,在Python中并不建议使用eval()
运行代码,因为这可能会有未知的风险。
正确的做法是使用内置的setattr(obj, name, value)
,它用来修改对象的属性,注意name
参数是str
类型表示属性的名称
setattr(user, 'status', 0)
因此,该接口的全部代码如下:
@bp_user.route('/modify', methods=['POST'])
def modify():
user_id = request.json.pop('id')
if not user_id:
return jsonify(status=0, message='字段缺失', data=None)
# 传来什么字段就修改哪个
user = User.query.get(user_id)
if not user:
return jsonify(status=-1, message='未找到该用户', data=None)
for field, value in request.json.items():
setattr(user, field, value)
db.session.commit()
return jsonify(status=1, message='操作成功', data=None)
假设,user和user_info表存在外键关系,user_info的user_id
字段外键对应use表的id字段,想实现级联删除/更新:
CASCADE
策略:如果外键对应表的主键行删除/更新,那么关联表的行也删除/更新cascade='all,delete'
就已经代表了级联删除和级联更新,没有update
这一项class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
username = db.Column(db.String(256), unique=True ,nullable=False)
password = db.Column(db.String(256), nullable=False)
status = db.Column(db.Integer, nullable=False, default=1)
create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)
# 关系
user_userinfo = db.relationship('UserInfo', backref='user.id', cascade='all,delete')
def __repr__(self):
desc = self.__class__.__name__ + '{'
for field in self.keys():
desc += '{}={},'.format(field, getattr(self, field))
desc += '}'
return desc
class UserInfo(db.Model):
__tablename__ = 'userinfo'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
user_id = db.Column(db.BigInteger, db.ForeignKey('user.id', ondelete='CASCADE', onupdate='CASCADE'))
sex = db.Column(db.String(8), nullable=False, default='未知')
age = db.Column(db.Integer, nullable=True)
region = db.Column(db.String(64), nullable=True)
create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)
def __repr__(self):
desc = self.__class__.__name__ + '{'
for field in self.keys():
desc += '{}={},'.format(field, getattr(self, field))
desc += '}'
return desc
SET NULL
策略:如果外键对应表的主键行删除/更新,那么关联表的行对应的外键字段设置为NULL
SET NULL
策略,而更新为CASCADE
策略:class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
username = db.Column(db.String(256), unique=True ,nullable=False)
password = db.Column(db.String(256), nullable=False)
status = db.Column(db.Integer, nullable=False, default=1)
create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)
# 关系
user_userinfo = db.relationship('UserInfo', backref='user.id', cascade='all,delete,delete-orphan')
def __repr__(self):
desc = self.__class__.__name__ + '{'
for field in self.keys():
desc += '{}={},'.format(field, getattr(self, field))
desc += '}'
return desc
class UserInfo(db.Model):
__tablename__ = 'userinfo'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
user_id = db.Column(db.BigInteger, db.ForeignKey('user.id', ondelete='SET NULL', onupdate='CASCADE'))
sex = db.Column(db.String(8), nullable=False, default='未知')
age = db.Column(db.Integer, nullable=True)
region = db.Column(db.String(64), nullable=True)
create_time = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now)
def __repr__(self):
desc = self.__class__.__name__ + '{'
for field in self.keys():
desc += '{}={},'.format(field, getattr(self, field))
desc += '}'
return desc
参考
@app.route('/user/add')
def user_add():
""" 插入 """
# 单个插入
new_user = User(
account='111111',
username='flask_test',
password='111111',
)
db.session.add(new_user)
# 回滚事务
# db.session.rollback()
# 提交事务
db.session.commit()
## 批量插入
# db.session.add_all([user0,user1,user2...])
# db.session.commit()
return '添加成功'
单个删除:
@app.route('/user/delete')
def user_delete():
""" 删除用户 """
user = User.query.get('111111')
if user:
db.session.delete(user)
db.session.commit()
return '删除成功'
return '该用户不存在'
批量删除:
User.query.filter(User.status == 0).delete(synchronize_session=False)
db.session.commit()
全部删除:
User.query.delete(synchronize_session=False)
db.session.commit()
@app.route('/user/update')
def user_update():
""" 更新 """
user = User.query.get('90217')
if user:
user.score = 666
db.session.commit()
return '修改成功'
return '该用户不存在'
@app.route('/user/list')
def user_list():
""" 查询所有 """
# 返回list
user_list = User.query.all()
return str(user_list)
@app.route('/user/get/' )
def user_get(account):
""" 根据主键查询 """
# 查询不到返回None
# user = User.query.get(account)
# 查询不到返回404NotFound
user = User.query.get_or_404(account)
return str(user)
@app.route('/user/filter')
def user_filter():
""" 过滤查询 """
## 获取多个
# filter_by:多字段,之间and关系
# users = User.query.filter_by(isAdmin=1).all()
# filter: 参数是 SQL Expression
# 等于 ==
users = User.query.filter(User.isAdmin == 0).all()
# 不等于 !=
# users = User.query.filter(User.isAdmin != 0).all()
# 模糊查询
# users = User.query.filter(User.username.like('%ang')).all()
# 在范围 in_
# users = User.query.filter(User.username.in_(['Shuang','Azir'])).all()
# 不在范围 ~ in_
# users = User.query.filter(~User.username.in_(['Shuang', 'Azir'])).all()
# 为Null == None
# users = User.query.filter(User.avatarUrl==None).all()
# 不为Null != None
# users = User.query.filter(User.avatarUrl != None).all()
# 或 or_
# users = User.query.filter(or_(
# User.score == 0,
# User.level == 0
# )).all()
## 获取第1个
user = User.query.filter(User.isAdmin == 0).first()
resp = '''
[.all()] users: {}
[.first()] user: {}
'''.format(users, user)
return resp
@bp_user.route('/list', methods=['GET'])
def list_user():
# 按照create_time降序排序
user_list = User.query.order_by(User.create_time.desc()).all()
return jsonify(status=1, message='获取成功', data=data={
'title': User.keys(),
'user_list': user_list
})
@bp_user.route('/list', methods=['GET'])
def list_user():
# 必须是int类型,因为paginate()要求就是传int
current = request.args.get('current', type=int)
size = request.args.get('size', type=int)
# 分页, error_out=False表示没查到返回空列表`[]`
pagination = User.query.order_by(User.create_time.desc()).paginate(page=current, per_page=size, error_out=False)
return jsonify(status=1, message='获取成功', data={
'title': User.keys(),
'user_list': pagination.items,# pagination.items: 返回当前页的内容列表
'current': current,
'size': size,
'pages': pagination.pages,
'has_next': pagination.has_next,
'has_prev': pagination.has_prev,
'total': pagination.total,
})
from sqlalchemy import func
@bp_user.route('/count', methods=['GET'])
def count_user():
""" 获取用户数量 """
user_count = User.query(func.count())
return jsonify(status=1, message='获取成功', data=user_count)
@bp_user.route('/allPassword', methods=['GET'])
def all_password():
""" 获取所有用户都使用了哪些密码 """
user_list = User.query.with_entities(User.password.distinct()).all()
distinct_passwords = [row[0] for row in user_list]
return jsonify(status=1, message='获取成功', data=distinct_passwords)
from src.db_model import Correct
from itertools import groupby
# 查询整个列表
correct_list = Correct.query.order_by(Correct.create_time.desc()).all()
# 以uuid4作为分组字段
grouped_data = groupby(correct_list, lambda c: c.uuid4)
# 遍历数据, k:分组字段的实际值, v:分组内的实体列表
for k, v in grouped_data:
list_for_key = [d for d in v]
print(k, '=>', list_for_key)
import memcache
# 在连接之前,一定要先启动memcached
client = memcache.Client({'127.0.0.1:11211'}, debug=True)
username = client.set('username', 'lzc', time=60)
client.set_multi({'title': '美君!', 'content': '你好,在吗'}, time=60)
print(username)
from redis import Redis
HOST = '127.0.0.1'
IP = 6379
PASSWORD = 'your_password'
pedis = Redis(host=HOST, port=IP, db=1, password=PASSWORD, decode_responses=True)
def demo_keys():
keys = pedis.keys("socketex:message:*")
for key in keys:
data = pedis.hgetall(key)
print(data)
key = 'username'
# 获取
print(pedis.get(key))
# 设置
pedis.set(key, '魏德曼')
print(pedis.get(key))
# 删除
pedis.delete(key)
print(pedis.get(key))
key = 'language'
# lpush
pedis.lpush(key, 'Java','Python')
# rpush
pedis.rpush(key, 'C++','C#')
pedis.lpush(key, 'JavaScript')
# 获取范围内的元素: JavaScript Python Java C++ C#
print(pedis.lrange(key, 0, -1))
# 删除
pedis.delete(key)
key = 'team'
# 添加元素
pedis.sadd(key, 0)
pedis.sadd(key, '1')
pedis.sadd(key, 1)
pedis.sadd(key, '2')
pedis.sadd(key, 1)
# 获取元素
print(pedis.smembers(key))
# 获取元素个数
print(pedis.scard(key))
# 判断元素是否在set种
print(pedis.sismember(key,'2'))
# 删除
pedis.delete(key)
key = 'web'
# 设置一个
pedis.hset(key, 'baidu', 'www.baidu.com')
pedis.hset(key, 'jd', 'www.jd.com')
# 获取一个
print(pedis.hget(key,'baidu'))
# 获取所有
print(pedis.hgetall(key))
print('='*40)
# 获取keys
print(pedis.hkeys(key))
# 获取values
print(pedis.hvals(key))
print('=' * 40)
# field不存在添加,否则不执行
pedis.hsetnx(key,'ncut','www.ncut.edu.cn')
pedis.hsetnx(key,'jd','www.360buy.com')
print(pedis.hgetall(key))
# 删除
pedis.delete(key)
pipe = pedis.pipeline()
pipe.set('account', '90217')
pipe.set('password', '123abc')
pipe.execute()
## 发布与订阅功能->异步发送邮件
key = 'email'
ps = pedis.pubsub() # 获取对象
ps.subscribe(key) # 订阅频道
# 监听
def listen():
while True:
for item in ps.listen(): # 持续监听,这是一个生成器
if item['type'] == 'message':
data = item['data']
print(data)
t_listen = threading.Thread(target=listen)
t_listen.start()
# 发布消息
def publish():
while True:
pedis.publish(key, '[[email protected]]发来的邮件: '+str(time.time()))
time.sleep(random.random()*4) # 随机等待一段时间
t_publish = threading.Thread(target=publish)
t_publish.start()