赞
踩
目录
参照博客:SQLAlchemy的使用(一)--基本使用方法_凡凡不知所错的博客-CSDN博客
filter operator :
检索返回的列表,以及列表的标量 :
一篇好的初探文章:【Python】 SQLAlchemy的初步使用 - K.Takanashi - 博客园
session.query(xxx)得到的是一个query对象,上面说过很多后面可以接上的方法,实际上还有更多如下:
one() 如果返回行数不为1,那么就报错;若刚好返回结果就一条就返回这条记录的对象
limit(n) 最多只返回n条结果
offset(n) 直接跳过前n条记录,从n+1条开始返回
order_by(Table.attribute 或者 'attribute') 返回结果按照给出的字段排序。
order_by(User.name.desc()) 或者 order_by('name desc')
filter(condition1).filter(condition2) 多个拼接的filter就相当于and_(condition1,condition2...)
请注意以上所有方法都要在all()之前调用,all出来已经是一个列表了,不能在作为调用方调用这些方法了。
还可以些数据库自带的函数,在用之前记得from sqlalchemy import func,就可以通过func来调用了。这些函数不是放在调用链中,大多数时候都是放在query方法的参数位置,
比如func.count() 统计一共有多少条记录作为结果等等
计数:
可以直接使用 .count()计算有多少行:
session.query(User).filter(User.name.like('%ed')).count()
当需要将指定的东西进行计数,就使用func.count():
session.query(func.count(User.id)).scalar()
使用query.join()结合两张表来查询数据表数据:
- result = session.query(AlchemyTest).join(AlchemyTestError).filter(AlchemyTestError.errorname == 'cuowu').first() #查询AlchemyTest表内的数据,看哪些user有这个error
- if result is not None:
- print(result.TestName)
因为这两张表只有一个外键,所以query.join()知道怎么关联这两张表,但是如果没有或者不止一个外键的时候,使用其他的形式:
result = session.query(AlchemyTest).join((AlchemyTestError, AlchemyTest.TestName==AlchemyTestError.TestName)).first()
这里有一个join的reminder:
outerjoin: query.outerjoin(User.addresses) # LEFT OUTER JOIN
本课程带领大家使用 SQLAlchemy 连接 MySQL 数据库,创建一个博客应用所需要的数据表,并介绍了使用 SQLAlchemy 进行简单了 CURD 操作及使用 Faker 生成测试数据。
学习本课程需要你对 Python 与 MySQL 都有基本的掌握。
ORM 全称 Object Relational Mapping
, 翻译过来叫对象关系映射
。简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对应关系。这样,我们要操作数据库,数据库中的表或者表中的一条记录就可以直接通过操作类或者类实例来完成。
SQLAlchemy 是Python 社区最知名的 ORM 工具之一,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型。
接下来我们将使用 SQLAlchemy 和 MySQL 构建一个博客应用的实验库。
先安装 SQLAlchemy:
sudo pip install sqlalchemy
实验楼环境已经为我们安装了 MySQL,但还没有启动, 在启动 MySQL 之前,我们需要进行一些配置,将 MySQL 默认的 latin1 编码改成 utf8 。
sudo vim /etc/mysql/my.cnf
通过上面的命令打开 MySQL 的配置文件, 添加下面几个配置:
- [client]
- default-character-set = utf8
-
- [mysqld]
- character-set-server = utf8
-
- [mysql]
- default-character-set = utf8
保存退出。现在我们可以启动 MySQL 服务了:
sudo service mysql start
在命令行下输入下面命令启动 MySQL:
mysql -uroot -p
看到上面的内容就说明我们的 MySQL 可以正常启动了(注意,上面的密码不需要输入内容,直接回车就行), 并且我们我们通过命令:
> create database blog;
创建一个名为 blog
的数据库为下面的使用作准备。
另外,我们需要安装一个 Python 与 MySQL 之间的驱动程序:
sudo apt-get install python-mysqldb
我们在 Code 下新建个 Python 文件,叫什么名字就随你便了,这里我们叫 db.py
,写入下面的内容:
- # coding: utf-8
-
- from sqlalchemy import create_engine
- engine = create_engine('mysql+mysqldb://root@localhost:3306/blog')
- print(engine)
在上面的程序中,我们连接了默认运行在 3306
端口的 MySQL 中的 blog
数据库。
运行下这个程序,看到下面的信息说明我们已经连接成功了:
要使用 ORM, 我们需要将数据表的结构用 ORM 的语言描述出来。SQLAlchmey 提供了一套 Declarative 系统来完成这个任务。我们以创建一个 users
表为例,看看它是怎么用 SQLAlchemy 的语言来描述的:
- # coding: utf-8
-
- from sqlalchemy import create_engine
- from sqlalchemy.ext.declarative import declarative_base
- from sqlalchemy import Column, String, Integer
-
-
- engine = create_engine('mysql+mysqldb://root@localhost:3306/blog?charset=utf8')
- Base = declarative_base()
-
-
- class User(Base):
-
- __tablename__ = 'users'
-
- id = Column(Integer, primary_key=True)
- username = Column(String(64), nullable=False, index=True)
- password = Column(String(64), nullable=False)
- email = Column(String(64), nullable=False, index=True)
-
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.username)
我们看到,在 User
类中,用 __tablename__
指定在 MySQL 中表的名字。我们创建了三个基本字段,类中的每一个 Column
代表数据库中的一列,在 Colunm
中,指定该列的一些配置。第一个字段代表类的数据类型,上面我们使用 String
, Integer
俩个最常用的类型,其他常用的包括:
- Text
- Boolean
- SmallInteger
- DateTime
nullable=False
代表这一列不可以为空,index=True
表示在该列创建索引。
另外定义 __repr__
是为了方便调试,你可以不定义,也可以定义的更详细一些。
python db.py
运行程序,我们在 MySQL 中看看表是如何创建的:
对于一个普通的博客应用来说,用户和文章显然是一个一对多的关系,一篇文章属于一个用户,一个用户可以写很多篇文章,那么他们之间的关系可以这样定义:
- class User(Base):
-
- __tablename__ = 'users'
-
- id = Column(Integer, primary_key=True)
- username = Column(String(64), nullable=False, index=True)
- password = Column(String(64), nullable=False)
- email = Column(String(64), nullable=False, index=True)
- articles = relationship('Article')
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.username)
-
-
- class Article(Base):
-
- __tablename__ = 'articles'
-
- id = Column(Integer, primary_key=True)
- title = Column(String(255), nullable=False, index=True)
- content = Column(Text)
- user_id = Column(Integer, ForeignKey('users.id'))
- author = relationship('User')
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.title)
每篇文章有一个外键指向 users
表中的主键 id
, 而在 User
中使用 SQLAlchemy 提供的 relationship
描述 关系。而用户与文章的之间的这个关系是双向的,所以我们看到上面的两张表中都定义了 relationship
。
SQLAlchemy 提供了 backref
让我们可以只需要定义一个关系:
articles = relationship('Article', backref='author')
添加了这个就可以不用再在 Article
中定义 relationship
了!
在 User
中我们只定义了几个必须的字段, 但通常用户还有很多其他信息,但这些信息可能不是必须填写的,我们可以把它们放到另一张 UserInfo
表中,这样User
和 UserInfo
就形成了一对一的关系。你可能会奇怪一对一关系为什么不在一对多关系前面?那是因为一对一关系是基于一对多定义的:
- class User(Base):
-
- __tablename__ = 'users'
-
- id = Column(Integer, primary_key=True)
- username = Column(String(64), nullable=False, index=True)
- password = Column(String(64), nullable=False)
- email = Column(String(64), nullable=False, index=True)
- articles = relationship('Article', backref='author')
- userinfo = relationship('UserInfo', backref='user', uselist=False)
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.username)
-
-
- class UserInfo(Base):
-
- __tablename__ = 'userinfos'
-
- id = Column(Integer, primary_key=True)
- name = Column(String(64))
- qq = Column(String(11))
- phone = Column(String(11))
- link = Column(String(64))
- user_id = Column(Integer, ForeignKey('users.id'))
定义方法和一对多相同,只是需要添加 userlist=False
。
一遍博客通常有一个分类,好几个标签。标签与博客之间就是一个多对多的关系。多对多关系不能直接定义,需要分解成俩个一对多的关系,为此,需要一张额外的表来协助完成:
- article_tag = Table(
- 'article_tag', Base.metadata,
- Column('article_id', Integer, ForeignKey('articles.id')),
- Column('tag_id', Integer, ForeignKey('tags.id'))
- )
-
-
- class Tag(Base):
-
- __tablename__ = 'tags'
-
- id = Column(Integer, primary_key=True)
- name = Column(String(64), nullable=False, index=True)
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.name)
表已经描述好了,在文件末尾使用下面的命令在我们连接的数据库中创建对应的表:
- if __name__ == '__main__':
- Base.metadata.create_all(engine)
进入 MySQL 看看:
所有的表都已经创建好了!
当你想打电话给朋友时,你是否得用手机拨通他的号码才能建立起一个会话?同样的,你想和 MySQL 交谈也得先通过 SQLAlchemy 建立一个会话:
- from sqlalchemy.orm import sessionmaker
-
- Session = sessionmaker(bind=engine)
- session = Session()
你可以把 sessionmaker
想象成一个手机,engine
当做 MySQL 的号码,拨通这个“号码”我们就创建了一个 Session 类,下面就可以通过这个类的实例与 MySQL 愉快的交谈了!
如果你玩过LOL, 我想你一定知道Faker。而在 Python的世界中,Faker 是用来生成虚假数据的库。 安装它:
sudo pip install faker
下面结合 Faker 库创建一些测试数据:
- faker = Factory.create()
- Session = sessionmaker(bind=engine)
- session = Session()
-
- faker_users = [User(
- username=faker.name(),
- password=faker.word(),
- email=faker.email(),
- ) for i in range(10)]
- session.add_all(faker_users)
-
- faker_categories = [Category(name=faker.word()) for i in range(5)]
- session.add_all(faker_categories)
-
- faker_tags= [Tag(name=faker.word()) for i in range(20)]
- session.add_all(faker_tags)
-
- for i in range(100):
- article = Article(
- title=faker.sentence(),
- content=' '.join(faker.sentences(nb=random.randint(10, 20))),
- author=random.choice(faker_users),
- category=random.choice(faker_categories)
- )
- for tag in random.sample(faker_tags, random.randint(2, 5)):
- article.tags.append(tag)
- session.add(article)
-
- session.commit()
在上面的代码中我们创建了10个用户,5个分类,20个标签,100篇文章,并且为每篇文章随机选择了2~5个标签。
使用 SQLAlchemy 往数据库中添加数据,我们只需要创建相关类的实例,调用 session.add()
添加一个,或者 session.add_all()
一次添加多个, 最后 session.commit()
就可以了。
更新一个字段:
- >>> a = session.query(Article).get(10)
- >>> a.title = 'My test blog post'
- >>> session.add(a)
- >>> session.commit()
添加一个标签:
- >>> a = session.query(Article).get(10)
- >>> a.tags.append(Tag(name='python'))
- >>> session.add(a)
- >>> session.commit()
- >>> a = session.query(Article).get(10)
- >>> session.delete(a)
- >>> session.commit()
删除直接调用 delete
删除获取到的对象,提交 session 即可。
在SQLAlchemy中,Text
和String
都是用于在数据库中存储字符串的类型,但它们之间有一些区别。
String
类型是变长字符串,它存储的是字符数据的最大长度,而Text
类型则是可变长度的字符串,它存储的是数据的实际长度。因此,如果存储的字符串长度固定,使用String
更有效率,而如果存储的字符串长度不固定,使用Text
更合适。Text
类型存储的是实际长度,所以在某些数据库中,它可能比String
类型在性能上更占优势。尤其是在处理大量数据时,使用Text
类型可能会提高查询效率。String
类型就足够了,因为它适用于大多数常见的字符串场景。但是,如果你需要存储大量文本数据,例如文章、描述等,使用Text
类型可能更适合。总之,在选择Text
和String
类型时,需要考虑你的实际需求和数据库性能。在大多数情况下,使用String
类型是足够的,但如果你需要存储大量可变长度的文本数据,使用Text
类型可能更有优势。
- # coding: utf-8
-
- import random
- from faker import Factory
-
- from sqlalchemy import create_engine, Table
- from sqlalchemy.ext.declarative import declarative_base #提取声明
- from sqlalchemy import ForeignKey #外键
- from sqlalchemy import Column, String, Integer, Text
- from sqlalchemy.orm import sessionmaker, relationship #创建会议、关系
-
-
- engine = create_engine('mysql+mysqldb://root@localhost:3306/blog?charset=utf8')
- Base = declarative_base()
-
-
- class User(Base):
-
- __tablename__ = 'users'
-
- id = Column(Integer, primary_key=True)
- username = Column(String(64), nullable=False, index=True)
- password = Column(String(64), nullable=False)
- email = Column(String(64), nullable=False, index=True)
- articles = relationship('Article', backref='author')
- userinfo = relationship('UserInfo', backref='user', uselist=False)
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.username)
-
-
- class UserInfo(Base):
-
- __tablename__ = 'userinfos'
-
- id = Column(Integer, primary_key=True)
- name = Column(String(64))
- qq = Column(String(11))
- phone = Column(String(11))
- link = Column(String(64))
- user_id = Column(Integer, ForeignKey('users.id'))
-
-
- class Article(Base):
-
- __tablename__ = 'articles'
-
- id = Column(Integer, primary_key=True)
- title = Column(String(255), nullable=False, index=True)
- content = Column(Text)
- user_id = Column(Integer, ForeignKey('users.id'))
- cate_id = Column(Integer, ForeignKey('categories.id'))
- tags = relationship('Tag', secondary='article_tag', backref='articles')
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.title)
-
-
- class Category(Base):
-
- __tablename__ = 'categories'
-
- id = Column(Integer, primary_key=True)
- name = Column(String(64), nullable=False, index=True)
- articles = relationship('Article', backref='category')
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.name)
-
-
- article_tag = Table(
- 'article_tag', Base.metadata,
- Column('article_id', Integer, ForeignKey('articles.id')),
- Column('tag_id', Integer, ForeignKey('tags.id'))
- )
-
-
- class Tag(Base):
-
- __tablename__ = 'tags'
-
- id = Column(Integer, primary_key=True)
- name = Column(String(64), nullable=False, index=True)
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.name)
-
-
- if __name__ == '__main__':
- Base.metadata.create_all(engine)
-
- faker = Factory.create()
- Session = sessionmaker(bind=engine)
- session = Session()
-
- faker_users = [User(
- username=faker.name(),
- password=faker.word(),
- email=faker.email(),
- ) for i in range(10)]
- session.add_all(faker_users)
-
- faker_categories = [Category(name=faker.word()) for i in range(5)]
- session.add_all(faker_categories)
-
- faker_tags= [Tag(name=faker.word()) for i in range(20)]
- session.add_all(faker_tags)
-
- for i in range(100):
- article = Article(
- title=faker.sentence(),
- content=' '.join(faker.sentences(nb=random.randint(10, 20))),
- author=random.choice(faker_users),
- category=random.choice(faker_categories)
- )
- for tag in random.sample(faker_tags, random.randint(2, 5)):
- article.tags.append(tag)
- session.add(article)
-
- session.commit()
本篇教程带领大家使用 SQLAlchemy 创建了一个博客应用的数据库及相关表,再次过程中, 介绍了使用 SQLAlchemy 定义一对一、一对多及多对多关系,CURD 及使用 Faker 生成测试数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。