Flask Tornado Django 对比

安装

虚拟环境

  • python3.7 -m venv venv_name 会在目录中产生一个venv_name的文件夹
  • source venv_name/bin/activate - 激活
  • deactivate - 退出
  • pip3 freeze命令查看虚拟环境中安装了哪些包

pip3批量安装

  • 创建txt文件,在txt文件中写入要批量安装的文件
  • pipe install -r requirement.txt

Django

  • pip3 install django==2.1.7

Flask

  • pip3 install flask

Tornado

  • pip3 install tornado==4.5

启动

Django

  • django-admin startproject 项目名
  • python3 manage.py startapp 应用名
  • 修改端口: python3 manage.py runserver 端口号
  • 修改 IP 和端口: python3 manage.py runserver IP:端口

Flask

app.run()函数的参数

  • from flask import Flask
  • app = Flask(name)
  • app.run(host=host, port=port, debug=True)
  • python3 manage.py

Manager管理启动命令

  • from flask_script import Manager
  • manage = Manager(app)
  • manage.run()
  • python3.7 hello.py runserver -p 端口号 -h 主机名 -d 打开调试

Tornado

  • from tornado import ioloop
  • import tornado.web
  • 返回一个app应用
def make_app():
   return tornado.web.Application(handlers=[
            (r'/路由地址', 对应方法),
        ], template_path=模版地址, static_path=静态文件地址)
  • app = make_app()
  • app.listen(端口号)
  • ioloop.IOLoop.current().start()
  • python3 manage.py

自定义参数

  • from tornado.options import define, options, parse_command_line
  • 定义默认启动的端口port为8000 define('port', default=8000, type=int)
  • parse_command_line()
  • app.listen(options.port)
  • python xxx.py --port=端口号

路由定义

Djando

  • 在urls.py文件中
  • 导包from django.contrib import admin
  • 导包from django.urls import path
  • urlpatterns = [path('路由地址/', 路由方法),path('路由地址/', 路由方法),..]
  • 设置路由地址admin/,路由方法admin.site.urls为管理页面

路由URL规则

  • from django.urls import path, re_path

path

  • <转换器:参数名>
  • 转换器: int,str,uuid,path

re_path

  • /(\d+)/(\w+)/
  • /(?P<参数名>\d+)/

拆分urls.py文件

  • 新建app文件夹
  • 在setting中的INSTALLED_APPS添加app
  • 在对应的app文件夹中,新建urls.py
  • 导入 from django.urls import path, re_path
  • 在根urls文件里导包, from django.urls import include
  • Django2.0以下写法
    • path('goods/', include('goods.urls')) 当前缀为goods的路径,从goods.urls的文件中寻找路由
    • 例如goods.urls中有/hello/的路由,则要写成goods/hello/
  • Django2.0以上写法

Flask

@app.route('/路由地址/<类型:参数名>/')
    def 路由方法():
        ....

设置参数

  • <类型:参数名>
  • 整型
  • 字符串
  • 不加类型,为字符串
  • 浮点数

使用蓝图

  • pip3 install flask-blueprint
  • from flask import Blueprint
  • blue = Blueprint('first', name)
  • @blue.route('/')
  • from app.views import blue
  • app.register_blueprint(blueprint=blue)

Tornado

  • import tornado.web
  • 在make_app方法的return tornado.web.Application()的handlers=[]参数中
  • (r'/路由名/', 路由方法)

设置参数

位置参数

  • 定义: tornado.web.Application(handlers=[('/days/(d+)/(d+)/), DasyHandler])
  • def get(self, month, day)

关键字参数

  • 定义: tornado.web.Application(handlers=[(r'/days2/(?P\d{4})/(?P\d{2})/(?P\d{2})])
  • def get(self, month, day, year)

路由视图

Djando

  • from django.shortcuts import render
  • from django.http import HttpResponse
  • 定义路由视图:def 路由视图名(request): return HttpResponse('')

判断提交类型

  • if request.method == 'GET':
  • if request.method == 'POST':
  • 若不判断,则默认GET
  • GET 只用于获取数据
  • POST 只用于创建数据
  • PUT 修改某个对象的全部属性
  • PATCH 修改某个对象的部分属性
  • DELETE 删除数据

获取返回的参数

接收get传递参数

接收post传递参数

Flask

  • @blue.route('/') def hello(): return

判断提交类型

  • from flask import request
  • if request.method == 'GET':
  • if request.method == 'POST':

直接返回字符串

  • return 'hello world'

渲染HTML页面

  • from flask import render_template
  • render_template('index.html')

跳转页面

  • from flask import redirect

跳转到路由地址

  • return redirect('/login/')

跳转到路由视图

  • url_for('蓝图的第一个参数.跳转的函数名',传参=值)
  • return redirect(url_for('first.s_id', id=1))

生成响应对象

  • from flask import make_response
  • res = make_response('响应内容', 响应状态码) 创建响应对象
  • return make_response('Hello World', 200)
  • return make_response('Hello World', 200)

获取返回的参数

接收get传递参数

  • from flask import request
  • 变量名 = request.args.get(name)
  • name为input标签的name属性

接收post传递参数

  • from flask import request
  • 变量名 = request.form.get(name)
  • name为input标签的name属性

设置响应状态码

  • res = make_response('响应内容', 响应状态码) 创建响应对象

Tornado

  • 在views.py页面中
  • import tornado.web
  • class 路由视图名(tornado.web.RequestHandler):

判断提交类型

  • def get(self): def post(self): def put(self): def patch(self): def delete(self):

直接返回字符串

  • self.write('hello world')

渲染HTML页面

  • self.render('index.html', 传参=值)

跳转页面

  • self.redirect('路由地址')

切入点函数

  • def initialize():实例化初始内容,在调用行为方法之前将自动调用
  • def prepare():在调用行为方法之前将自动调用
  • def on_finish():在调用行为结束时自动调用

获取返回的参数

接收get传递参数

  • self.get_argument(name)/self.get_arguments(name)

获取请求URL中的参数

  • self.get_query_argument(name)/ self.get_query_arguments(name)

接收post传递参数

  • self.get_argument(name)/self.get_arguments(name)
  • self.get_body_argument(name)/self.get_body_arguments(name)

设置响应状态码

  • self.set_status(200)

cookie参数

关于cookie

  • 产生场景:由于HTTP无状态协议,无法保持登陆状态,使用cookie,保存一个令牌(标识符)用于标识用户的登陆状态
  • 产生令牌:在登陆时向cookie中设置
  • cookie不能跨浏览器,参数有字节限制,不能无限的存储参数

Django

Flask

设置cookie参数

  • 生成响应内容 res = make_reponse()
  • 设置cookie值 res.set_cookie(key, value, max_age) max_age为cookie存在时间毫秒
res = make_response(render_template('index.html'))
# 给index.html添加cookie
# 设置set_cookie('token', )
res.set_cookie('token', '12345678', max_age=3000)
return res

获取cookie参数

  • token = request.cookies.get('token')

删除cookie数据

  • res.delete_cookie('token')

Tornado

普通cookie

设置cookie参数

  • 设置cookie,其中的expire参数表示过期时间,到了过期时间,自动删除
  • self.set_cookie('token', '123456', expires_days=1)

获取cookie参数

  • self.get_cookie('token')

删除cookie数据

  • self.clear_cookie('token')
  • self.clear_all_cookies()

secure cookie


session参数

关于session

  • Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。

Django

Flask

第一种: session数据存储在客户端

  • Flask采用'secure cookie'方式保存session,即session数据是使用base64编码后保存在客户端的cookie中。也就是说无须依赖第三方数据库保存session数据。
  • 先导入session
    • from flask import session
  • 对session中键值对加密,设置secret_key的加密复杂程度,使session的value加密
    • app.secret_key = '1234567890'
  • 向session会话中设置键值对
    • session['login_status'] = 1
  • 判断session是否有登陆标识
    • if 'login_status' in session:

第二种: session数据存储在服务器端

  • 步骤1: 当客户端发送请求到服务端的时候,服务端会校验请求中cookie参数中的sessionid值,如果cookie中不存在sessionid则认为客户端访问服务端时,是发起了一个新的会话。
  • 步骤2: 如果是新的会话,则服务端会传递给客户端一个cookie,并在cookie中存储一个新的sessionid值,并将相关数据保存在session中。
  • 步骤3: 客户端下次再发送请求的时候,请求上下文对象会携带cookie,通过校验cookie中的sessionid值,即可判断是否是同一会话。
  • 步骤4: 如果校验会话是同一会话,则可以从session中获取到之前保存的数据。
  • 访问者的标识问题服务器需要识别来自同一访问者的请求。这主要是通过浏览器的cookie实现的。 访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。

将session数据存储在数据库

  • 安装flask-session,是flask框架的session组件
    • pip3 install flask-session
  • from flask_session import Session
  • 安装python的redis库
    • pip3 install redis
  • 配置Session
    • app.config['SESSION_TYPE'] = 'redis'; app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port=6379)
  • 对session中键值对加密,设置secret_key的加密复杂程度,使session的value加密
    • app.secret_key = '1234567890'
  • Session(app)

读取session数据

  • value = session['login_status']

删除session数据

  • del session['login_status']

Tornado


数据库模型

Django

导入

  • from django.db import models

数据库简单配置与迁移

  • 修改 settings.py 文件中 DATABASE 的数据: NAME,USER,PASSWORD,HOST,PORT,OPTIONS
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'dj',
        'USER': 'root',
        'PASSWORD': '7890267648',
        'HOST':'127.0.0.1',
        'PORT':3306
    }
}
  • 在setting表中的INSTALLED_APPS添加'app名'
  • 生成迁移文件: python manage.py makemigrations
  • 执行迁移文件: python manage.py migrate
  • 当第一次迁移 django 默认提供的表时,直接执行 migrate 即可,若要迁移新建的表或者修改表,则先生成迁移文件,再执行迁移文件。

模型定义

字段定义

  • IntegerField: 整型字段
  • CharField: 字符串
  • BooleanField: 布尔值
  • DateTimeField: 年月日时分秒字段
  • DateField: 年月日
  • TimeField: 时间戳
  • ImageFiled: 图片
  • FloatFiled: 浮点数
  • DecimalField: 浮点数,指定了长度的浮点数
  • TextField: 存文本,texteare
  • AutoField: 自增字段,不用定义

约束定义

  • max_length: 最大长度
  • min_length: 最小长度
  • unique: 唯一
  • null: 是否为空
  • default: 默认值
  • auto_now_add 和 auto_now: 互斥,当调 save()的时候才会生成

模型操作

  • from django.db import models
  • Student.objects

  • 对象.save()
    • stu = Student() stu.save()
  • create(字段=值,字段 2=值 2...)
    • Student.objects.create(s_name='小花',age=20)

  • 对象.delete()
    • Student.objects.filter(s_name = '小小花').delete()
  • filter().delete()
    • stu = Student.objects.filter(s_name = '小明').first() stu.delete()

  • 修改的对象.save()
    • stu.age = 50 stu.save()
  • filter().update(字段=值,字段 2=值 2...)
    • Student.objects.filter(s_name='小花').update(age=40)

查询所有
  • Student.objects.all()
筛选
  • filter(字段=值)
    • 查询结果类型为 QuerySet,取其中的数据,.first(), last(),[下标]
  • .get(字段=值)
    • .get()直接获取到对象 .filter()获取 QuerySet 对象,要使用.first() last()来获取对象 .filter().first() 相当于 .get
    • get(条件),查询条件必须查找到结果,如果查询不到结果,则报错'DoesNotExist',若查询到了多个,也会报错
筛选不满足条件的
  • exclude(),筛选出不满足条件的
统计多少条数据
  • Student.objects.all().count()
排序
  • Student.objects.all().order_by('id')
  • 若要降序,则在字段前家-号('-id')
获取对象
  • Student.objects.all().values('s_name', 'age')
  • 序列化,将对象的属性转化为字典格式数据
模糊查询
  • contains 字段包含关键字 字段__contains = '值'
  • startswith 字段开头包含关键字 字段__startswith = '值'
  • endswith 字段结尾包含的关键字 字段__endswith = '值'
查询结果在某一范围
  • id__in=[1,2,3,4,5,6,7]
  • Student.objects.filter(id__in=[1,2,3,4,5]).all()
  • Student.objects.filter(pk__in=[1,2,3,4,5]).all() pk 代表主键
大于 gt,大于等于 gte,小于 lt,小于等于 lte
  • Student.objects.filter(ag__gt=23).all()
聚合
  • 导包 from django.models import Avg,Sum,Count,Max,Min
    -Student.objects.all().aggragate(Avg('age'))
字段值大于另一个字段值
  • 导包 from django.models import F
  • Student.objects.filter(yuwen__gt=F('math') + 10)
Q() & Q()且 ,Q() | Q() 或,~Q() 非
  • 且 Student.objects.filter(s_name__contains='花', age=23).all()
  • 或 Student.objects.filter(Q(s_name__contains='花') | Q(age=23)).all()
  • 非 Student.objects.filter(~ Q(s_name__contains='花')

模型关联关系

一对一

class A():
    id = modules.IntegerFiled()

class B():
    aa = mldels.OneToOneField(A,, on_delete=models.CASCADE, null=True,related_name='cc')
  • OneToOneField(关联模型)
  • 模型定义
    • 关联名 = models.OneToOneField(关联的表名, related_name = '关系名', on_delete=models.CASCADE, null=True)
  • 已知 A 对象 a 查询 B 对象
    • a.b 当 related_name 没定义时
    • a.cc 当 related_name = 'cc'时
  • 已知 B 对象 b 查询 A 对象 b.aa
  • 一对一:定义在关联的两个模型中的任意一方都可以

一对多

class A():
    id

class B():
    aa = models.ForeignKey(A, on_delete=models.CASCADE, null=True,related_name='cc')
  • ForeignKey(关联模型)
  • 模型定义
    • aa = ForeignKey(A)
  • 已知 A 对象 a,查询 B 对象
    • a.b_set 当 related_name 没定义时
    • a.cc 当 related_name = 'cc'时
  • 已知 B 对象 b 查询 A 对象 b.aa
  • 一对多:定义在'多'的一方

多对多

  • course = models.ManyToManyField(Course要进行关联的表的名字,related_name='stu') 会自动生成中间文件,中间文件的表名为course
  • 查询id为1的学生课程信息
  • stu = Student.objects.get(pk=1)
  • 学生查询课程
    • stu.course
  • 课程查询学生
    • cou = Course.objects(pk=1)
    • 当 related_name 没定义时 cou.student_set.all()
    • 当 related_name 定义时 cou.stu.all()
  • 增加中间表信息
    • stu = Student.objects.filter(s_name = '小明').first()
    • cou1 = Course.objects.get(c_name='日语')
    • stu.course.add(cou1)
  • 删除中间表信息
    • stu.course.remove(cou1)
  • on_delete参数
    • models.CASCADE 表示: 主键所在行的数据被删,外键所在行的数据也会被删
    • models.PROTECT 表示: 主键有对应的外键数据时,不让删除主键的数据
    • models.SET_NULL 表示: 主键删除,外键置空
  • 注意: ManyToManyFiled定义的字段定义在任何一个关联模型中都可以

Flask

使用flask-sqlalchemy操作数据库

  • 安装pymysql与flask_sqlalchemy
  • from flask_sqlalchemy import SQLAlchemy
  • db = SQLAlchemy()
  • 定义id主键,自增字,类型要大写
  • id = db.Column(db.Integer, primary_key=True, autoincrement=True)

配置数据库连接信息

  • dialect+driver://username:password@host:port/database
  • app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:7890267648@localhost:3306/flask9'
  • app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  • db.init_app(app)

迁移模型

  • 第一次迁移模型时候才有用 db.create_all()

删除表

  • db.drop_all()

增删改查

  • 新增
# 新增学生数据
    stu = Student()
    stu.s_name = '小明'
    stu.age = 20
    # 准备向数据库flask9中的student表中插入数据
    db.session.add(stu)
    # 提交操作
    db.session.commit()
    return '创建数据成功'
  • 批量增加
stu_list = []
    for i in range(10):
        stu = Student()
        stu.s_name = '小明' + str(i)
        stu.age = i
        stu_list.append(stu)
    db.session.add_all(stu_list)
    db.session.commit()
    return '数据添加完成'
  • 删除 db.session.delete(stu)

  • 修改

    • stus = Student.query.filter_by(s_name='小张2')[0]
    • stus.age = 100
  • 查询

    • 筛选出来的都为列表,就算只有一个数据,也是列表中存放一个数据,所以要用下标或者.first去取
    • stu = Student.query.filter_by(s_name='小张0').all()[0] # .all为列表
    • stu = Student.query.filter_by(s_name='小张0').first() - 筛选出的第一个
  • 查询所有学生信息

    • all()结果为列表,列表中的元素为查询的学生对象
    • stus = Student.query.all()
    • print(stus)
  • 查询id=1的学生信息

    • stu = Student.query.filter(Student.id == 1).first()
    • get():查询主键所在行的信息
    • stu = Student.query.get(21)
  • 排序 order_by()

    • stus = Student.query.order_by( -Student.id ).all()
  • offset limit

    • stus = Student.query.offset(1).limit(3).all()
    • 分页 stus = Student.query.offset((page-1)*3).limit(3).all()
    • stus[(page-1)3:page3]
  • 模糊查询like % _

    • 包含
      • stus = Student.query.filter(Student.s_name.contains('小张')).all()
    • like
      • stus = Student.query.filter(Student.s_name.like('%小张%')).all()
      • stus = Student.query.filter(Student.s_name.like('_小张')).all()
      • stus = Student.query.filter(Student.s_name.like('小张_')).all()
    • 以什么什么开头
      • stus = Student.query.filter(Student.s_name.stratswith('小张_')).all()
    • 以什么什么结束
      • stus = Student.query.filter(Student.s_name.endswith('小张_')).all()
  • 大于 gt lt 大于等于gt 小于等于le

    • stus = Student.query.filter(Student.age.ge(4)).all()
    • stus = Student.query.filter(Student.age >= 9).all()
  • where id in [1,2,3,4,5,6,7]

    • stus = Student.query.filter(Student.id.in_([1,2,3,3,5,6,7])).all()
  • not in

    • stus = Student.query.filter(Student.id.notin_([1,2,3,3,5,6,7])).all()
  • 多条件查询

    • stus = Student.query.filter(Student.age == 2).filter(Student.s_name.like('小%')).all()
    • stus = Student.query.filter(Student.age == 2, Student.s_name.like('小%')).all()
  • and or 条件查询

    • stus = Student.query.filter(Student.age == 2 or Student.s_name.like('小%')).all()
  • and_, or_ not_

    • from sqlalchemy import and_, not_, or
    • stus = Student.query.filter(and_(Student.age == 2, Student.s_name.like('小%'))).all()

一对多关系

  • 添加外键
    • 定义的关联班级表id的外键g_id
    • g_id = db.Column(db.Integer, db.ForeignKey('grade.id'), nullable=True)
    • 若是新建表,则会自动生成外键,若是已有的表,则要手动在数据库中加外键。
  • 关联关系的定义:stus = db.relationship('Student', backref= 'p')。班级查询学生:班级对象.stus,为列表,返回班级对象对应的学生对象。学生查询班级:学生对象.backref,为列表,返回学生对象对应的班级对象。
  • 有一个外键就要写一个关系

多对多关系

  • 定义
    • stus = db.relationship('Student', secondary=c_s, backref='cou', lazy='dynamic')
    • 学生查询课程:学生对象.backref
    • 课程查询学生:课程对象.stus
    • 添加和删除stu.cou.append(cou1)、stu.cou.remove(cou2)
  • 中间表
    • c_s = db.Table('c_s',db.Column('s_id', db.Integer, db.ForeignKey('student.id')),db.Column('c_id', db.Integer, db.ForeignKey('course.id')))

Tornado

安装SQLAlchemy

  • pip3 install SQLAlchemy

配置连接

  • 新建conn.py文件
  • # 连接数据库格式# mysql+pymysql://root:[email protected]:3306/tornado
  • from sqlalchemy import create_engine
    • # 创建引擎,建立连接 engine = create_engine(db_url)
  • from sqlalchemy.ext.declarative import declarative_base
    • # 模型与数据库表进行关联的基类,模型必须继承于Base
    • Base = declarative_base(bind=engine)
  • from sqlalchemy.orm import sessionmaker
    • # 创建session会话
    • DbSession = sessionmaker(bind=engine)
    • session = DbSession()

建立模型

  • 新建models.py文件
  • from sqlalchemy import Column, Integer, String
  • from utils.conn import Base
  • 创建表和粘贴表的方法
    • def create_db():Base.metadata.create_all()
    • def drop_db():Base.metadata.drop_all()
  • 创建数据模型
  # 要继承Base
class Student(Base):
    # 主键自增的int类型的id主键
    id = Column(Integer, primary_key=True, autoincrement=True)
    # 定义不能为空的唯一的姓名字段
    s_name = Column(String(10), unique=True, nullable=False)
    s_age = Column(Integer, default=18)

使用模型

  • 在views.py文件中
  • 导入创建表和删除表方法
    • from app.models import create_db, Student,drop_db
  • 导入session
    • from utils.conn import session

创建单条数据

  • stu = Student()
  • session.add(stu)
  • session.commit()

创建多条数据

  • session.add_all(stus)
  • session.commit()

删除数据

  • session.delete(stu)
  • session.commit()
    • 或者 session.query(表).filter(筛选条件).delete()

查询数据

  • stus = session.query(Student).filter_by(s_name == '小明').all() 返回列表
    • filter_by 使用字段名s_name
  • stus = session.query(Student).filter(Student.s_name == '小明').all() # 返回列表
    • filter 使用类名.字段名

模版

Django

  • 在setting.py中的TEMPLATES参数设置templates文件夹路径
  • 在setting.py中的STATIC_URL参数设置static文件夹路径
  • 父模板: 用于挖坑 {% block name %} {% endblock %}
  • 子模板: 负责继承父模板后,进行填坑

标签: {% 标签 %}

  • {% extends '父模板' %}
  • {% block title %} {% block %}
  • {% if 条件 %} {% else %} {% endif %}
  • {% ifequal 变量 值 %} {% endifequal %}
  • {% for i in [] %} {% endfor %}

变量: {{ 变量名 }}

  • {{ forloop.counter }}
  • {{ forloop.counter0 }}
  • {{ stu.course.all }}: 通过学生查询所有的课程信息
  • {{ stu.course.下标 }}

过滤器

  • 定义: 使用管道符 ‘|’

Flask

jinja2

  • 语法{% %}
  • 在模版页面中

    {% block title %}
    {% endblock %}

  • 在使用模版的页面中
{% extends 'base.html' %}

{% block title %}
    学生列表页面
{% endblock %}

继承模版填充内容

  • {{ super() }},不能忘加括号
{% block js %}
    {{ super() }}
    
{% endblock %}

引用外部文件写法

{% block css %}
    
{% endblock %

后端向前端传入变量

  • stus_score = [90, 89, 100, 99, 87, 67];return render_template('stu.html', scores = stus_score)

前端解析变量

  • 解析变量使用{{变量名}}

    {{ scores}}

  • 解析标签,extends,block,for
  • {{ loop.index }} 从1开始
  • {{ loop.index0 }} 从0开始
  • {{ loop.revindex }} 反向开始
  • {{ loop.revindex0 }} 反向d到0结束
  • {{ loop.first }} 第一次循环,返回true
  • {{ loop.last }} 最后一次循环,返回true

过滤器

  • content_h2 = 'hello world!'
  • {{ content_h2 | safe }} 加载样式
  • {{ 'Python' | length }} 长度
  • {{ 'Python' | upper }} 大写
  • {{ 'Python' | lower }} 小写
  • {{ 'python' | upper | length }} 长度
  • {{ 'Python' | reverse }} 反序
  • {{ content_h2 | striptags }} 取消样式

Tornado

你可能感兴趣的:(Flask Tornado Django 对比)