Web后端学习笔记 Flask(6)数据库
SQLAlchemy一对一关系实现:
在一对多的条件下:给Article表中添加article,只需要将article放入到user的article属性中,再将user添加到user表中即可,此时的article会自动添加到Article表中。
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) content = Column(Text, nullable=False) uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False) # 创建外键 # ondelete表示的是外键的约束 author = relationship("User", backref="articles") # relationship 一个Article对应一个author def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username article1 = Article(title="new art 1", content="ct111") article2 = Article(title="new art 2", content="ct222") article3 = Article(title="new art 3", content="ct333") user = User(username="ghost") user.articles.extend([article1, article2, article3]) db_session.add(user) db_session.commit() # 此时,user被添加到User表中,而所有的文章添加到了Article表中,uid是当前添加的user
在一对一的条件下,也可以进行添加,例如,通过添加article,实现将user添加到User中
article1 = Article(title="the Knight", content="ktkt111") user = User(username="knight") # 一对一直接赋值即可 article1.author = user db_session.add(article1) db_session.commit()
一对一关系的实现:
举例: 在后台会存储用户的信息,但是用户信息中有常用的字段(例如,username, id, sex)以及不常用的字段,例如address, email等信息,那么为了提高数据库的查找效率,可以对用户的存储进行优化,将常用的用户信息存放到user表中,将不常用的用户信息存放到user_extend表中,则这两个表的关系就是一对一的关系。
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) content = Column(Text, nullable=False) uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False) # 创建外键 # ondelete表示的是外键的约束 author = relationship("User", backref="articles") # relationship 一个Article对应一个author def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) # 因为一个User只能对应一个user_extend,必须是一对一的关系 extend = relationship("UserExtend", uselist=False) # uselist表示使用列表,默认为True, 表示User下的extend是一个列表,则表示extend不唯一 # 由于extend需要与user一一对应,所以将uselist参数设置为False,此时表示extend是唯一的 def __repr__(self): return str(self.id) + " | " + self.username class UserExtend(Base): __tablename__ = "user_extend" id = Column(Integer, primary_key=True, autoincrement=True) school = Column(String(50), nullable=True) address = Column(String(50), nullable=False) email = Column(String(50), nullable=False) uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICTION")) # 在orm层面做关联 user = relationship("User") article1 = Article(title="the Knight", content="ktkt111") user = User(username="knight")
通过这样的设置,user和user_extend则会成为一一对应,但是此时不能再设置backref参数为extend
还有一种方法,即通过backref函数设置backref参数设置。
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship, backref HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) content = Column(Text, nullable=False) uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False) # 创建外键 # ondelete表示的是外键的约束 author = relationship("User", backref="articles") # relationship 一个Article对应一个author def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username class UserExtend(Base): __tablename__ = "user_extend" id = Column(Integer, primary_key=True, autoincrement=True) school = Column(String(50), nullable=True) address = Column(String(50), nullable=False) email = Column(String(50), nullable=False) uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICTION")) # 在orm层面做关联 user = relationship("User", backref=backref("extend", uselist=False)) article1 = Article(title="the Knight", content="ktkt111") user = User(username="knight")
多对多的关系实现:
举例:在博客上,一篇文章的标签有多个,一个标签也可能对应多篇文章,这是一个典型的多对多的关系。
如果需要定义一个多对多的关系,那么首先需要将两个做多对多的模型定义出来,使用Table定义一个中间表,中间表一般只包含两个模型的外键字段,让这两个字段的组合作为中间表的复合主键,在多对多的两个模型上,随便选择一个,做一个relationship,同时定义secondary参数为中间表。
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 article_tag = Table( "article_tag", # 数据库的名字 Base.metadata, # 元数据 Column("article_id", Integer, ForeignKey("article.id"), primary_key=True), Column("tag_id", Integer, ForeignKey("tag.id"), primary_key=True), # 这个表中没有主键,可以将article_id和tag_id一起作为一个复合主键 # 假设user表中 article_id/title = 1/"cxcx" # tag表中,tag_id / tag_name = 1/"leisure" # 则数据表article_tag 中会插入 article_id/tag_id = 1/1 # 为了减少数据存储的冗余,因该只能插入一次 article_id/tag_id = 1/1, # 所以可以将他们的组合作为一个复合主键 ) class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) tags = relationship("Tag", backref="articles", secondary=article_tag) def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) class Tag(Base): __tablename__ = "tag" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + "|" + self.name # 创建表 # Base.metadata.drop_all() # Base.metadata.create_all() # 插入数据 # article1 = Article(title="gone to xxx") # article2 = Article(title="Leave now") # # tag1 = Tag(name="scary") # tag2 = Tag(name="horrible") # article1.tags.extend([tag1, tag2]) # # tag3 = Tag(name="funny") # article2.tags.extend([tag2, tag3]) # # db_session.add_all([article1, article2]) # db_session.commit() # 数据查询 articles = db_session.query(Article).all() for article in articles: tag_str = [] for tag in article.tags: tag_str.append(tag.name) print(article.title, " ", tag_str)
查询的效果:
ORM层面删除数据注意事项:
外键以及外键约束是数据库层面,下面介绍以下基于ORM层面的约束。例如,在数据库层面有一个约束叫restrict,代表限制删除,即如果要删除父表的数据,但是由于从表也能用到了父表的数据,所以数据库是拒绝删除的。但是在ORM层面,如果指定了级联删除,那么ORM就会无视数据库的RESTRICT约束,先把从表中的数据删除,然后再将从表中的数据删除。这样就实现了级联删除。
orm层面删除数据会无视MySQL层面的外键约束,直接会将对应的数据删除,然后将从表中的外键设置为空,如果想要避免这种行为,应该将从表中的null设置为False.
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) uid = Column(Integer, ForeignKey("user.id"), nullable=False) author = relationship("User", backref="articles") def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) # Base.metadata.drop_all() # Base.metadata.create_all() # # user1 = User(username="Topic") # article1 = Article(title="Gone with u") # article1.author = user1 # db_session.add(article1) # db_session.commit() # 在orm层面会直接删除数据, # orm会先将article的uid设置为null,然后再将user表中的数据删除 # 为了限制这种默认的行为,可以将uid的nullable属性设置为False user = db_session.query(User).first() db_session.delete(user) db_session.commit()
orm层面的CASCADE删除
在SQLAlchemy中,只要将一个数据添加到session中,和它相关联的数据都可以一起存储到数据库中。这是通过relationship的时候,有一个关键字参数cascade可以设置这些属性。cascade的属性值有:
1. save-update:默认值,表示在添加一条数据的时候,会把其他和它相关联的数据都添加到数据库中。
2. delete:表示删掉某一模型中的数据的时候,是否删除掉使用relationship关联的数据。
3. delete-orphan:表示当对一个ORM对象解除了父表中的关联对象的时候,自己便会被删除掉。当然如果父表中的数据被删除,自己也会被删除。这个选项只能用在一对多上,不能用在多对多以及多对一上。并且还需要在子模型的relationship中,增加一个single_parent=True的参数。
4. merge:默认选型。当在使用session.merge合并一个对象的时候,会将使用了relationship相关联的对象进行merge操作。
5. expunge: 移除操作的时候,会将相关联的对象也进行移除,这个操作只是从session中移除,并不会真正从数据库中移除。
6. all:是对save-update,merge,refresh-expire, expunge,delete的集中缩写
# 数据库层面定义 uid = Column(Integer, ForeignKey("user.id", cascade="save-update, delete"))
如果需要实现,删除文章的时候,将相关的作者删除,则可以设置cascade
class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # 数据库层面定义 uid = Column(Integer, ForeignKey("user.id")) # orm层面定义 author = relationship("User", backref="articles", cascade="save-update, delete") def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)
如果需要实现,删除文章的时候,删除相关的作者,或者删除作者的时候,同时删除相关的文章,则可以在user中也定义一个relationship.
class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) articles = relationship("Article", cascade="save-update,delete") def __repr__(self): return str(self.id) + " | " + self.username class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # 数据库层面定义 uid = Column(Integer, ForeignKey("user.id")) # orm层面定义 author = relationship("User", cascade="save-update,delete") def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)
例如,可以再定义一张表,comment:
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) # 这里可以用backref函数在子表中实现 articles = relationship("Article", cascade="save-update,delete") # user删除,对应的article会删除 comments = relationship("Comment") # user删除,对应的comment不会删除 def __repr__(self): return str(self.id) + " | " + self.username class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # 数据库层面定义 uid = Column(Integer, ForeignKey("user.id")) # orm层面定义 author = relationship("User", cascade="save-update,delete") def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) class Comment(Base): __tablename__ = "comment" id = Column(Integer, primary_key=True, autoincrement=True) content = Column(String(50), nullable=False) uid = Column(Integer, ForeignKey("user.id")) author = relationship("User") def __repr__(self): return str(self.id) + " | " + self.content # Base.metadata.drop_all() # Base.metadata.create_all() user1 = User(username="Top") article1 = Article(title="Gone with wind") article2 = Article(title="Jane") comment1 = Comment(content="good") comment2 = Comment(content="great works") user1.articles.append(article1) user1.articles.append(article2) user1.comments.append(comment1) user1.comments.append(comment2) db_session.add(user1) db_session.commit()
数据库中的排序:三种排序方法:
1. orderby
在数据库中插入数据:
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time) # Base.metadata.drop_all() # Base.metadata.create_all() # article = Article(title="title3") # db_session.add(article) # db_session.commit() articles = db_session.query(Article).order_by(Article.create_time.desc()) # 反向排序 # articles = db_session.query(Article).order_by("~article.create_time") # 反向排序 for article in articles: print(article)
排序结果:
2. 定义模型的时候,传递orderby参数
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) # 定义排序的方式 __mapper_args__ = { "order_by": create_time.desc() } def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time) # Base.metadata.drop_all() # Base.metadata.create_all() # article = Article(title="title3") # db_session.add(article) # db_session.commit() articles = db_session.query(Article).all() # 反向排序 # articles = db_session.query(Article).order_by("~article.create_time") # 反向排序 for article in articles: print(article)
3. 在定义relationship的时候,可以传递order_by参数,指定排序方式
在存在主表以及父表的时候,通过relationship中的参数指定排序方式
首先在表中插入数据:
示例代码:
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship, backref from datetime import datetime import random from sqlalchemy import Table HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) uid = Column(Integer, ForeignKey("user.id")) # 通过user拿到user下的所有的文章的时候,可以通过时间排序 author = relationship("User", backref=backref("articles", order_by=create_time.desc())) def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time) class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username # Base.metadata.drop_all() # Base.metadata.create_all() # article1 = Article(title="title1") # article2 = Article(title="title2") # user = db_session.query(User).filter(User.username == "toc").first() # user.articles.append(article2) # # db_session.add(user) # db_session.commit() user = db_session.query(User).first() articles = user.articles for article in articles: print(article)
查询结果:
排序的默认方式是从小到大,如果需要反过来,可以使用这个字段的desc()方法。
limit,offset,以及切片操作:
limit:可以限制每次查找的时候只查询几条数据
offset:可以限制查询数据的时候过滤掉前面多少条数据
slice:可以对query()对象使用切片操作
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship, backref from datetime import datetime import random from sqlalchemy import Table import time HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time) # Base.metadata.drop_all() # Base.metadata.create_all() # 插入数据 # for x in range(100): # title = "title" + str(x+1) # article = Article(title=title) # time.sleep(1) # db_session.add(article) # db_session.commit() # print("current {}".format(x)) # # 查询limit articles = db_session.query(Article).limit(10).all() for article in articles: print(article) # 查询offset print("-"*50) articles1 = db_session.query(Article).offset(10).limit(10).all() # 从第11条开始,查找10条 for article in articles1: print(article) # 查询slice print("-"*50) articles2 = db_session.query(Article).slice(20, 30).all() for article in articles2: print(article)
数据查询懒加载技术:
在一对多,或者多对多的时候,如果想要获取多的这一部分的数据的时候,通常来讲,通过一个属性就可以全部获取,例如上面用到的user.artices就可以获取全部的文章。但是有的时候并不像获取全部的数据,指向获取这个作者今天发布的文章,或者只是想展示少部分的数据。可以通过给relationship传递一个lazy=dynamic,那么以后通过user.articles获取到的就不是一个列表,而是一个AppendQuery对象,可以对这个对象在进行一层过滤和排序操作。
如果采用将所有的数据从数据库中拿出来再进行过滤的话,就会比较耗费性能。上述的方法称为懒加载。
# -*- coding: utf-8 -*- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func from sqlalchemy import Text, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship, backref from datetime import datetime import random from sqlalchemy import Table import time HOST_NAME = "127.0.0.1" PORT = "3306" DATABASE = "cms" USERNAME = "root" PASSWORD = "root1234" # dialect+driver://username:password@host:port/database DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format( username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE ) # 创建数据库引擎 engine = create_engine(DB_URI) Base = declarative_base(engine) # 通过继承Base创建ORM模型/ 创建基类 db_session = sessionmaker(engine)() # 创建会话,才能实现增删改查 # 1. 创建ORM模型,必须继承自SQLAlchemy: # 2. 在ORM中创建一些属性,跟表中的字段一一映射,这些属性必须是SQLAlchemy提供的数据类型 # 3. 将创建好的ORM模型映射到数据库中 class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) def __repr__(self): return str(self.id) + " | " + self.username class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # 数据库层面定义 uid = Column(Integer, ForeignKey("user.id")) # orm层面定义 author = relationship("User", backref=backref("articles", lazy="dynamic")) # 懒加载 def __repr__(self): return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid) user = db_session.query(User).first() print(type(user.articles)) articles = user.articles.filter(Article.id > 50).all() # user.articles可以直接使用filter进行过滤 for article in articles: print(article) # user.articles 是一个<class 'sqlalchemy.orm.dynamic.AppenderQuery'> # 所以除了可以使用filter的方法 # 也可以使用append方法添加新的数据,再次commit到数据库中。 article_new = Article(title="new article") user.articles.append(article_new) db_session.commit()
lazy的属性值:
1. select, 默认值,例如,如果没有访问user.articles,sqlalchemy就不会从数据库中查找数据,一旦访问了这个属性,sqlalchemy就会从数据库查找所有的数据,返回的数据是一个list对象,这也是懒加载。
2. dynamic:在访问user.articles属性的时候,返回的是一个AppendQuery对象。
-----------------------------------------------------------------------------------------------------------
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)