snjl

我大概率会编程。


  • 首页

  • 标签

  • 分类

  • 归档

  • 搜索

flask:WTF扩展

发表于 2019-02-13 | 分类于 flask
字数统计: 1.4k 字 | 阅读时长 ≈ 6 分钟

Web应用程序的一个重要方面是为用户提供一个用户界面。 HTML提供了一个

标签,用于设计一个接口。 可以适当使用表单的元素,如文本输入,广播,选择等。

通过GET或POST方法将用户输入的数据以Http请求消息的形式提交给服务器端脚本。

  • 服务器端脚本必须从http请求数据重新创建表单元素。 所以实际上,表单元素必须被定义两次 - 一次是HTML,一次是服务器端脚本。
  • 使用HTML表单的另一个缺点是很难(如果不是不可能)动态地呈现表单元素。 HTML本身无法验证用户的输入。

这就是WTForms,一个灵活的表单,渲染和验证库来得方便的地方。 Flask-WTF扩展为这个WTForms库提供了一个简单的接口。

使用Flask-WTF,可以在Python脚本中定义表单域并使用HTML模板来呈现它们。 也可以将验证应用于WTF字段。

阅读全文 »

flask:文件上传

发表于 2019-02-13 | 分类于 flask
字数统计: 481 字 | 阅读时长 ≈ 2 分钟

在Flask中处理文件上传非常简单。 它需要一个enctype属性设置为’multipart/form-data’的HTML表单,将该文提交到指定URL。 URL处理程序从request.files[]对象中提取文件并将其保存到所需的位置。

每个上传的文件首先保存在服务器上的临时位置,然后再保存到最终位置。 目标文件的名称可以是硬编码的,也可以从request.files [file]对象的filename属性中获取。 但是,建议使用secure_filename()函数获取它的安全版本。

可以在Flask对象的配置设置中定义默认上传文件夹的路径和上传文件的最大大小。

变量 说明
app.config[‘UPLOAD_FOLDER’] 定义上传文件夹的路径
app.config[‘MAX_CONTENT_PATH’] 指定要上传的文件的最大大小 - 以字节为单位

以下代码具有URL: /upload 规则,该规则显示templates文件夹中的upload.html文件,以及调用uploader()函数处理上传过程的URL => /upload-file规则。

upload.html有一个文件选择器按钮和一个提交按钮。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Flask示例</title>
</head>
<body>

<form action = "http://localhost:5000/upload" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit" value="提交"/>
</form>

</body>
</html>

选择文件后点击提交。 表单的post方法调用URL=> /upload_file。 底层函数uploader()执行保存文件操作。

以下是Flask应用程序的Python代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
app = Flask(__name__)

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
print(request.files)
f.save(secure_filename(f.filename))
return 'file uploaded successfully'
else:
return render_template('upload.html')


if __name__ == '__main__':
app.run(debug = True)

nginx简单域名配置

发表于 2019-02-13 | 分类于 nginx , 服务器
字数统计: 216 字 | 阅读时长 ≈ 1 分钟

安装好nginx后,使用

1
vim /etc/nginx/nginx.conf

修改配置文件。

在http{···}内增加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  server {
listen 80;
server_name baidu.com test.baidu.com;

rewrite ^/$ /index permanent;
location /{
index form;
proxy_pass http://127.0.0.1:19192;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_read_timeout 300s;
}
location /static {
root /home/agent/agent/work/html;
}
}

这里的listen表示对外的端口,监听的是80端口,server_name是配置的域名,可以配置一级二级三级域名,其中,二三级域名需要到云平台去配置后再在这里配置才可以。

rewrite里的index是表示直接访问配置的域名的时候,后缀加入,例如这里配置为index,则访问baidu.com,会直接跳转到baidu.com/index,如果配置为form,会直接跳转为baidu.com/form。

nginx检测

使用

1
nginx -t

检测nginx配置是否有错。

部署

使用

1
service nginx reload

比restart平滑。

flask:session会话

发表于 2019-02-13 | 分类于 flask
字数统计: 830 字 | 阅读时长 ≈ 4 分钟

与Cookie不同,会话数据存储在服务器上。 会话是客户端登录到服务器并注销的时间间隔。

需要在此会话中进行的数据存储在服务器上的临时目录中。与每个客户端的会话分配一个会话ID。 会话数据存储在cookie顶部,服务器以加密方式签名。 对于这种加密,Flask应用程序需要一个定义SECRET_KEY。

会话对象也是一个包含会话变量和关联值的键值对的字典对象。例如,要设置’username’会话变量,请使用语句

1
session['username']='admin'

要删除会话变量,请使用pop()方法。

1
session.pop('username', None)

以下代码是Flask中会话如何工作的简单演示。 URL => ‘/‘ 提示用户登录,因为会话变量username没有设置。

1
2
3
4
5
6
7
8
@app.route('/')
def index():
if 'username' in session:
username = session['username']
return 'Logged in as ' + username + '<br>' + \
"<b><a href = '/logout'>click here to log out</a></b>"
return "You are not logged in <br><a href = '/login'></b>" + \
"click here to log in</b></a>"

当用户浏览到URL=>’/login’时,login()函数显示视图,因为它是通过GET方法调用的,所以打开一个登录表单。

表单填写后重新提交到URL=> /login,现在会话变量被设置。 应用程序被重定向到URL=> /。 这时找到会话变量:username。

1
2
3
4
5
6
7
8
9
10
11
@app.route('/login', methods = ['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form action = "" method = "post">
<p><input type = text name = "username"/></p>
<p<<input type = submit value = Login/></p>
</form>
'''

该应用程序还包含一个logout()视图函数,它删除’username’会话变量的值。 再次 URL 跳转到 ‘/‘ 显示开始页面。

1
2
3
4
5
@app.route('/logout')
def logout():
# remove the username from the session if it is there
session.pop('username', None)
return redirect(url_for('index'))

运行应用程序并访问主页(确保设置应用程序的secret_key)。

1
2
3
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.secret_key = 'any random string’

完整代码如下所示

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
from flask import Flask
from flask import render_template
from flask import request
from flask import make_response
from flask import Flask, session, redirect, url_for, escape, request



app = Flask(__name__)
app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'

@app.route('/')
def index():
if 'username' in session:
username = session['username']
return '登录用户名是:' + username + '<br>' + \
"<b><a href = '/logout'>点击这里注销</a></b>"


return "您暂未登录, <br><a href = '/login'></b>" + \
"点击这里登录</b></a>"



@app.route('/login', methods = ['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))

return '''
<form action = "" method = "post">
<p><input type ="text" name ="username"/></p>
<p><input type ="submit" value ="登录"/></p>
</form>
'''

@app.route('/logout')
def logout():
# remove the username from the session if it is there
session.pop('username', None)
return redirect(url_for('index'))


if __name__ == '__main__':
app.run(debug = True)

nginx配置vim高亮

发表于 2019-02-13 | 分类于 nginx , 服务器
字数统计: 105 字 | 阅读时长 ≈ 1 分钟

下载vim语法高亮配置文件到/usr/share/vim/vim74/syntax/

1
wget http://www.vim.org/scripts/download_script.php?src_id=19394 -O nginx.vim

或者在别的文件夹下载好后,移到syntax文件夹:

1
mv nginx.vim /usr/share/vim/vim74/syntax/

修改配置文件/usr/share/vim/vim74/filetype.vim

在最后增加:

1
au BufRead,BufNewFile /etc/nginx/*,/usr/local/nginx/conf/* if &ft == '' | setfiletype nginx | endif

之后使用vim /etc/nginx/nginx.conf,就有高亮表示。

SQLAlchemy:更新数据

发表于 2019-02-13 | 分类于 python , SQLAlchemy
字数统计: 86 字 | 阅读时长 ≈ 1 分钟

更新记录

更新单条记录

1
2
3
4
5
query = session.query(User) 
user = query.get('lujianxing11')
print user.accout
user.accout='987'
session.flush()

更新多条记录

1
2
3
4
query = session.query(User)
query.filter(User.user_name=='lujianxing2').update({User.age: '15'})
query.filter(User.user_name=='lujianxing2').update({'age': '16'})
query.filter(User.pwd=='aaa').update({'age': '17'})

flask:url构建

发表于 2019-02-13 | 分类于 flask
字数统计: 314 字 | 阅读时长 ≈ 1 分钟

url_for()函数对于动态构建特定函数的URL非常有用。 该函数接受函数的名称作为第一个参数,并接受一个或多个关键字参数,每个参数对应于URL的变量部分。以下脚本演示了使用url_for()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, redirect, url_for
app = Flask(__name__)

@app.route('/admin')
def hello_admin():
return 'Hello Admin'

@app.route('/guest/<guest>')
def hello_guest(guest):
return 'Hello %s as Guest' % guest

@app.route('/user/<name>')
def user(name):
if name =='admin':
return redirect(url_for('hello_admin'))
else:
return redirect(url_for('hello_guest',guest = name))

if __name__ == '__main__':
app.run(debug = True)

Python上面的脚本有一个函数用户(名称),它接受来自URL的参数值。User()函数检查收到的参数是否与’admin’匹配。 如果匹配,则使用url_for()将应用程序重定向到hello_admin()函数,否则将该接收的参数作为guest参数传递给hello_guest()函数。保存上面的代码到一个文件:hello.py,并从Python shell运行。打开浏览器并输入URL - http://localhost:5000/user/admin浏览器中的应用程序响应输出结果是

1
Hello Admin

Shell在浏览器中输入以下URL - http://localhost:5000/user/mvl应用程序响应结果现在变为

1
Hello mvl as Guest

SQLAlchemy:Query

发表于 2019-02-13 | 分类于 python , SQLAlchemy
字数统计: 1.7k 字 | 阅读时长 ≈ 8 分钟

Query

Session的query函数会返回一个Query对象。query函数可以接受多种参数类型。可以是类,或者是类的instrumented descriptor。下面的这个例子取出了所有的User记录。

1
2
3
4
5
6
7

>>> for instance in session.query(User).order_by(User.id):
... print(instance.name, instance.fullname)
ed Ed Jones
wendy Wendy Williams
mary Mary Contrary
fred Fred Flinstone

阅读全文 »

SQLAlchemy:创建连接和表

发表于 2019-02-13 | 分类于 python , SQLAlchemy
字数统计: 2.1k 字 | 阅读时长 ≈ 8 分钟

连接

1
engine = create_engine('mysql+mysqlconnector://root:123456@localhost:3306/test',echo=True)

orm实体

当我们使用ORM的时候,其配置过程主要分为两个部分:一是描述我们要处理的数据库表的信息,二是将我们的Python类映射到这些表上。这两个过程在SQLAlchemy中是一起完成的,我们将这个过程称之为Declarative。

使用Declarative参与ORM映射的类需要被定义成为一个指定基类的子类,这个基类应当含有ORM映射中相关的类和表的信息。这样的基类我们称之为declarative base class。在我们的应用中,我们一般只需要一个这样的基类。这个基类我们可以通过declarative_base来创建

1
2
3
>>> from sqlalchemy.ext.declarative import declarative_base

>>> Base = declarative_base()

现在我们已经有了一个基类,我们可以基于这个基类来创建我们的自定义类了。我们以建立一个用户类为例子。从Base派生一个名为User的类,在这个类里面我们可以定义将要映射到数据库的表上的属性(主要是表的名字,列的类型和名称等):

1
2
3
4
5
6
7
8
9
10
11
12
>>> from sqlalchemy import Column, Integer, String
>>> class User(Base):
... __tablename__ = 'users'
...
... id = Column(Integer, primary_key=True)
... name = Column(String)
... fullname = Column(String)
... password = Column(String)
...
... def __repr__(self):
... return "<User(name='%s', fullname='%s', password='%s')>" % (
... self.name, self.fullname, self.password)

通过Declarative生成的类至少应该包含一个名为tablename的属性来给出目标表的名称,以及至少一个Column来给出表的主键(Primary Key)。SQLAlchemy不会对于类名和表名之间的关联做任何假设,也不会自动涉及数据类型以及约束的转换。一般的你可以自己创建一个模板来建立这些自动转换,这样可以减少你的很多重复劳动。

当我们的类声明完成后,Declarative将会将所有的Column成员替换成为特殊的Python访问器(accessors),我们称之为descriptors。这个过程我们称为instrumentation,经过instrumentation的映射类可以让我们能够读写数据库的表和列。

注意除了这些涉及ORM的映射意外,这些mapping类的其他部分仍然是不变的。

建立表

我们通过Declarative系统构建好我们的User类之后,与之同时的关于表的信息也已经创建好了,我们称之为table metadata。描述这些信息的类为Table。我们可以通过table这个类变量来查看表信息

1
2
3
4
5
6
>>> User.__table__ 
Table('users', MetaData(bind=None),
Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
Column('name', String(), table=<users>),
Column('fullname', String(), table=<users>),
Column('password', String(), table=<users>), schema=None)

其中,常用字段类型如下:

1
2
3
4
5
6
db.Integer 整型
db.String (size) 字符串,size 为最大长度,比如db.String(20)
db.Text 长文本
db.DateTime 时间日期,Pythondatetime对象
db.Float 浮点数
db.Boolean 布尔值

当我们完成类声明时,Declarative用一个Python的metaclass来为这个类进行了加工。在这个阶段,它依据我们给出的设置创建了Table对象,然后构造一个Mapper对象来与之关联。这些幕后的对象我们大多都不需要直接与之打交道。

Table对象是一个更大家庭—-我们称之为MetaData—-的一部分。当我们使用Declarative时,这个对象也可以在Declarative base class的.metadata属性中看到。

MetaData是我们与数据库打交道的一个接口。对于我们的SQLite数据库而言,此时还没有一个名为users的表的存在,我们需要使用MetaData来发出CREATE TABLE的命令。下面我们使用MetaData.create_all()指令,将我们上面得到的Engine作为参数传入。如果你上面设置了echo为True的话,应该可以看到这一过程中的SQL指令。首先检查了users表的存在性,如果不存在的话会执行表的创建工作。

1
2
3
4
5
6
7
8
9
10
11
12
>>> Base.metadata.create_all(engine)
SELECT ...
PRAGMA table_info("users")
()
CREATE TABLE users (
id INTEGER NOT NULL, name VARCHAR,
fullname VARCHAR,
password VARCHAR,
PRIMARY KEY (id)
)
()
COMMIT

建立session

Session是一个非常重要的概念,类似于iOS中的NSManagedContext的概念,我也在尝试进一步去理解它。

我们现在可以和数据库对话了。ORM对数据库的入口即是Session,当我们构建应用时,和create_engine的同一级别下,我们定义一个Session类来作为生成新的Session的Factory类

1
2
>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=engine)

当你试图在定义Engine之前定义Sesssion的话,这里的bind可以不设置

1
>>> Session = sessionmaker()

后续你定义好Engine后可以通过configure()来将其连接到Session

1
>>> Session.configure(bind=engine)  # once engine is available

这个我们自定义的工厂类就可以拿来我们构造新的Session了。

1
session = Session()

上面的Session已经和我们的SQLite的数据库的Engine关联起来了,但是我们可以发现它还没有打开任何到数据库的连接(connection)。当一个Session被首次使用时,它会从Engine所维护的连接池中取出一个连接来操作数据库。这个连接在我们应用有所更改或者关闭Session时会被释放。

更新数据

为了将User对象存入数据库,我们调用Sesson的add()函数

1
2
>>> ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
>>> session.add(ed_user)

当这个操作完成之后,我们成这个User实例的状态为pending。目前实际上还没有执行SQL操作,也就是说数据库中还没有产生和这个User实例对应的行。Session将会在需要的时候执行相应的SQL命令,这个过程我们称之为flush。如果我们试图查询Ed Jones,所有处于pending状态的信息将会首先被flush,然后负责进行查询的SQL语言在此之后立即被执行。

例如,我们创建一个查询来获取刚刚我们创建的用户(涉及查询的部分我们后续会详细介绍)。这个查询会返回一个和我们之前添加的用户相同的用户实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> our_user = session.query(User).filter_by(name='ed').first() BEGIN (implicit)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('ed', 'Ed Jones', 'edspassword')
SELECT users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.password AS users_password
FROM users
WHERE users.name = ?
LIMIT ? OFFSET ?
('ed', 1, 0)
>>> our_user
<User(name='ed', fullname='Ed Jones', password='edspassword')>

事实上这里的Session判断出来了需要返回的行和已经存在内存中的一个映射实例应当是同一个,所以我们会得到一个和之前完全相同的实例

1
2
>>> ed_user is our_user
True

这里ORM所表现的理念,我们称之为identity map。这个设计理念保证了在一个Session对于一个制定行的操作,作用于同一个内存实例上。当一个拥有特定主键的对象出现在Session中时,所有的查询操作对这个主键都会返回一个相同的Python对象。并且,如果你试图引入重复了主键的新的对象时,系统会产生一个错误来阻止你的操作。

我们可以通过add_all()来一次加入多个对象

1
2
3
4
>>> session.add_all([
... User(name='wendy', fullname='Wendy Williams', password='foobar'),
... User(name='mary', fullname='Mary Contrary', password='xxg527'),
... User(name='fred', fullname='Fred Flinstone', password='blah')])

并且,如果我们希望改变Ed的密码,可以直接修改之:

1
>>> ed_user.password = 'f8s7ccs'

这个修改会被Session记录下来

1
2
>>> session.dirty
IdentitySet([<User(name='ed', fullname='Ed Jones', password='f8s7ccs')>])

当然,上面的插入操作也被记录了

1
2
3
4
>>> session.new 
IdentitySet([<User(name='wendy', fullname='Wendy Williams', password='foobar')>,
<User(name='mary', fullname='Mary Contrary', password='xxg527')>,
<User(name='fred', fullname='Fred Flinstone', password='blah')>])

我们可以使用commit()命令来将这些更改flush到数据库中。

1
>>> session.commit()

flask:发送邮件

发表于 2019-02-13 | 分类于 flask
字数统计: 735 字 | 阅读时长 ≈ 3 分钟

基于Web的应用程序通常需要具有向用户/客户端发送邮件的功能。 Flask-Mail扩展使得用任何电子邮件服务器设置一个简单接口变得非常简单.

起初,Flask-Mail扩展可使用pip工具来安装,如下所示

1
pip install Flask-Mail

然后需要通过设置以下应用程序参数的值来配置Flask-Mail。

编号 参数 描述
1 MAIL_SERVER 邮件服务器的名称/IP地址
2 MAIL_PORT 所用服务器的端口号
3 MAIL_USE_TLS 启用/禁用传输安全层加密
4 MAIL_USE_SSL 启用/禁用安全套接字层加密
5 MAIL_DEBUG 调试支持,默认是Flask应用程序的调试状态
6 MAIL_USERNAME 发件人的用户名
7 MAIL_PASSWORD 发件人的密码
8 MAIL_DEFAULT_SENDER 设置默认发件人
9 MAIL_MAX_EMAILS 设置要发送的最大邮件
10 MAIL_SUPPRESS_SEND 如果app.testing设置为true,则发送被抑制
11 MAIL_ASCII_ATTACHMENTS 如果设置为true,则将附加的文件名转换为ASCII

flask-mail模块包含以下重要类的定义。

Mail类

它管理电子邮件消息的要求。 类构造函数采用以下形式

编号 方法 描述
1 send() 发送Message类对象的内容
2 connect() 与邮件主机打开连接
3 send_message() 发送消息对象

Message类

它封装了一封电子邮件,Message类的构造函数有几个参数

1
2
flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, 
reply-to, date, charset, extra_headers, mail_options, rcpt_options)

Message类方法

  • attach() - 向消息添加附件。 该方法采用以下参数
  • filename - 要附加的文件的名称
  • content_type - 文件的MIME类型
  • data - 原始文件数据
  • disposition - 内容处置,如果有的话。

add_recipient() - 向消息添加另一个收件人

在以下示例中,Google的Gmail服务的SMTP服务器用作Flask-Mail配置的MAIL_SERVER。

第1步

在代码中从flask-mail模块导入Mail和Message类。

1
from flask_mail import Mail, Message

第2步

然后根据以下设置配置Flask-Mail。

1
2
3
4
5
6
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True

第3步

创建一个Mail类的实例。

1
mail = Mail(app)

第4步

在由URL规则映射的Python函数(‘/‘)中设置Message对象。

1
2
3
4
5
6
@app.route("/")
def index():
msg = Message('Hello', sender = 'yourId@gmail.com', recipients = ['id1@gmail.com'])
msg.body = "This is the email body"
mail.send(msg)
return "Sent"

第5步

整个代码如下。 在Python Shell中运行以下脚本并访问URL: http://localhost:5000/。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask
from flask_mail import Mail, Message

app =Flask(__name__)
mail=Mail(app)

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)

@app.route("/")
def index():
msg = Message('Hello', sender = 'yourId@gmail.com', recipients = ['id1@gmail.com'])
msg.body = "Hello Flask message sent from Flask-Mail"
mail.send(msg)
return "Sent"

if __name__ == '__main__':
app.run(debug = True)

12…21
snjl

snjl

越过山丘,才发现无人等候。

203 日志
44 分类
107 标签
RSS
GitHub E-Mail Weibo
© 2019 snjl
总访问量次 | 总访客人 |
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.4