error: [Errno 13] Permission denied:python安装包的时候报出权限错误的解决办法
error: [Errno 13] Permission denied:小编今天在安装Python的衣蛾自定义模块的时候,安装不上,提示权限错误,这种错误的解决办法也是比较好解决的。只需要使用root权限就可以了,简单粗暴的解决问题了,是不是很简单呢。
解决办法:
sudo + 命令 error: [Errno 13] Permission denied:小编今天在安装Python的衣蛾自定义模块的时候,安装不上,提示权限错误,这种错误的解决办法也是比较好解决的。只需要使用root权限就可以了,简单粗暴的解决问题了,是不是很简单呢。
解决办法:
sudo + 命令 bulk_save_objects:速度中等,稳定高test_table:需要添加的数据列表
User:添加的实体对象
for k,v in enumerate(test_table):
session.bulk_save_objects(
[
User(rank=k+1)
]
)
session.commit()session.query(User).filter(User.district=='shandong').update({User.arrress: '中国'})
session.commit()session.query(User).filter(User.district=='shandong').delete()
session.commit() 由于浏览器受同源策略的限制,在使用XMLHttpRequest对象进行跨域请求时,请求的时候会出现No 'Access-Control-Allow-Origin' header is present on the requested resource的问题,导致请求失败。
解决办法:
app = Flask(__name__)
# 跨域支持
def after_request(response):
#JS前端跨域支持
response.headers['Cache-Control'] = 'no-cache'
response.headers['Access-Control-Allow-Origin'] = '*'
return response
app.after_request(after_request) 信号通过发送发生在核心框架的其它地方或 Flask 扩展的动作时的通知来帮助你解耦应用。简而言之,信号允许特定的发送端通知订阅者发生了什么。使用信号分为3步,定义信号,监听信号,发送信号。
定义信号:定义信号需要使用到blinker这个包的Namespace类来创建一个命名空间。比如定义一个在访问了某个视图函数的时候的信号。示例代码如下:
# Namespace的作用:为了防止多人开发的时候,信号名字冲突的问题
from blinker import Namespace
my_signal = Namespace()
visit_signal = my_signal.signal('my_signal')监听信号:监听信号使用singal对象的connect方法,在这个方法中需要传递一个函数,用来接收以后监听到这个信号该做的事情。示例代码如下:
mysignal.connect(visit_func)发送信号:发送信号使用singal对象的send方法,这个方法可以传递一些其他参数过去。示例代码如下:
my_signal.send(username='xiaoning')template_rendered:模版渲染完成后的信号。before_render_template:模版渲染之前的信号。request_started:模版开始渲染。request_finished:模版渲染完成。request_tearing_down:request对象被销毁的信号。got_request_exception:视图函数发生异常的信号。一般可以监听这个信号,来记录网站异常信息。appcontext_tearing_down:app上下文被销毁的信号。appcontext_pushed:app上下文被推入到栈上的信号。appcontext_popped:app上下文被推出栈中的信号message_flashed:调用了Flask的flashed方法的信号。在Flask中处理请求时,应用会生成一个“请求上下文”对象。整个请求的处理过程,都会在这个上下文对象中进行。这保证了请求的处理过程不被干扰。
在Flask中,类似于request的对象,其实是绑定到了一个werkzeug.local.Local对象上。这样,即使是同一个对象,那么在多个线程中都是隔离的。
应用上下文和请求上下文都是存放到一个LocalStack的栈中。和应用app相关的操作就必须要用到应用上下文,比如通过current_app获取当前的这个app。和请求相关的操作就必须用到请求上下文,比如使用url_for反转视图函数。
如果想要在视图函数外面执行相关的操作,比如获取当前的app(current_app),或者是反转url,那么就必须要手动推入相关的上下文:
手动推入app上下文:
# 第一种方式:
app_context = app.app_context()
app_context.push()
# 第二种方式:
with app.app_context():
print(current_app)手动推入请求上下文:推入请求上下文到栈中,会首先判断有没有应用上下文,如果没有那么就会先推入应用上下文到栈中,然后再推入请求上下文到栈中:
with app.test_request_context():
print(url_for('my_list'))注意: 为什么上下文需要放在栈中:
g对象是在整个Flask应用运行期间都是可以使用的。并且他也是跟request一样,是线程隔离的。这个对象是专门用来存储开发者自己定义的一些数据,方便在整个Flask程序中都可以使用。一般使用就是,将一些经常会用到的数据绑定到上面,以后就直接从g上面取就可以了,而不需要通过传参的形式,这样更加方便。
在Flask中钩子函数是使用特定的装饰器装饰的函数。那么这种函数就叫做钩子函数。
before_first_request:Flask项目第一次部署后会执行的钩子函数。before_request:请求已经到达了Flask,但是还没有进入到具体的视图函数之前调用。一般这个就是在视图函数之前,我们可以把一些后面需要用到的数据先处理好,方便视图函数使用。context_processor:使用这个钩子函数,必须返回一个字典。这个字典中的值在所有模版中都可以使用。这个钩子函数的函数是,如果一些在很多模版中都要用到的变量,那么就可以使用这个钩子函数来返回,而不用在每个视图函数中的render_template中去写,这样可以让代码更加简洁和好维护。errorhandler:在发生一些异常的时候,比如404错误,比如500错误。那么如果想要优雅的处理这些错误,就可以使用errorhandler来出来。需要注意几点:
flask.abort可以手动的抛出相应的错误,比如开发者在发现参数不正确的时候可以自己手动的抛出一个400错误。flask中的WTForms的主要作用就是做表单验证,把用户提交上来的数据进行验证是否合法,也就类似于表单验证,还可以做模版渲染。
做表单验证:
validators指定验证器,验证器的格式是一个列表。以后在视图中,就只需要使用这个表单类的对象,并且把需要验证的数据,也就是request.form传给这个表单类,以后调用form.validate()方法,如果返回True,那么代表用户输入的数据都是合法的,否则代表用户输入的数据是有问题的。如果验证失败了,那么可以通过form.errors来获取具体的错误信息。
示例代码如下:
ReistForm类的代码:
class RegistForm(Form):
username = StringField(validators=[Length(min=3,max=10,message='用户名长度必须在3到10位之间')])
password = StringField(validators=[Length(min=6,max=10)])
password_repeat = StringField(validators=[Length(min=6,max=10),EqualTo("password")])视图函数中的代码:
form = RegistForm(request.form)
if form.validate():
return "success"
else:
print(form.errors)
return "fail"Email:验证上传的数据是否为邮箱。EqualTo:验证上传的数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等。InputRequir:原始数据的需要验证。如果不是特殊情况,应该使用InputRequired。Length:长度限制,有min和max两个值进行限制。NumberRange:数字的区间,有min和max两个值限制,如果处在这两个数字之间则满足。Regexp:自定义正则表达式进行验证。URL:验证是否是URL格式。UUID:验证是否是UUID格式。注意:在验证器里面我们可以通过message来指定错误的返回内容。
validate_字段名(self,filed)。field.data可以获取到这个字段的具体的值。如果数据满足条件,那么可以什么都不做。如果验证失败,那么应该抛出一个wtforms.validators.ValidationError的异常,并且把验证失败的信息传到这个异常类中。
示例代码:
captcha = StringField(validators=[Length(4,4)])
def validate_captcha(self,field):
if field.data != 'sunxiaoning':
raise ValidationError('验证码错误!')Flask-SQLAlchemy是针对flask开发而封装的一个包,这里面使得SQLAlchemy操作更方便,基本用法和SQLAlchemy类似。
pip install flask-sqlalchemySQLALCHEMY_DATABASE_URI这个键放到app.config中。示例代码:app.config["SQLALCHEMY_DATABASE_URI"] = DB_URI.flask_sqlalchemy.SQLAlchemy这个类定义一个对象,并将app传入进去。示例代码:db = SQLAlchemy(app)。示例代码:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
HOSTNAME = '' # 主机地址
PORT = '3306' # 端口号
DATABASE = '' # 数据库
USERNAME = '' # 数据库账号
PASSWORD = '' # 数据库密码
# dialect+driver://username:password@host:port/database
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)delarative_base来创建一个基类。而是使用db.Model来作为基类。Column、String、Integer以及relationship等,都不需要导入了,直接使用db下面相应的属性名就可以了。__tablename__,那么flask_sqlalchemy会默认使用当前的模型的名字转换成小写来作为表的名字,并且如果这个模型的名字使用了多个单词并且使用了驼峰命名法,那么会在多个单词之间使用下划线来进行连接。虽然flask_sqlalchemy给我们提供了这个特性,但是不推荐使用。db.drop_all()db.create_all()以后session也不需要使用sessionmaker来创建了。直接使用db.session就可以了。操作这个session的时候就跟之前的sqlalchemy的session是一样的。
在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段。注意:从表中外键的字段,必须和父表的主键字段类型保持一致。
示例代码如下:
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
class Article(Base):
__tablename__ = 'article'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
content = Column(Text,nullable=False)
# 外键
uid = Column(Integer,ForeignKey("user.id"))外键约束有以下几项:
SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问。
示例代码:
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
# articles = relationship("Article")
def __repr__(self):
return "<User(username:%s)>" % self.username
class Article(Base):
__tablename__ = 'article'
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
uid = Column(Integer,ForeignKey("user.id"))
author = relationship("User",backref="articles")另外,可以通过backref来指定反向访问的属性名称。articles是有多个。他们之间的关系是一个一对多的关系。
在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一个uselist=False这个参数进去。就是告诉父模型,以后引用这个从模型的时候,不再是一个列表了,而是一个对象了。
示例代码:
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
extend = relationship("UserExtend",uselist=False)
def __repr__(self):
return "<User(username:%s)>" % self.username
class UserExtend(Base):
__tablename__ = 'user_extend'
id = Column(Integer, primary_key=True, autoincrement=True)
school = Column(String(50))
uid = Column(Integer,ForeignKey("user.id"))
user = relationship("User",backref="extend")当然,也可以借助sqlalchemy.orm.backref来简化代码:
class User(Base):
__tablename__ = 'user'
id = Column(Integer,primary_key=True,autoincrement=True)
username = Column(String(50),nullable=False)
# extend = relationship("UserExtend",uselist=False)
def __repr__(self):
return "<User(username:%s)>" % self.username
class UserExtend(Base):
__tablename__ = 'user_extend'
id = Column(Integer, primary_key=True, autoincrement=True)
school = Column(String(50))
uid = Column(Integer,ForeignKey("user.id"))
user = relationship("User",backref=backref("extend",uselist=False))ORM层面删除数据,会无视mysql级别的外键约束。直接会将对应的数据删除,然后将从表中的那个外键设置为NULL。如果想要避免这种行为,应该将从表中的外键的nullable=False。
在SQLAlchemy,只要将一个数据添加到session中,和他相关联的数据都可以一起存入到数据库中了。这些是怎么设置的呢?其实是通过relationship的时候,有一个关键字参数cascade可以设置这些属性:
在一对多,或者多对多的时候,如果想要获取多的这一部分的数据的时候,往往能通过一个属性就可以全部获取了。比如有一个作者,想要或者这个作者的所有文章,那么可以通过user.articles就可以获取所有的。但有时候我们不想获取所有的数据,比如只想获取这个作者今天发表的文章,那么这时候我们可以给relationship传递一个lazy='dynamic',以后通过user.articles获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。
通过lazy='dynamic',获取出来的多的那一部分的数据,就是一个AppenderQuery对象了。这种对象既可以添加新数据,也可以跟Query一样,可以再进行一层过滤。
总而言之一句话:如果你在获取数据的时候,想要对多的那一边的数据再进行一层过滤,那么这时候就可以考虑使用lazy='dynamic'。
lazy可用的选项:
select:这个是默认选项。还是拿user.articles的例子来讲。如果你没有访问user.articles这个属性,那么sqlalchemy就不会从数据库中查找文章。一旦你访问了这个属性,那么sqlalchemy就会立马从数据库中查找所有的文章,并把查找出来的数据组装成一个列表返回。这也是懒加载。dynamic:这个就是我们刚刚讲的。就是在访问user.articles的时候返回回来的不是一个列表,而是AppenderQuery对象。子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点。不用写多个sql语句就可以实现一些复杂的查询。那么在sqlalchemy中,要实现一个子查询,应该使用以下几个步骤:
query对象后面执行subquery方法,将这个查询变成一个子查询。label方法,取个别名。在父查询中,如果想要使用子查询的字段,那么可以通过子查询的返回值上的c属性拿到。
整体的示例代码如下:
stmt = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='sunxiaoning').subquery()
result = session.query(User).filter(User.city==stmt.c.city,User.age==stmt.c.age).all()查询内容
模型中的属性。可以指定只查找某个模型的其中几个属性。
user = session.query(User).first()
username = session.query(User.username).first()equals:
user = session.query(User).filter(User.name == "sunxiaoning").first()not equals:
query.filter(User.username != 'sunxiaoning').all()like:
query.filter(User.username.like('%ning%'))in:
query.filter(User.username.in_(['sun','xiao','ning']))
query.filter(User.username.in_(
session.query(User.username).filter(User.username.like('%sun%'))
))not in:
query.filter(~User.username.in_(['sun','xiao','ning']))is null:
query.filter(User.username==None)
# OR
query.filter(User.username.is_(None))is not null:
query.filter(User.username != None)
# OR
query.filter(User.username.isnot(None))and:
from sqlalchemy import and_
query.filter(and_(User.username=='sun', User.age<18))
# 或者是传递多个参数
query.filter(User.username=='sun', User.age<18)
# 或者是通过多次filter操作
query.filter(User.username=='sun').filter(User.age<18)or:
from sqlalchemy import or_
query.filter(or_(User.username=='sun', User.age<18))MATCH:
query.filter(User.username.match('sun'))SQLAlchemy中filter()和filter_by()的区别:
1、filter引用列名时,使用“类名.属性名”的方式,比较使用两个等号“==”
2、filter_by引用列名时,使用“属性名”,比较使用一个等号“=”
3、在使用多条件匹配的时候,filter需要借助sqlalchemy里的and_ ; 而filter_by不需要,直接把多个匹配条件写在一起
4、在使用多条件匹配时,用到>=、>、<=、<的情况,貌似不能使用filter_by。可能是姿势不对
order_by:可以指定根据这个表中的某个字段进行排序,如果在前面加了一个-,代表的是降序排序。在模型定义的时候指定默认排序:有些时候,不想每次在查询的时候都指定排序的方式,可以在定义模型的时候就指定排序的方式。有以下两种方式:
在模型定义中,添加以下代码:
__mapper_args__ = {
"order_by": _id
}desc()方法,或者是在排序的时候使用这个字段的字符串名字,然后在前面加一个负号。Query定义了一个很方便的计数函数count()
切片:可以对Query对象使用切片操作,来获取想要的数据。可以使用slice(start,stop)方法来做切片操作。也可以使用[start:stop]的方式来进行切片操作。一般在实际开发中,中括号的形式是用得比较多的。希望大家一定要掌握。示例代码如下:
users = session.query(User).order_by(User._id.desc())[0:10]func.sum:求和。
func上,其实没有任何聚合函数。但是因为他底层做了一些魔术,只要mysql中有的聚合函数,都可以通过func调用。
session.query(func.count(User.id)).all()根据某个字段进行分组。比如想要根据性别进行分组,来统计每个分组分别有多少人,那么可以使用以下代码来完成:
session.query(User.username,func.count(User.id)).group_by(User.username).all()having是对查找结果进一步过滤。比如只想要看未成年人的数量,那么可以首先对年龄进行分组统计人数,然后再对分组进行having过滤。示例代码如下:
result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()