Python-Flask框架

2018-10-16  本文已影响0人  云中的Jason

(本文后期会重新整理,敬请期待)

URL和视图

安装Homebrew

在终端输入以下代码,安装Homebrew:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Python安装

mac环境下默认安装了python 2.7,安装3.6需要用以下代码:

brew install python3

Python虚拟环境安装

  1. 因为python的框架版本更新迭代速度太快,有时需要在一台电脑上存在一个框架的多个版本,这时就需要虚拟环境。通过以下代码安装:
pip3 install virtualenv
  1. 虚拟环境管理工具virtualenvwrapper可以很便捷的新建、删除、切换虚拟环境。virturalenvwrapper可以通过一下代码安装:
pip3 install virtualenvwrapper
  1. 在使用virturalenvwrapper之前,需要对 virtualenvwrapper 进行配置。它需要指定一个环境变量,叫做 WORKON_HOME,并且需要运行一下它的初始化工具 virtualenvwrapper.sh,这个脚本默认安装在 /usr/local/bin/ 目录下。WORKON_HOME 就是它将要用来存放各种虚拟环境目录的目录,这里我们可以设置为 ~/.Python/Envs。通过以下方式将配置代码加入.bash_profile中
修改方式
vim .bash_profile
open -e .bash_profile
配置代码
export WORKON_HOME=$HOME/.Python/Envs
export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3
source /usr/local/bin/virtualenvwrapper.sh 
  1. virtualenvwrapper常用指令:
mkvirtualenv env1 //创建虚拟环境
workon //列出虚拟环境
workon Flask_env //使用虚拟环境env1
deactivate //退出虚拟环境
rmvirtualenv env1 //删除虚拟环境env1

flask 安装

进入创建的虚拟环境,在虚拟环境下安装flask,安装指令如下:

pip3 install flask

第一个flask程序

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello world!'
if __name__ == '__main__'
    app.run()

debug 模式

  1. 在app.run()中传入一个关键字参数debug,app.run(debug=Ture),就设置当前项目为debug模式。
  2. debug模式的两大功能:

使用配置文件

  1. 新建一个'config.py'文件
  2. 在主app文件中导入这个文件,并且配置到app中,示例代码如下
import config
app.config.from_object(config)
  1. 还有许多的其他参数,都是放在这个配置文件中,比如‘SECRET_KEY‘和’SQLALCHEMY‘。

URL 传参

  1. 参数的作用:可以在相同的URL中指定不同的参数,来加载不同的数据。
  2. 在flask中使用参数:
@app.route('/article/<id>')
def article(id):
    return u'你请求的参数是:%s' % id
* 参数需要放在两个尖括号中
* 视图函数中需要放和url中的参数同名的参数

URL 反转

  1. 什么叫反转URL:从视图函数到URL的转换叫做反转URL
href="{{ url_for('index') }}"
  1. 反转URL的用处

页面跳转和重定向

  1. 用处:在用户访问一些需要登录的界面时,如果用户没有登录,那么可以让它重定向到登录页面
  2. 代码实现:
from flask import Flask,redirect,url_for
redirect(url_for('login'))

Jinjia2模版

Flask渲染Jinjia2模版和传参

  1. 如何渲染模版
    • 模版放在‘templates’文件夹下
    • 从‘flask’中导入‘render_template’函数
    • 从视图函数中,使用‘render_template’函数,渲染模版。注意,只需要填写模版的名字,不需要填写‘templates’这个文件路径
  2. 模版传参:
    • 如果只有一个或少量参数,直接在‘render_template’函数中添加关键字参数就可以了。
    • 如果有多个参数,那么可以先把所有的参数放到字典中,然后在‘render_template’中,使用**将字典转换成关键参数传递进去,这样的代码更方便管理和使用。
  3. 在模版中,使用一个变量的语法是{{ params }}
  4. 访问模版中的属性或是字典,可以通过{{ params.property }}的形式,或者使用{{ params['property'] }}

if判断语句

  1. 语法
{% if xxx %}
{% eles %}
{% endif %}
  1. if的使用和python相差无几

for循环遍历

  1. 字典的遍历语法和python一样,可以使用‘items()’、‘keys()’、‘values()’、‘iteritems()’、‘iterkeys()’、‘itervalues()’
{% for k,v in user.items() %}
    <p>{{ k }}:{{ v }}</p>
{% endfor %}
  1. 列表的遍历与python一样
{% for website in websites %}
    <p>{{ website }}</p>
{% endfor %}

过滤器

  1. 介绍和语法
{{ params|default('xxx') }}
  1. default过滤器:如果当前变量不存在,这时候可以指定默认值
  2. length过滤器:求列表、字符串、字典和元祖的长度
{{ params|length }}

继承和block

  1. 继承的作用和语法
{% extends 'base.html' %}
  1. block实现:
<!--接口-->
{% block main %}{% endblock%}
{% block main %}
    <h1>这是登录页面</h1>
{% endblock %}

URL链接和加载静态文件

  1. 使用‘url_for(视图函数名称)’可以反转成url
  2. 加载静态文件:
<link href="{{ url_for('static',filename='css/static.css') }}" rel="stylesheet" type="text/css" />
<script src="{{ url_for('static',filename='js/static.js') }}"></script>

SQLAlchemy数据库

Mac下数据库的安装

  1. MySql下载链接
  2. Mac上安装Mysql后,在系统偏好设置里启动MySql服务
  3. 配置环境变量:
进入vim
vim ~/.bash_profile
添加mysql路径
PATH=$PATH:/usr/local/mysql/bin
按esc,输入‘:wq’保存退出
激活配置文件
source ~/.bash_profile
  1. 数据库相关指令:
mysql -u username -p
show databases

mysqlclient安装

  1. 进入虚拟环境,安装mysql-connector-c
brew install mysql-connector-c
  1. 修改mysql_config文件的配置,位于/usr/local/bin/mysql_config
原代码:
libs="-L$pkglibdir"
libs="$libs -l "

更改后代码:
libs="-L$pkglibdir"
libs="$libs -lmysqlclient -lssl -lcrypto"
  1. 安装mysqlclient:
pip3 install mysqlclient

Flask-SQLAlchemy的介绍与安装

  1. ORM:Object Relationship Mapping(模型关系映射)
  2. flask-sqlalchemy是一套ORM框架
  3. ORM的好处:可以让我们操作数据库和操作对象一样,非常方便。因为一个表就抽象成一个类,一条数据就抽象成该类的一个对象。
  4. 安装‘Flask-sqlalchemy’:
pip install flask-sqlalchemy

Flask-SQLAlchemy的使用

  1. 初始化和设置数据库配置信息:
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
  1. 设置配置信息,在config.py文件中添加以下配置信息:
* dialect+driver://username:password@host:port/database *
DIALECT = 'mysql'
DRIVER = 'mysqldb'
USERNAME = 'root'
PASSWORD = 'Gao123456'
HOST = 'localhost'
PORT = '3306'
DATABASE = 'db_demo1'
SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USERNAME,PASSWORD,HOST,PORT,DATABASE)
SQLALCHEMY_TRACK_MODIFICATIONS = False
  1. 在主app文件中添加配置文件(config.py)
import config

app.config.from_object(config)
目录需要包含一个叫做 __init__.py 的文件
from config.config

app.config.from_object(config.config_demo1)
  1. 测试
db.creat_all()
如果没有报错,说明配置没有问题,如果有错误,可以根据错误进行修改

SQLAlchemy模型与表映射

  1. 模型需要继承自‘db.Model’,然后需要映射到表中的属性,必须写成‘db.Column’的数据类型。
  2. 数据类型:
  1. 其他参数:
class Article(db.Model):
    __tablename__ = 'article'#指定表名
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    content = db.Column(db.Text,nullable=False)

SQLAlchemy数据增删改查

  1. 增加
# 增加
article1 = Article(title='aaa',content='bbb')
db.session.add(article1)
# 事务
db.session.commit()
  1. 查找
# 查询
article1 = Article.query.filter(Article.title == 'aaa').first()
print('title:%s' % article1.title)
print('comment:%s' % article1.content)
  1. 修改
# 修改
# 1.先把需要修改的数据查找出来
article1 = Article.query.filter(Article.title == 'aaa').first()
# 2.将查找到的数据所要修改的地方进行修改
article1.title = 'new title'
# 3.做事务提交
db.session.commit()
  1. 删除
# 删除
# 1.把需要删除的数据查找出来
article1 = Article.query.filter(Article.title == 'aaa').first()
# 2.删除数据
db.session.delete(article1)
# 3.做事务提交
db.session.commit()

Flask_SQLAlchemy外键及其关系

  1. 外键:
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(100),nullable=False)

class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    content = db.Column(db.Text,nullable=False)
    author_id = db.Column(db.Integer,db.ForeignKey('user.id'))
    author = db.relationship('User',backref=db.backref('articles'))
  1. author = db.relationship('User',backref=db.backref('articles'))解释:
  1. 多对多关系
class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    tags = db.relationship('Tag',secondary='article_tag',backref=db.backref('articles'))

class Tag(db.Model):
    __tablename__ = 'tag'
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    name = db.Column(db.String(100),nullable=False)

article_tag = db.Table('article_tag',
    db.Column('article_id',db.Integer,db.ForeignKey('article.id'),primary_key=True),
    db.Column('tag_id',db.Integer,db.ForeignKey('tag.id'),primary_key=True)
)
tags = db.relationship('Tag',secondary='article_tag',backref=db.backref('articles'))
article1 = Article(title='iPhone')
article2 = Article(title='iPad')   
tag1 = Tag(name='Easy')
tag2 = Tag(name='Good')
article1.tags.append(tag1)
article1.tags.append(tag2)
article2.tags.append(tag1)
article2.tags.append(tag2)
db.session.add(article1)
db.session.add(article2)
db.session.add(tag1)
db.session.add(tag2)
db.session.commit()
article1 = Article.query.filter(Article.title =='iPhone').first()
tags = article1.tags
for tag in tags:
    print (tag.name)

Flask_script的介绍与安装

  1. Flask-script:其作用是可以通过命令行的形式来操作FLask。例如通过命令跑一个开发版本的服务器,设置数据库,定时任务等。
  2. 安装:进入到虚拟环境中,使用一下命令安装:
pip install flask-script
  1. 如何直接在主‘manager.py’中写命令,那么在终端只需要python manager.py command_name就可以了。
  2. 如果把一些命令集中在一个文件中,那么在终端就需要输入一个父命令,比如python manager.py db init
  3. 例子:
from flask_script import Manager
from flask_script_demo import app
from db_script import DBmanager

manager = Manager(app)

@manager.command
def runserver():
    print('The server is running!')

manager.add_command('db',DBmanager)

if __name__ == '__main__':
    manager.run()
  1. 有子命令的例子:
from flask_script import Manager

DBmanager = Manager()

@DBmanager.command
def init():
    print('数据库初始化完成')

@DBmanager.command
def migrate():
    print('数据库迁移成功')

分开‘models’以及解决循环引用:

  1. 分开models的目的:为了让代码更加方便的管理
  2. 如何解决循环引用:把‘db’放在一个单独的文件中,切断循环引用的线条就可以了
# models_sep.py
from flask import Flask
from models import Article
from exts import db

# models.py
from exts import db
class Article(db.Model):
    pass

# exts.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

db.init_app(app)

Flask-Migrate的介绍与安装

  1. 介绍:因为采用db.create_all在后期修改字段的时候,不会自动的映射到数据库中,必须删除表,然后重新运行db.create_all才会重新映射,这样不符合我们的需求。因此flask—migrade就是为了解决这个问题,它可以在每次修改模型后,将修改的内容映射到数据库中
  2. 安装:进入虚拟环境使用一下命令安装:
pip install flask-migrate
  1. 使用‘flask-migrate’必须借助‘flask-script’,这个包的‘MigrateCommand’中包含的所有与数据库相关的命令
  2. ‘flask-migrate’相关的命令:
  1. 注意点:需要映射到数据库的模型,都要导入到manager.py中,如果没有导入,就不会映射到数据库中
  2. manager.py相关代码:
from flask_script import Manager
from migrate_demo import app
from flask_migrate import Migrate,MigrateCommand
from exts import db
from models import Article

# 模型 -> 迁移文件 -> 表
# init
# migrate
# upgrate

manager = Manager(app)

# 1. 要使用Flask-migrate,必须要绑定app和db
migrate = Migrate(app,db)
# 2. 把MigrateCommand命令添加到manager中
manager.add_command('db',MigrateCommand)

if __name__ == '__main__':
    manager.run()

session和cookie操作

cookie的相关内容:

  1. cookie出现的原因:在网站中,http请求是无状态的。这就是说即使第一次和服务器连接并且登录成功后,第二次请求服务器依然不能知道当前请求的是哪个用户。cookie的出现就是为了解决这一问题,第一次登录后,服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地。当用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪一个了
  2. 如果服务器返回了cookie给浏览器,那么浏览器再次请求相同的服务器的时候,就会自动的吧cookie发送给服务器,这个过程用户不需要处理
  3. cookie是保存在浏览器中的,相对的是浏览器

session的相关内容:

  1. session介绍:session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但是服务器发展至今,一些session信息还是绰绰有余的
  2. 使用session的好处:

Flask中的session工作机制

  1. flask中session机制是:把敏感数据经过加密后放入session中,然后再把session存放到cookie中。下次请求的时候,再从浏览器发送过来的cookie中
    读取session,然后从session中读取敏感数据并进行解密,最终获取到用户数据
  2. flask的这种session机制,可以节省服务器的开销,因为把所有的信息都存储到了客户端(浏览器)
  3. 安全是相对的,把session放到cookie中,经过加密也是比较安全的

Flask中操作session

  1. 使用session需要从flask中导入session,以后所有和session相关的操作都是通过这个变量来的
  2. 使用session需要设置‘SECRET_KEY’用来加密,并且这个‘SECRET_KEY’如果在每次服务器启动后都变化的话,那么之前的session就不能再通过当前这个‘SECRET_KEY’进行解密了
  3. 操作session的时候和操作字典相同
  1. 设置session的过期时间

装饰器

  1. 装饰器实际上就是一个函数,有两个特别之处
  1. 装饰器的使用是通过@符号,放在函数的上面
  2. 装饰器中定义的函数,要使用args,*kwargs两个参数组合
  3. 需要使用functools.wraps在装饰器中的函数上把传进来的函数进行一个处理,这样就不会丢失其原来name等属性
from functools import wraps
def my_log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('hello world!')
        func(*args, **kwargs)
    return wrapper

@my_log
def run():
    print('run')

@my_log
def add(a, b):
    c = a + b
    print('c = %s' % c)

run()
add(1, 3)
print(run.__name__)

知识点补充

get请求和post请求

  1. get请求
  1. post请求

get和post请求获取参数

  1. get请求是通过flask.request.args来获取的
  2. post请求是通过flask.request.form来获取的
  3. post请求在模版中要注意:
  1. 示例代码
<form action="{{ url_for('login') }}" method="POST">
    <table>
        <tbody>
            <tr>
                <td>用户名:</td>
                <td><input type="text" placeholder="请输入用户名" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="text" placeholder="请输入密码" name="password"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="登录"></td>
            </tr>
        </tbody>
    </table>
</form>

保存全局变量的g属性(g:global)

  1. g对象是专门用来保存用户的数据的
  2. g对象在一次请求中,代码所有的地方都是可以使用的

钩子函数(hook)

  1. before_request:
@app.before_request
def my_before_request():
   if session.get('username'):
       g.username = session.get('username')
  1. context_processor:
@app.context_processor
def my_context_processor():
    return {'username':'Jason'}

实战演练

项目结构搭建

导航条构建

父模版抽离

{% extends 'base.html' %}
{% block title %}首页{% endblock %}
{% block main %}这是首页{% endblock %}

登录页面完成和注册页面完成

pass

用户模型创建

  1. 创建模型User
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    telephone = db.Column(db.String(11), nullable=False)
    username = db.Column(db.String(50), nullable=False)
    password = db.Column(db.String(100), nullable=False)
  1. 进入虚拟环境,利用flask-script创建数据库表
python manage.py db init
python manage.py db migrate
python manage.py db upgrade

注册功能完成

登录功能完成

待完善

登录和注销状态切换

利用钩子函数context_processor

发布问答界面完成

登录限制

在未登录状态下,访问发布问答页面时,要登录

from functools import wraps
from flask import session, redirect
# 登录限制的装饰器
def login_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get('user_id'):
            return func(*args, **kwargs)
        else:
            return redirect('login')
    return wrapper

# 发布问答
@app.route('/question/')
@login_required
def question():
    if request.method == 'GET':
        return render_template('question.html')
    else:
        pass

发布问答功能完成

# 发布问答
@app.route('/question/', methods=['GET', 'POST'])
@login_required
def question():
    if request.method == 'GET':
        return render_template('question.html')
    else:
        title = request.form.get('title')
        content = request.form.get('content')
        question = Question(title=title, content=content)
        user_id = session.get('user_id')
        user = User.query.filter(User.id == user_id).first()
        question.author = user
        db.session.add(question)
        db.session.commit()
        return redirect(url_for('index'))

密码保护

from exts import db
# 导入转换密码需要的库
from werkzeug.security import generate_password_hash, check_password_hash


# 用户模型
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    telephone = db.Column(db.String(11), nullable=False)
    username = db.Column(db.String(50), nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)


# 定义函数,需要用属性时,可以用函数代替
    @property
    def password(self):
        return self.password_hash


# 转换密码为hash存入数据库
    @password.setter
    def password(self, row_password):
        self.password_hash = generate_password_hash(row_password)


# 检查密码
    def check_password(self, row_password):
        return check_password_hash(self.password_hash, row_password)


# 登录
@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        telephone = request.form.get('telephone')
        password = request.form.get('password')
        user = User.query.filter(User.telephone == telephone).first()
        if user:
            if user.check_password(password):
                session['user_id'] = user.id
                session.permanent = True
                return redirect(url_for('index'))
            else:
                return u'密码错误!'
        else:
            return u'用户不存在,请注册后登录!'


# 注册
@app.route('/regist/', methods=['GET', 'POST'])
def regist():
    if request.method == 'GET':
        return render_template('regist.html')
    else:
        telephone = request.form.get('telephone')
        username = request.form.get('username')
        password_1 = request.form.get('password_1')
        password_2 = request.form.get('password_2')
        # 手机号码验证,如果被注册,就不能再注册了
        user = User.query.filter(User.telephone == telephone).first()
        if user:
            return u'改手机号已被注册,请更换手机号码!'
        else:
            # password_1和password_2要一样才可以
            if password_1 != password_2:
                return u'两次密码不一样,请核对后再填写!'
            else:
                user = User(telephone=telephone, username=username, password=password_1)
                db.session.add(user)
                db.session.commit()
                # 如果注册成功,就让页面跳转到登录界面
                return redirect(url_for('login'))

定时任务Celery

  1. 安装celery
pip install celery
  1. 通过Homebrew安装消息代理Redis
brew install redis
  1. 通过指令redis-server启动Redis(关闭redis:redis-cli shutdown
  2. 通过终端进入celery文件所在目录,执行以下命令开启工作池
celery -A celery_task worker --loglevel=info

celery_task代码如下所示

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from celery import Celery
from celery import platforms
from crawler import getdata
import datetime
import time


# 用于开启root也可以启动celery服务,默认是不允许root启动celery的
platforms.C_FORCE_ROOT = True
# 创建一个celery实例,传递进去的第一个参数必须是本文件的文件名celery,指定broker为本机redis6380服务
celery = Celery('celery_task', broker='redis://localhost:6379/0')


@celery.task
def task(h=1, m=0):
    while True:
        while True:
            now = datetime.datetime.now()
            if now.hour == h and now.minute == m:
                break
            time.sleep(60)
        getdata()
        print('执行完毕!')

上一篇下一篇

猜你喜欢

热点阅读