基础flask开发时遇到的问题总结
flask开发小Demo
涉及的知识点:
蓝图, 配置文件, flask-session, flask-sqlalchemy, flask-script, flask-migrate....
遇到的小坑。。。
1.应该把引用的蓝图对象放到create_app中:
import os from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_session import Session from exts.auth import Auth db = SQLAlchemy() auth = Auth() def create_app(): app = Flask(__name__) app.config.from_object('settings.DevelopmentConfig') app._static_folder = os.path.abspath("static/") from flaskDemo3.views.account import ac from flaskDemo3.views.home import home from flaskDemo3.views.host import host app.register_blueprint(ac) app.register_blueprint(home) app.register_blueprint(host) Session(app) db.init_app(app) auth.init_app(app) return app
2.在使用context_processor给全局模板传变量的时候,应该返回一个字典,并且模板中使用key来调用变量
def init_app(self, app):
app.auth_manage = self
self.app = app
app.before_request(self.check_login)
app.context_processor(self.context_processor)
def context_processor(self): user_info = session.get('user_info') return dict(current_user=user_info) # 模板中使用
3. 通过flask-sqlalchemy来插入和更新数据时,有两种方式,第一种通过原生sql,第二种通过sqlalchremy的add方法:
############插入数据#############
# 第一种:对于字段很多的对象,这种方式比较方便。 db.session.execute('insert into users(name, pwd, age) values(:user, :pwd, :age)', form.data) db.session.commit() db.session.remove() # 第二种: user = form.data['user'] pwd = form.data['pwd'] obj = models.Users(name=user, pwd=pwd) db.session.add(obj) db.session.commit() db.session.remove()
################更新数据##########
title = form.data.get('title')
ip = form.data.get('ip')
depart = form.data.get('depart')
db.session.query(models.Hosts).filter(models.Hosts.id == pk).update({models.Hosts.title:title, models.Hosts.ip:ip,
models.Hosts.depart:depart})
4. 用wtforms定义字段的时候,不要在某个字段类,比如SelectField中,进行数据库操作,容易报错:
No application found. Either work inside a view function or push an application context.
有两种解决办法:
第一种: 最下面通过init来赋值 def __init__(self, *args, **kwargs): super(HostForm, self).__init__(*args, **kwargs) self.depart.choices = db.session.query(models.Depart.id, models.Depart.title).all() 第二种: 在视图中赋值 form = MenuForm() if request.method == "GET":
form.depart.choices = [(v.id, v.title) for v in db.session.query(models.Depart).all()]
5. 反向查询的应用注意:
from sqlalchemy import Column, String, Integer,ForeignKey from sqlalchemy.orm import relationship # model.py: class Hosts(db.Model): id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(32), nullable=False) ip = Column(String(32),nullable=False) depart = Column(Integer,ForeignKey('depart.id')) dps = relationship('Depart', backref='hosts') class Depart(db.Model): id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(32), nullable=False)
#############查询所有主机的名称和部门名称######## host_list = db.session.query(models.Hosts).all() for item in host_list: print(item.title, item.dps.title) #############查询部门id为2的所有主机名称和部门名称####### dep_obj = db.session.query(models.Depart).filter(models.Depart.id==2).first() host_list = dep_obj.hosts for item in host_list: print(item.title, item.dps.title)
6. 关于模板中,静态文件的路径问题:
静态文件路径常见几种写法:
第一种: 注意前面的反斜杠一定加上。
<link rel="shortcut icon" href="/static/imgs/luffy-study-logo.png">
第二种:
<img class="logo" src="{{ url_for('static', filename='imgs/logo.svg') }}">
7. 通过wtforms做更新操作,带上原来的数据到模板。
wtforms做更操作时,带上原有的数据:
if request.method == 'GET':
form = HostForm()
form.title.data = host_obj.title
form.ip.data = host_obj.ip
form.depart.data = host_obj.depart
return render_template('change.html', form=form)
8. 关于浏览器访问服务器图片
@ac.route('/media/<username>') def get_img(username): user_obj = db.session.query(models.UserInfo).filter(models.UserInfo.name==username).first() avatar = user_obj.avatar filepath = 'media/imgs/%s' % (avatar) # 注意路径的拼接 # print(filepath) return send_file(filepath)
# user_obj.avatar存的是图片的名称default.png。
# 前端根据模板字符串就可以获取:
<p><img src="/media/{{ current_user['user'].name }}" style="width: 56px; height: 56px;"></p>
9. 通过sqlAlchemy查询操作完后:

可以执行db.session.remove(),但是不需要commit()。不然会报错!
记住,更新数据完后,要commit()

10.Parent instance <User at 0x2ceb5aaa160> is not bound to a Session;lazy load operation of attribute 'dep' cannot proceed (Background on this error at: http://sqlalche.me/e/13/bhk3)
这种情况主要是: session 已经被提交,导致操作的 model 对象已经不在当前 session 中了。
举例:
current_app.auth_manager.login({'id': uid, 'user': user_obj})
往session中存了对象后,又取出,通过外键去查询某些字段的时候,就会报这个错。
# 解决办法:
登录成功后,可以往session中存一个该用户的唯一值,比如用户名,id, token等,然后再需要获取对象某些字段值的地方:
user_dict = session.get('user_info')
username = user_dict['user']
user_obj = db.session.query(models.User).filter(models.User.name==username).first()
print(user_obj.name, user_obj.dep.title)
----------------------未完待续

浙公网安备 33010602011771号