看着一双美丽的眼睛流动着对那个时代的向往,不由得让人也期待啊。
关于MVC方式,个人这么理解:
M --> model模块,主要的核心函数处理模块,负责处理大部分的业务的业务模型
V --> view模块,视图模块,负责展现出好看的界面
c --> ctrol模块,操作控制模块,负责处理控制部分
ORM:对象关系映射,包括数据创建过程,数据查询过程,删除,更新的过程。ORM操作数据库模型
来间接的操作数据库。
后期的所有数据库操作都是通过ORM来操作的。
首先在数据库中创建好数据库,数据库名字为meizi,字符集为utf8mb4 – UTF-8 Unicode,排序规则为utf8mb4_general_ci
还是使用之前的妹子图的小项目,先创建目录data,然后新建creata_database.py,准备创建数据库结构,需要的数据结构大致如下
class data():
id = None
# id号
title = ''
# 页面标题
url = ''
# 该页面的主网址
show_img = ''
# 页面的单张展示图片
all_img = ''
# 页面的所有图片
def sample(self):
pass
然后使用sqlalchemy把结构直接映射到数据库,非常方便。这里提起一下,sqlalchemy不是flask自带的,但是falsk对sqlalchemy做了部分的优化,使用pipenv install flask-sqlalchemy即可安装。
ok,下面的新建的数据库模型
# -*- coding: utf-8 -*-
# @Time : 2018/7/24 0024 13:40
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : creata_database.py
# @Software: PyCharm
import sys
from sqlalchemy import Column,Integer,String
# 导入column(字段),Integer(数字类型)
reload(sys)
sys.setdefaultencoding('utf-8')
class data():
id = Column(Integer,primary_key=True,autoincrement=True)
# 设置id号为数据库的主键,并且自增长
# 相当于SQL:id int primary key auto_increment
title = Column(String(100),nullable=True,default='获取该妹子信息失败')
# 页面标题长度为100,并且允许为空,如果为空的话就生成上面的default
url = Column(String(100),nullable=False,unique=True)
# 该页面的主网址长度100,不允许为空,不允许重复
show_img = Column(String(100),nullable=False)
# 页面的单张展示图片
all_img = Column(String(100),nullable=False)
# 页面的所有图片
def sample(self):
pass
然后实例化sql的对象,新增代码:
from flask_sqlalchemy import SQLAlchemy
# 实例化sqlalchemy对象,在flask中导入进来
db = SQLAlchemy()
# db就是sqlalchemy的初始化的核心对象
class data(db.Model):
id= xxx重复上面的代码
把之前的类继承db即可。然后回到主目录下的init.py文件下,该文件之前是把蓝图注册到app里面的,之前的init.py代码如下
# -*- coding: utf-8 -*-
# @Time : 2018/7/19 0019 18:36
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : __init__.py.py
# @Software: PyCharm
import sys
from flask import Flask
from app.web.data.creata_database import db
reload(sys)
sys.setdefaultencoding('utf-8')
def create_app():
app = Flask(__name__,template_folder=('web/templates'))
app.config.from_object('config')
start_Blueprint(app)
return app
def start_Blueprint(app):
from app.web.Mmzi import web
app.register_blueprint(web)
导入data目录下create_database.py中的db对象,然后注册到app当中并且初始化对象,并且调用他。
# -*- coding: utf-8 -*-
# @Time : 2018/7/19 0019 18:36
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : __init__.py.py
# @Software: PyCharm
import sys
from flask import Flask
#from app.web.data.creata_database import db
reload(sys)
sys.setdefaultencoding('utf-8')
def create_app():
app = Flask(__name__,template_folder=('web/templates'))
app.config.from_object('config')
start_Blueprint(app)
db.init_app(app)
with app.app_context():
db.create_all()
return app
def start_Blueprint(app):
from app.web import web
app.register_blueprint(web)
app就像一个插板一样,蓝图可以注册到app里面,路由注册到app里面,甚至数据库也可以注册到app里面,后期的登录等模块一样注册到里面,当前已经差不多配置完成了,还有重要的一点没说,那就是链接到哪个数据库里面。
在主目录下的config.py中可以添加数据库的配置信息,之前config之定义了DEBUG的开关,这个时候可以加入数据库配置。
SQLAlchemy本身无法操作数据库,其必须以来pymsql,cymysql,mysqldb等第三方插件,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,下面使用过cymysql进行操作
app主目录下的config.py配置文件
# -*- coding: utf-8 -*-
# @Time : 2018/7/17 0017 20:42
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : config.py
# @Software: PyCharm
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:[email protected]:3306/meizi'
# SQLALCHEMY_DATABASE_URI是flask定义好的配置项,就像DEBUG一样
# mysql + cymysql : 使用mysql数据库,驱动使用cymysql(需要pipenv install cymysql),你还可以使用pymysql
# 然后数据库账号密码,主机和端口以及数据库名字
最后允许主程序的时候,会发现数据库中多了一个名为meizi的数据库,其中多了一张名为data的表,数据库的结构和定义的结构一致。
MySQL-Python
mysql+mysqldb://:@[:]/
pymysql
mysql+pymysql://:@/[?]
MySQL-Connector
mysql+mysqlconnector://:@[:]/
cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
# coding=utf-8
from sqlalchemy import create_engine
engine = create_engine("mysql+pymysql://root:[email protected]:3306/school?charset=utf8", max_overflow=5)
# 执行SQL
cur = engine.execute(
"insert into user (name, password) values('lihy', 'lihy')"
)
# 新插入行自增ID
cur.lastrowid
# 执行SQL
cur = engine.execute(
"insert into user(name, password) values(%s, %s)", [('liq', 'liq'), ('liuxj', 'liuxj235')]
)
# 执行SQL
cur = engine.execute(
"insert into user(name, password) values(%(name)s, %(password)s)", name='lium', password='lium123'
)
# 执行SQL
cur = engine.execute('select * from user')
# 获取第一行数据, 第n行,所有数据
cur.fetchone()
cur.fetchmany(3)
cur.fetchall()
# -*-coding:utf-8-*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]:3306/movie'
# 用于连接数据的数据库
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。
db = SQLAlchemy(app)
# 实例化db对象
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(35), unique=True)
pwd = db.Column(db.String(20))
phone = db.Column(db.String(11), unique=True)
def __repr__(self):
# repr返回一个对象的 string 格式,repr的用法是:比如a='admin',repr(a)>>>“‘admin’”
return ''%self.name
关系使用 relationship() 函数表示。然而外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明:
class Person(db.Model):
__tablename__ = 'persion'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(100),index=True)
pwd = db.Column(db.String(100),index=True)
info = db.relationship('Address',backref = 'ss')
class Address(db.Model):
__tablename__ = 'address'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
persion_id = db.Column(db.Integer, db.ForeignKey('persion.id'))
上面的例子中,address表中的person_id关联对象为person表的id的值。随后在person表中设置关联属性,关联属性名为info,第一个参数指向Address模型,另一个名叫backref的参数,叫做反向关系,我们将其设置成backref=ss。设置好了后它会向Persion模型中添加一个名为info的属性,这个属性可以代替persion_id去直接访问Persion模型的对象。
>>>r=persion(id=1,name='admin')
>>>u=User(id=10,name='Hyman',persion_id=1)
>>>r.info.append(u)
>>>print u.role
我们将u添加到r的info中,这样我们同时也在u中添加了一个名叫做persion的属性,而这属性就是我们定义的r对象.这就是所谓的可以用info代替persion_id访问Role模型,但是它获取的是Persion模型对象而非器对应的id的值…
如果使用MYSQL语句创建数据库然后使用外键关联的话,这么写:
用户表
create table user(
id int primary key autoincrement,
username varchar(100) not null
)
文章表
create table article(
id int primary key autoincrement,
title varchar(100) not null,
content text,
authot_id int, //这个是关联用户表的id字典,要记住一个表的外键一定是另一个表的主键
foreign ket 'author_id' references 'user.id'
)
就这个例子如果使用SQLALchemy的话,创建模型这么写
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)
author_id = db.Column(db.Integer,db.ForeignKey('user.id'))# 引用user表的id字段
MySQL主键和外键使用及说明
db.create_all()
向数据库插入数据分为三个步骤:
from 你的数据库模型文件 import 你创建的数据库中的表名
me = 你创建的数据库中的表名('admin','18')
db.session.add(me)
db.session.commit()
db.session.delete(me)
db.session.commit()
假设数据库中有如下条目,并且下面条目的表名为User:
id username email
1 admin [email protected]
2 peter [email protected]
3 guest [email protected]
获取所有数据:
res = User.query(username).all()
获取返回数据的第一行:
res = User.query(username).first()
过滤数据:
res = User.query(username).filter(id>1).all()
limit:
res = User.query(username).all()[1:3]
and or:
from sqlalchemy import and_
User.query.filter(and_(id==1, username=='admin')).all()
User.query.filter(id==1, username=='admin').all()
User.query.filter(id==1).filter(username=='admin').all()
from sqlalchemy import or_
User.query.filter(or_(id==1, id==2)).all()
多条件查询:
res = User.query(username).filter(id>0).filter(id<7).all()
通过用户名查询用户:
peter = User.query.filter_by(username='peter').first()
peter.id
>>> 1
peter.email
>>> [email protected]
如果查询一个不存在的用户名返回 None
使用更复杂的表达式查询一些用户:
User.query.filter(User.email.endswith('@example.com')).all()
>>> [, ]
返回对象是列表
按某种规则对用户排序:
User.query.order_by(User.username)
>>> [, , ]
限制返回用户的数量:
User.query.limit(1).all()
>>> []
filter_by
和filter
都是过滤条件,只是用法有区别filter_by
里面不能用!=
还有> <
等等,所有filter
用得更多,filter_by
只能用=
。
res = User.query.filter(User.username='admin').first()
res.username='root'
db.sission.commit()
#coding:utf-8
from flask_sqlalchemy import SQLAlchemy
from flask import Flask,render_template
app = Flask(__name__,template_folder='')
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]:3306/test404?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(50),index=True)
content = db.Column(db.Text)
db.create_all()
@app.route('/')
def index():
# # 添加数据
# # insert article(title,content) values('妹子大粑粑','AAbbCCaaaeeA啊啊')
# ti = Article(title = '妹子大粑粑',content='AAbbCCaaaeeA啊啊')
# db.session.add(ti)
# db.session.commit()
# # 查询数据
# # select * from article where title='妹子大粑粑'
# result = Article.query.filter(Article.title=='妹子大粑粑').first().content
# # 第一条的内容
# res1 = Article.query.filter(Article.title=='妹子大粑粑').all()[0].content
# # 第一条的内容
# return render_template('index.html',x=res1)
# # 修改数据
# # 先查询到要修改的数据,然后对需要修改的地方修改,然后提交
# result = Article.query.filter(Article.title == '妹子大粑粑').first()
# result.content = '啊啊啊啊啊啊啊啊啊去啊啊啊啊啊啊啊土拨鼠啊'
# db.session.commit()
# # 删除数据
# # 同上
# result = Article.query.filter(Article.title == '妹子大粑粑').first()
# db.session.delete(result)
# db.session.commit()
app.run(debug=True)
创建一个数据库对象
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(32))
def __repr__(self):
return "" % self.name
person = Person(name='jack')
session.add(person)
session.commit()
如何获取id的?
>>> person = Person(name='ilis')
>>> person.id #此时还没有commit到mysql,因此无id
>>> session.add(person)
>>> person.id #同上
>>> session.commit()
2015-08-18 23:08:23,530 INFO sqlalchemy.engine.base.Engine INSERT INTO person (name) VALUES (%s)
2015-08-18 23:08:23,531 INFO sqlalchemy.engine.base.Engine ('ilis',)
2015-08-18 23:08:23,532 INFO sqlalchemy.engine.base.Engine COMMIT
>>> person.id #commit后,可以获取该对象的id
2015-08-18 23:08:27,556 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2015-08-18 23:08:27,557 INFO sqlalchemy.engine.base.Engine SELECT person.id AS person_id, person.name AS person_name
FROM person
WHERE person.id = %s
2015-08-18 23:08:27,557 INFO sqlalchemy.engine.base.Engine (5L,)
5L
>>>
添加多个数据
session.add_all([
Person(name='jack'),
Person(name='mike')
])
session.commit()
回滚
>>> person = Person(name='test')
>>> session.add(person)
>>> session.query(person).filter(name=='test')
>>> session.query(Person).filter(Person.name=='test').all()
2015-08-18 23:13:23,265 INFO sqlalchemy.engine.base.Engine INSERT INTO person (name) VALUES (%s)
2015-08-18 23:13:23,265 INFO sqlalchemy.engine.base.Engine ('test',)
2015-08-18 23:13:23,267 INFO sqlalchemy.engine.base.Engine SELECT person.id AS person_id, person.name AS person_name
FROM person
WHERE person.name = %s
2015-08-18 23:13:23,267 INFO sqlalchemy.engine.base.Engine ('test',)
[]
>>> session.rollback()
2015-08-18 23:13:37,496 INFO sqlalchemy.engine.base.Engine ROLLBACK
>>> session.query(Person).filter(Person.name=='test').all()
2015-08-18 23:13:38,690 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2015-08-18 23:13:38,691 INFO sqlalchemy.engine.base.Engine SELECT person.id AS person_id, person.name AS person_name
FROM person
WHERE person.name = %s
2015-08-18 23:13:38,692 INFO sqlalchemy.engine.base.Engine ('test',)
[]
>>>
数据查询
使用Session的query()方法。
session.query(Person).all()
session.query(Person).filter(Person.name==‘jack’).one()
session.query(Person).first()
session.query(Person.name).filter(Person.id>1).all()
session.query(Person).all()[1:3]
session.query(Person).ordre_by(-Person.id)
query = session.query(Person)
query.filter(Person.id==1).all()
query.filter(Person.id!=1).all()
query.filter(Person.name.like('%ac%')).all()
query.filter(Person.id.in_([1,2,3])).all()
query.filter(~Person.id.in_([1,2,3])).all()
query.filter(Person.name==None).all()
from sqlalchemy import and_
query.filter(and_(Person.id==1, Person.name=='jack')).all()
query.filter(Person.id==1, Person.name=='jack').all()
query.filter(Person.id==1).filter(Person.name=='jack').all()
from sqlalchemy import or_
query.filter(or_(Person.id==1, Person.id==2)).all()
from sqlalchemy import text
query.filter(text("id>1")).all()
query.filter(Person.id>1).all() #同上
query.filter(text("id>:id")).params(id=1).all() #使用:,params来传参
query.from_statement(
text("select * from person where name=:name")).\
params(name='jack').all()
Query使用count()函数来实现查询计数。
query.filter(Person.id>1).count()
from sqlalchemy import func
session.query(func.count(Person.name), Person.name),group_by(Person.name).all()
session.query(func.count('*')).select_from(Person).scalar()
session.query(func.count(Person.id)).scalar()
import contextlib
@contextlib.contextmanager
def mysql(host='127.0.0.1',user='root',passwd='root',db='meizi',port=3306,charset='utf8'):
conn = pymysql.connect(host='127.0.0.1',user='root',passwd='root',db='meizi',port=3306,charset='utf8')
cursor = conn.cursor()
try:
yield cursor
finally:
conn.commit()
cursor.close()
conn.close()
# # 执行sql
# with mysql() as cursor:
# print(cursor)
# row_count = cursor.execute("select * from tb7")
# row_1 = cursor.fetchone()
# print row_count, row_1
官方文档
参考链接
参考链接