Flask基本的综合使用
下面案例主要展示二手车信息页、详情页和用户浏览记录、收藏信息
Flask综合案例展示二手车信息页、详情页和用户浏览记录,收藏信息
展示信息页
展示车辆详情页
添加和展示收藏信息(MySql存储)
flask-sqlalchemy 数据多对多关系
怎么添加两者关系到中间表
查询关系
浏览记录(redis存储)
前端js展示数据逻辑:
展示信息页
逻辑思路:
- 根据图我们可以得到需要返回的数据
- 在models的车类中添加方法返回我们需要的数据
- 然后根据前端查询车的品牌、模型等各种信息不同展示数据,这里只简单写了品牌和模型
models.py文件添加方法:
class Car(db.Model):
...
def to_list_dict(self):
# 返回列表页的数据
# 需要的数据:品牌,模型 detail
# 价格,年份,公里数 id 默认图片
car_obj_dict = {
'brand': self.brande.name,
'model': self.model.name,
'detail': self.model.detail,
'price': self.price,
'car_register_time': self.annual_datetime,
'car_distance': self.car_distance,
'car_id': self.id,
# 默认图片
'index_image_url': QINIUURL+self.index_image_url
}
return car_obj_dict
然后是展示数据的函数:
@api.route('/cars')
def cars_list_info():
# 将是一个get请求,返回车辆列表
# 有可能为空
brand = request.args.get('brand')
car_model = request.args.get('model')
print(request.args.get('price'))
if len(brand) == 0 and len(car_model) == 0:
cars_lists = Car.query.all()
print(cars_lists)
ret_data_list = []
for each in cars_lists:
# 调用对象的方法来实现转dict
ret = each.to_list_dict()
print(ret)
# 添加进字典
ret_data_list.append(ret)
print(ret_data_list)
return jsonify(data=ret_data_list)
elif len(brand) == 0 and len(car_model) !=0:
# 只有型号没有品牌
car_lists = Car.query.all()
ret_data_list = [] # todo 需要返回的数据
for each in car_lists:
if each.brande.car_model == car_model:
print(car_model)
return jsonify(data=ret_data_list)
elif len(brand) != 0 and len(car_model) ==0:
# 只有品牌
brand_id = Brande.query.filter_by(name=brand).first().id
cars_lists = Car.query.filter_by(brande_id=brand_id).all()
ret_data_list = [] # todo 需要返回的数据
for each in cars_lists:
# 调用对象的方法来实现转dict
ret = each.to_list_dict()
print(ret)
# 添加进字典
ret_data_list.append(ret)
return jsonify(data=ret_data_list)
return jsonify(msg='ok')
展示车辆详情页
- 还是写个方法返回需要的数据,因为需要的数据太多,这里不多写
- 然后写一个接口返回数据,而且详情页需要添加当前的车辆id到redis中,以便后来查询用户的浏览记录
@api.route('/car_detail')
def cat_detail():
# 这个是详情页,只需要获取car_id
car_id = request.args.get('car_id')
car_obj = Car.query.get(car_id)
# 检验数据是否为空
if not car_obj:
return jsonify(errcode=constant.RET_CAR_NOTFOUND, errmsg='car_id出错')
# todo 当用户登录的情况下,存储car_id到redis数据库8中,类型用列表,有个g变量存了user_id
user_id = session.get('user_id')
if user_id:
try:
history_key = 'history_%s' % user_id
# 可能插入重复,所以要删除原来的再加入
redis_store.lrem(history_key, 0, car_id)
# 进行存储,左插入,获取使用lrange
redis_store.lpush(history_key, car_id)
except Exception as e:
print(e)
return jsonify(errcode=constant.RET_REDIS_INSERT_ERR, errmsg='redis插入错误')
print(request.args)
print(car_obj) # todo 获取到了这辆车,然后展示六个表内容和图片,to_detail_dict()
# todo 防止频繁访问mysql,存进redis
redis_key = 'mysql-redis_%s' % car_id # 存进redis的key名
redis_data = redis_store.get(redis_key)
if redis_data:
# 注意bytes转码
ret_dict = redis_data.decode()
else:
# 字典存进redis要序列化
try:
ret_dict = json.dumps(car_obj.to_detail_dict())
redis_store.set(redis_key, ret_dict, constant.CAR_INFO_REDIS_EXPIRES)
except Exception as e:
print(e)
return jsonify(errcode=constant.RET_REDIS_INSERT_ERR, errmsg='redis插入错误')
# 返回信息,和data
ret_dict = json.loads(ret_dict)
return jsonify(msg='ok', data=ret_dict)
添加和展示收藏信息(MySql存储)
逻辑思路:
- 首先要验证是否登录,然后session获取user_id
- 在用户登录的前提下,添加收藏信息函数为:collect_cars(),添加数据到多对多关系表中
- 然后是展示收藏数据函数为:show_collect(),直接查询返回即可
相关代码,这里面重点是多对多关系表的建立和操作
@api.route('/collect')
@login_required
def collect_cars():
# todo 收藏车,根据get发送的carid
car_id = request.args.get('car_id')
car_obj = Car.query.get(car_id)
# 分别获取car和user对象,收藏是车对用户,1对多
user_id = session.get('user_id')
user_obj = User.query.get(user_id)
# 判断非空
if not all([car_obj, user_obj]):
return jsonify(msg='用户不存在', code=constant.USER_NOT_LOGIN)
try:
print('car_obj.users')
# 这是收藏车
car_obj.users.append(user_obj)
db.session.commit()
except Exception as e:
print(e)
db.session.rollback()
return jsonify(msg='db数据库出错', code=constant.DB_COMMIT_ERR)
return jsonify(msg='ok', code=constant.RET_OK)
@api.route('/show_collect')
@login_required
def show_collect():
# 收藏数据,是多对多关系
user_id = session.get('user_id')
user_obj = User.query.get(user_id)
user_phone = user_obj.phone
# 判断非空
if not user_obj:
return jsonify(msg='用户不存在', code=constant.USER_NOT_LOGIN)
# print(user_obj.cars)
# 如果收藏为空则返回msg=null
if not len(user_obj.cars):
return jsonify(msg='null', code=constant.RET_CAR_NOTFOUND)
# 返回的数据列表
ret_list = []
for car_obj in user_obj.cars:
ret_list.append(car_obj.to_list_dict())
return jsonify(code=constant.RET_OK, data=ret_list, user_phone=user_phone)
flask-sqlalchemy 数据多对多关系
如何创建多对多关系,在models文件添加中间表模型,SqlAlchemy会自动帮你处理多对多关系
# 这个是系统会帮你创建的中间表
registrations = db.Table("registrations",
# 字段名sc_user_id关联的是用户id
db.Column("sc_user_id", db.Integer, db.ForeignKey("sc_users.id")),
# 字段名sc_car_id关联车的id
db.Column("sc_car_id", db.Integer, db.ForeignKey("sc_cars_info.id"))
)
class User(db.Model):
__tablename__ = 'sc_users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20), unique=True, nullable=True)
password = db.Column(db.String(100), nullable=True)
phone = db.Column(db.String(11), nullable=False)
# # 与car表建立联系,backref表示可以通过car.user_set查询,secondary指定副表名称
cars = db.relationship("Car",
secondary=registrations,
backref=db.backref("user_set", lazy="dynamic"))
class Car(db.Model):
__tablename__ = 'sc_cars_info'
id = db.Column(db.Integer, primary_key=True)
# 关联user
users = db.relationship('User', secondary=registrations,
backref=db.backref('cars_set'), lazy='dynamic')
创建之后记得迁移
怎么添加两者关系到中间表
- 截取一段代码,car_obj和user_obj分别是查询得到的Car和User对象
- 利用append()添加对象就是添加两者的关系,例子为用户收藏了某车辆,收藏关系是人对车是多对多
try:
print('car_obj.users')
# 这是收藏车
car_obj.users.append(user_obj)
db.session.commit()
except Exception as e:
print(e)
db.session.rollback()
return jsonify(msg='db数据库出错', code=constant.DB_COMMIT_ERR)
查询关系
- 直接查询User对象的cars属性即可,是一个列表存储着car对象
# 收藏数据,是多对多关系
user_id = session.get('user_id') # 查询到登录信息,并得到user对象
user_obj = User.query.get(user_id)
ret_list = [] # 返回的数据列表
for car_obj in user_obj.cars:
# 遍历user对象的cars属性即可
ret_list.append(car_obj.to_list_dict())
return jsonify(code=constant.RET_OK, data=ret_list, user_phone=user_phone)
浏览记录(redis存储)
逻辑思路:
- 首先要验证是否登录,然后session获取user_id
- 在用户登录的前提下,当用户访问详情页(详情页接口函数写)的时候存储car_id到redis数据库中,类型用列表
- 然后写一个接口返回用户浏览记录数据
返回用户浏览数据代码:
@api.route('/userhistory')
@login_required
def user_history():
# 用户的浏览记录,放在redis中存储,打开车辆详情页就存储,用户登录才保存
user_id = session.get('user_id')
user_obj = User.query.get(user_id)
# 判断非空
if not user_obj:
return jsonify(msg='用户不存在', code=constant.USER_NOT_LOGIN)
history_key = 'history_%s' % user_id
# 判断redis是否存在数据
redis_data = redis_store.lrange(history_key, 0, -1)
if redis_data:
ret_list = []
try:
for car_id in redis_data:
# 取出来是Bytes类型
car_id = car_id.decode()
print(car_id)
car_obj = Car.query.get(car_id)
ret_list.append(car_obj.to_list_dict())
return jsonify(code=constant.RET_OK, data=ret_list)
except Exception as e:
return jsonify(msg='redis数据库出错', code=constant.RET_REDIS_OUTPUT_ERR)
return jsonify(msg='null', code=constant.RET_CAR_NOTFOUND)
前端js展示数据逻辑:
- 向后端发送请求浏览数据信息,获得一个字典里两个key值,当msg的值不为ok时则展示内容为空,否则去遍历data值,然后展示所有内容
/**
* Created by phoebobo on 2019/7/12.
*/
$(function () {
var get_url = 'http://127.0.0.1:5000/api/v1.0/userhistory';
$.ajax({
url: get_url,
type: 'GET',
xhrFields: {
withCredentials: true
},
success: function (ret) {
console.log(ret);
if (ret['code'] != 0){
console.log('errrrrr');
$('.car_cate_item').append("<p id='p1'>暂无收藏车辆</p><a href='https://www.guazi.com/hz/buy/'><p id='p2'>去逛逛瓜子海量车源")
}
else {
var data = ret['data'];
var str = "<li class='car_detail'>";
$.each(data, function (index, dict) {
console.log(index, dict);
str +="<a href='carDetail.html?car_id="+dict.car_id+"' class='to_car_detail'>" +
"<img src='"+dict.index_image_url+"' width='180px' height='120px'/>" +
"<p class='cate_car_title'>"
+dict.brand+' '+dict.model+' '+dict.detail+ "</p><p class='cate_intro_car'>"
+'¥'+dict.price+'万 '+dict.car_register_time+' ' +dict.car_distance+'万里程'+"</p></a>";
});
str += "</li>";
$('.car_cate_item').html(str);
}
},
error: function (data) {
console.log(data)
}
})
});