# 链接数据库须要建立引擎 from sqlalchemy import create_engine hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" # 链接方式:数据库+驱动://用户名:密码@ip:端口/数据库 engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") # 测试链接是否成功 conn = engine.connect() # 咱们直接可使用conn去获取数据 data = conn.execute("show databases") print(data.fetchall()) # [('information_schema',), ('mysql',), ('performance_schema',), ('sakila',), ('satori',), ('sys',), ('world',)]
from sqlalchemy import create_engine hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") # 须要如下步骤 ''' 1.建立一个orm模型,这个orm模型必须继承SQLAlchemy给咱们提供好的基类 2.在orm中建立一些属性,来跟表中的字段进行一一映射,这些属性必须是SQLAlchemy给咱们提供好的数据类型 3.将建立好的orm模型映射到数据库中 ''' # 1.建立orm,继承基类 from sqlalchemy.ext.declarative import declarative_base # 这个declarative_base只是一个函数,咱们须要传入engine,而后返回基类 Base = declarative_base(engine) class Girls(Base): # 首先是表名,建立表要指定名字,如何指定呢? __tablename__ = "girls" # __tablename__就是咱们的表名,咱们指定为girls # 2.建立属性,来跟表中的字段一一映射 # 首先咱们须要有列,还要有字段的属性。注意:我这里是为了演示,工做中要写在开头。 from sqlalchemy import Column, Integer, String id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(30)) # String也是一个类,里面能够传入数字表示最多能够存多少字节的字符串 age = Column(Integer) gender = Column(String(1)) anime = Column(String(50)) # 3.建立完毕,那么接下来就要映射到数据库中 Base.metadata.create_all() # 表示将Base的全部子类的模型映射到数据库中,一旦映射,即便改变模型以后再次执行,也不会再次映射。
from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class Girls(Base): __tablename__ = "girls" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(30)) age = Column(Integer) gender = Column(String(1)) anime = Column(String(50)) # 实例化一个对象,是用来增删改查数据的 girls =Girls() # 会获得一个Session类 Session = sessionmaker(bind=engine) # 而后实例化获得一个Session对象,这个session使用来提交操做的 session = Session()
girls.name = "satori" girls.age = 16 girls.gender = "f" girls.anime = "东方地灵殿" # 这两步表示将girls作的操做所有提交上去执行 session.add(girls) session.commit() # 也能够批量操做 session.add_all([Girls(name="koishi", age=15, gender="f", anime="东方地灵殿"), Girls(name="mashiro", age=16, gender="f", anime="樱花庄的宠物女孩"), Girls(name="matsuri", age=400, gender="f", anime="sola"), Girls(name="kurisu", age=20, gender="f", anime="命运石之门")]) session.commit()
# session.query获得的是一个query对象,调用filter_by依旧是一个query对象 # 调用first方法获取第一条查询记录,若是不存在则为None girls = session.query(Girls).filter_by(gender="f").first() print(girls.name, girls.age, girls.anime) # satori 16 东方地灵殿
# 改和查比较相似 # 仍是先获取相应的记录 girls = session.query(Girls).filter_by(gender="f").first() # 直接修改便可 girls.name = "古明地觉" # 一旦涉及到数据的变动,那么就必需要进行提交,查不涉及因此不须要 # 如何提交呢?咱们只是改,因此不须要add,直接使用commit便可 session.commit()
# 筛选出要删除的字段 girl = session.query(Girls).filter_by(name="古明地觉").first() # 添加用add,删除用delete session.delete(girl) # 别忘了提交 session.commit()
1.模型,指定查找这个模型中全部的对象python
2.模型中的属性,能够指定查找模型的某几个属性mysql
3.聚合函数git
func.count:统计行的数量程序员
func.avg:求平均值sql
func.max:求最大值数据库
func.min:求最小值flask
func.sum:求总和windows
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, func from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) # 以上这些都是必须的 class Girls(Base): __tablename__ = "girls" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(30)) age = Column(Integer) gender = Column(String(1)) anime = Column(String(50)) # 之后就不会打印一个query对象了,而是会打印返回值 def __repr__(self): return f"{self.name}--{self.age}--{self.anime}" Session = sessionmaker(bind=engine) session = Session() # 这里指定了Girls,也就是模型,那么会查找全部的模型对象 for girl in session.query(Girls).all(): print(girl) ''' koishi--15--东方地灵殿 mashiro--16--樱花庄的宠物女孩 matsuri--400--sola kurisu--20--命运石之门 ''' # 但若是我不想要全部属性,而是要部分属性怎么办呢?好比我只想要name和age,就能够这样 # 会获取一个有元组组成的字典 print(session.query(Girls.name, Girls.age).all()) # [('koishi', 15), ('mashiro', 16), ('matsuri', 400), ('kurisu', 20)] # 聚合函数 # 获得query对象虽然只有一条数据,但仍是要加上first print(session.query(func.count(Girls.name)).first()) # (4,) print(session.query(func.avg(Girls.age)).first()) # (Decimal('112.7500'),) print(session.query(func.max(Girls.age)).first()) # (400,) print(session.query(func.min(Girls.age)).first()) # (15,) print(session.query(func.sum(Girls.age)).first()) # (Decimal('451'),)
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class Girls(Base): __tablename__ = "girls" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(30)) age = Column(Integer) gender = Column(String(1)) anime = Column(String(50)) # 之后就不会打印一个query对象了,而是会打印返回值 def __repr__(self): return f"{self.name}--{self.age}--{self.anime}" Session = sessionmaker(bind=engine) session = Session() # 关于过滤,有两种方法,一种是filter,另外一种是filter_by # filter须要使用类名.属性的方式,filter_by只须要属性便可,这就意味着后者使用简单,但前者能够写出更复杂的查询 # 下面来看看都有哪些查询方法 # 一、==,因为可能有多条,咱们只选择一条。 print(session.query(Girls).filter(Girls.age == 16).first()) # 古明地觉--16--东方地灵殿 # 二、!= print(session.query(Girls).filter(Girls.age != 16).first()) # 四方茉莉--400--sola # 三、like,%和sql里的同样。除此以外还要ilike,不区分大小写 print(session.query(Girls).filter(Girls.anime.like("%久%")).all()) # [雨宫优子--16--悠久之翼, 宫村宫子--15--悠久之翼] # 四、in_,至于为何多了多了一个_,这个bs4相似,为了不和python里的关键字冲突。为何不是_in,若是放在前面那表明不想被人访问 print(session.query(Girls).filter(Girls.age.in_([16, 400])).all()) # [古明地觉--16--东方地灵殿, 椎名真白--16--樱花庄的宠物女孩, 四方茉莉--400--sola, 春日野穹--16--缘之空, 雨宫优子--16--悠久之翼] # 五、notin_,等价于~Girls.age.in_() print(session.query(Girls).filter(Girls.age.notin_([16, 20, 400])).all()) # [立华奏--18--angelbeats, 古河渚--19--Clannad, 坂上智代--18--Clannad, 古明地恋--15--东方地灵殿, 宫村宫子--15--悠久之翼] # 六、isnull print(session.query(Girls).filter(Girls.age is None).first()) # None # 七、isnotnull print(session.query(Girls).filter(Girls.age is not None).first()) # 古明地觉--16--东方地灵殿 # 八、and print(session.query(Girls).filter(and_(Girls.age == 16, Girls.anime == "樱花庄的宠物女孩")).first()) # 椎名真白--16--樱花庄的宠物女孩 # 九、or print(session.query(Girls).filter(or_(Girls.age == 15, Girls.anime == "悠久之翼")).all()) # [古明地恋--15--东方地灵殿, 雨宫优子--16--悠久之翼, 宫村宫子--15--悠久之翼]
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) # 我如今新建两张表 # 表People--表language ==》父表--子表 class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) # 这个pid指的是People里面的id,因此要和People里的id保持一致 pid = Column(Integer, ForeignKey("People.id")) # 引用的表.引用的字段 Base.metadata.create_all()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) # 还记得约束的种类吗 # 1.RESTRICT:父表删除数据,会阻止。 ''' 由于在子表中,引用了父表的数据,若是父表的数据删除了,那么字表就会懵逼,不知道该找谁了。 ''' # 2.NO ACTION ''' 和RESTRICT做用相似 ''' # 3.CASCADE ''' 级联删除:咱们Language表的pid关联了People的id。若是People中id=1的记录被删除了,那么Language中关联id=1的记录也会被删除 就是咱们关联了,个人pid关联了你的id,若是你删除了一条记录,那么根据你删除记录的id,我也会相应的删除一条,要死一块死。 ''' # 4.SET NULL ''' 设置为空:和CASCADE相似,就是个人pid关联你的id,若是id没了,那么pid会被设置为空,不会像CASCADE那样,把相应pid所在整条记录都给删了 ''' # 那么如何设置呢?在ForeignKey中有一个onedelete参数,能够接收上面四种中的一种 pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) # 因为咱们以前已经建立了,因此再次建立已不会修改,因此只能先删除,而后再次建立 Base.metadata.drop_all() Base.metadata.create_all() # 而后添加几条记录吧 Session = sessionmaker(bind=engine) session = Session() session.add_all([People(name="Guido van Rossum", age=62), People(name="Dennis Ritchie", age=77), People(name="James Gosling", age=63), Language(name="Python", birthday=1991, type="解释型", pid=1), Language(name="C", birthday=1972, type="编译型", pid=2), Language(name="Java", birthday=1995, type="解释型", pid=3)]) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) # 若是我想经过Language表查询People表的数据呢? # 能够经过relationship进行关联 people = relationship("People") Base.metadata.drop_all() Base.metadata.create_all() Session = sessionmaker(bind=engine) session = Session() session.add_all([People(name="Guido van Rossum", age=62), People(name="Dennis Ritchie", age=77), People(name="James Gosling", age=63), Language(name="Python", birthday=1991, type="解释型", pid=1), Language(name="C", birthday=1972, type="编译型", pid=2), Language(name="Java", birthday=1995, type="解释型", pid=3)]) session.commit() people = session.query(Language).all() for i in people: # Language的people已经和People这个表关联了,我经过language依旧能够访问 print(i.people.name, i.people.age) ''' Guido van Rossum 62 Dennis Ritchie 77 James Gosling 63 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) language = relationship("Language") def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) people = relationship("People") def __repr__(self): return f"{self.name}--{self.birthday}--{self.type}" Session = sessionmaker(bind=engine) session = Session() # 经过People里的language,查找Language表的记录 # 实际上这里的language仍是全部People对象的集合 language = session.query(People).all() # 遍历People对象 for i in language: # People的language已经和Language这个表关联了,我经过language依旧能够访问 # 因为People和Language是一对多的关系,因此一个People记录可能对应多个Language记录,因此获得的都是一个列表 # 经过i.language,直接会去查找Language表,从而打印出结果 print(i.language) ''' [Python--1991--解释型] [C--1972--编译型, unix--1973--操做系统] [Java--1995--解释型] ''' # 这里获得是每个People对象 for i in language: # 这里遍历每个People对象下的language,经过这里的language查找Language表的记录。 # 而这里的两个language是不同的,因此我这里起名字失误了,不该该都叫language的,容易引发歧义,まぁいいや for j in i.language: print(i.name, j.name, j.birthday, j.type) ''' Guido van Rossum Python 1991 解释型 Dennis Ritchie C 1972 编译型 Dennis Ritchie unix 1973 操做系统 James Gosling Java 1995 解释型 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) # 咱们把这一行注释掉 # language = relationship("Language") def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) # 咱们在People表中把relationship给注释掉了,可是在Language表的relationship中添加了一个backref="language",反向引用 # 意思是说,咱们即使在People中不指定,也依旧能够经过People对象.language的方式来访问到Language表中的全部属性 # 由于前面指定了People表示已经和People表关联了 # 固然这里也能够不叫language,比方说我改为中文试试 ''' people = relationship("People", backref="language") ''' people = relationship("People", backref="古明地盆") def __repr__(self): return f"{self.name}--{self.birthday}--{self.type}" Session = sessionmaker(bind=engine) session = Session() language = session.query(People).all() # 遍历People对象 for i in language: print(i.古明地盆) ''' [Python--1991--解释型] [C--1972--编译型, unix--1973--操做系统] [Java--1995--解释型] ''' # 能够看到即使用中文依旧能够访问,可是工做中千万别这么干,不然被技术leader看到了,要么把你骂一顿,要么把你给开除了
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) # 咱们把这一行注释掉 # language = relationship("Language") def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) people = relationship("People", backref="language") def __repr__(self): return f"{self.name}--{self.birthday}--{self.type}" Session = sessionmaker(bind=engine) session = Session() people = People(id=6, name="KenThompson", age=75) language1 = Language(name="B", birthday=1968, type="编译型", pid=6) language2 = Language(name="Go", birthday=2009, type="编译型", pid=6) # 因为People和Language是关联的,而且经过language能够访问到Language表的属性 # 那么能够经过people.language.append将Language对象添加进去 people.language.append(language1) people.language.append(language2) # 而后只须要提交People对象people,就会自动将Language对象language一、language2也提交了 session.add(people) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) # 咱们把这一行注释掉 # language = relationship("Language") def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class Language(Base): __tablename__ = "Language" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) birthday = Column(Integer, nullable=False) type = Column(String(20), nullable=False) pid = Column(Integer, ForeignKey("People.id", ondelete="RESTRICT")) people = relationship("People", backref="language") def __repr__(self): return f"{self.name}--{self.birthday}--{self.type}" Session = sessionmaker(bind=engine) session = Session() people = People(id=7, name="松本行弘", age=53) language = Language(name="ruby", birthday=1995, type="解释型", pid=7) # 反向添加,刚才的是正向添加的。 # 正向:people.language.append,反向:language.people=people # 正向里的language是backref,反向里的people是people = relationship("People", backref="language")的左值 language.people = people # 而后只须要提交People对象people,就会自动将Language对象language一、language2也提交了 session.add(people) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) # 表示获得的不是一个列表,由于咱们是一对一,只有一个元素 extend = relationship("People_extend", uselist=False) def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class People_extend(Base): __tablename__ = "People_extend" id = Column(Integer, primary_key=True, autoincrement=True) country = Column(String(20)) uid = Column(Integer, ForeignKey("People.id")) # 而且这里不须要backref了,加了会报错 people = relationship("People") ''' people = People() extend = People_extend() 而后经过people.extend = extend实现便可 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) # 表示获得的不是一个列表,由于咱们是一对一,只有一个元素 # extend = relationship("People_extend", uselist=False) def __repr__(self): return f"{self.name}--{self.age}--{self.languages}" class People_extend(Base): __tablename__ = "People_extend" id = Column(Integer, primary_key=True, autoincrement=True) country = Column(String(20)) uid = Column(Integer, ForeignKey("People.id")) # 或者把上面的注释掉,导入backref模块 people = relationship("People", backref=backref("extend", uselist=False)) ''' 用法和以前的同样 people = People() extend = People_extend() 而后经过people.extend = extend实现便可 再使用People访问的时候,直接经过people.extend.来访问便可 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) # 如今咱们的两张表建好了,既然要实现多对多,须要借助第三张表。 # SQLAlchemy已经为咱们提供好了一个table,让咱们去使用 Article_Tag = Table("Article_Tage", Base.metadata, Column("article_id", Integer, ForeignKey("Article.id"), primary_key=True), Column("tag_id", Integer, ForeignKey("Tag.id"), primary_key=True) ) 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) class Tag(Base): __tablename__ = "Tag" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) ''' 总结一下: 一、先把两个须要多对多的模型创建出来 二、使用Table定义一个中间表,中间表就是包含两个模型的外键字段就能够了,而且让它们两个作一个复合主键 三、在两个须要作多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,须要传入一个secondary="中间表" ''' Base.metadata.create_all()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) # 如今咱们的两张表建好了,既然要实现多对多,须要借助第三张表。 # SQLAlchemy已经为咱们提供好了一个table,让咱们去使用 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) ) 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) class Tag(Base): __tablename__ = "Tag" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) ''' 总结一下: 一、先把两个须要多对多的模型创建出来 二、使用table定义一个中间表,中间表就是包含两个模型的外键字段就能够了,而且让它们两个作一个复合主键 三、在两个须要作多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,须要传入一个secondary="中间表" ''' Base.metadata.create_all() article1 = Article(title="article1") article2 = Article(title="article2") tag1 = Tag(name="tag1") tag2 = Tag(name="tag2") # 每一篇文章,添加两个标签 article1.tags.append(tag1) article1.tags.append(tag2) article2.tags.append(tag1) article2.tags.append(tag2) Session = sessionmaker(bind=engine) session = Session() # 只需添加article便可,tag会被自动添加进去 session.add_all([article1, article2]) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) # 如今咱们的两张表建好了,既然要实现多对多,须要借助第三张表。 # SQLAlchemy已经为咱们提供好了一个table,让咱们去使用 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) ) class Article(Base): __tablename__ = "Article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) ''' Article对象.tags获取Tag里面的属性 Tag对象.articles(backref)获取Article里面的属性 ''' tags = relationship("Tag", backref="articles", secondary=Article_Tag) def __repr__(self): return f"{self.title}" class Tag(Base): __tablename__ = "Tag" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) def __repr__(self): return f"{self.name}" ''' 总结一下: 一、先把两个须要多对多的模型创建出来 二、使用table定义一个中间表,中间表就是包含两个模型的外键字段就能够了,而且让它们两个作一个复合主键 三、在两个须要作多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,须要传入一个secondary="中间表" ''' Base.metadata.create_all() # article1 = Article(title="article1") # article2 = Article(title="article2") # # tag1 = Tag(name="tag1") # tag2 = Tag(name="tag2") # # # 每一篇文章,添加两个标签 # article1.tags.append(tag1) # article1.tags.append(tag2) # article2.tags.append(tag1) # article2.tags.append(tag2) # # Session = sessionmaker(bind=engine) # session = Session() # # # 只需添加article便可,tag会被自动添加进去 # session.add_all([article1, article2]) # session.commit() Session = sessionmaker(bind=engine) session = Session() tag = session.query(Tag).first() print(tag.articles) # [article1, article2] article = session.query(Article).first() print(article.tags) # [tag1, tag2] # 能够看到,相应的数据所有获取出来了
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # uid是为了创建外键,咱们要和use表的id进行关联,因此类型也要和user表的id保持一致 uid = Column(Integer, ForeignKey("user.id")) # 这个是为了咱们可以经过一张表访问到另一张表 # 之后User对象即可以经过articles来访问Articles表的属性了 author = relationship("User", backref="articles") Base.metadata.create_all() # 建立几条记录 user = User(username="guido van rossum") article = Article(title="Python之父谈论python的将来") article.author = user # 而后使用session添加article便可,会自动添加user session.add(article) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) class Article(Base): __tablename__ = "article" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) # uid是为了创建外键,咱们要和use表的id进行关联,因此类型也要和user表的id保持一致 uid = Column(Integer, ForeignKey("user.id")) # 这个是为了咱们可以经过一张表访问到另一张表 # 之后User对象即可以经过articles来访问Articles表的属性了 author = relationship("User", backref="articles") Base.metadata.create_all() # # 建立几条记录 # user = User(username="guido van rossum") # article = Article(title="Python之父谈论python的将来") # # article.author = user # # 而后使用session添加article便可,会自动添加user # session.add(article) # session.commit() # 由于只有一条数据,因此直接first user = session.query(User).first() session.delete(user) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) 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")) # 能够看到其余都是不变的,只是这里咱们显式的指定了cascade # 这里设置为"",这样就不会有save-update属性了。 author = relationship("User", backref="articles", cascade="") Base.metadata.drop_all() Base.metadata.create_all() # 建立几条记录 user = User(username="guido van rossum") article = Article(title="Python之父谈论python的将来") article.author = user # 而后使用session添加article便可,此时就不会添加user了 session.add(article) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) 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")) # 能够看到其余都是不变的,只是这里咱们显式的指定了cascade # 咱们也能够手动指定save-update,固然这样和不指定cascade是同样,由于默认就是save-update author = relationship("User", backref="articles", cascade="save-update") Base.metadata.drop_all() Base.metadata.create_all() # 建立几条记录 user = User(username="guido van rossum") article = Article(title="Python之父谈论python的将来") article.author = user # 而后使用session添加article便可,会添加user session.add(article) session.commit()
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) 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")) # 能够看到其余都是不变的,只是这里咱们显式的指定了cascade # 咱们试一下delete,先说一下,能够设置多个属性,属性之间使用英文的逗号分隔 # 这样指定以后,若是当我删除了Article表的数据,那么与之相关联的User表中的数据也会被删除 author = relationship("User", backref="articles", cascade="save-update,delete") Base.metadata.drop_all() Base.metadata.create_all() # 建立几条记录 user = User(username="guido van rossum") article = Article(title="Python之父谈论python的将来") article.author = user # 若是不加delete,那么我删除Article表的数据,User表的数据依旧会坚挺在那里 # 可是我如今加上了delete,那么当我删除Article表的数据,User表的数据也会被删除 session.add(article) session.commit()
class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) age = Column(Integer) # 就以User为例,在SQLAlchemy中有一个属性叫作__mapper_args__ # 是一个字典,咱们能够指定一个叫作order_by的key,value则为一个字段 __mapper_args__ = {"order_by": age} # 倒序的话,__mapper_args__ = {"order_by": age.desc()} # 之后再查找的时候直接session.query(table).all()便可,自动按照咱们指定的排序
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref from pprint import pprint hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) age = Column(Integer) 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")) author = relationship("User", backref=backref("articles")) Base.metadata.drop_all() Base.metadata.create_all() user = User(username="guido", age=63) for i in range(10): article = Article(title=f"title{i}") article.author = user session.add(article) session.commit() user = session.query(User).first() pprint(user.articles) ''' [<__main__.Article object at 0x000001B73F8A5208>, <__main__.Article object at 0x000001B73F8A5278>, <__main__.Article object at 0x000001B73F8A52E8>, <__main__.Article object at 0x000001B73F8A5358>, <__main__.Article object at 0x000001B73F8A53C8>, <__main__.Article object at 0x000001B73F8A5438>, <__main__.Article object at 0x000001B73F8A54A8>, <__main__.Article object at 0x000001B73F8A5550>, <__main__.Article object at 0x000001B73F8A55F8>, <__main__.Article object at 0x000001B73F804400>] '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_ from sqlalchemy import Column, Integer, String, ForeignKey, Table from sqlalchemy.orm import sessionmaker, relationship, backref from pprint import pprint hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) age = Column(Integer) 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")) # 若是转化成一个AppendQuery对象,获取部分数据呢?只须要加上一个lazy="dynamic"便可 # 注意这里必定要写在backref里面,咱们的目的是为了经过user取article,把article转成一个AppendQuery对象,因此要写在backref里面 # 若是写在了外面,那么就至关于经过article去找user,把user变成一个AppendQuery对象了 # 因此咱们要导入backref,表示反向引用。backref="articles",是为了经过user取得article,因此明明定义在article里面,却反过来被user使用 # 同理backref=backref("articles")和backref="articles"是同样的,可是之因此要加上里面的这个backref,是为了给user提供更好的属性,好比这里的懒加载 # 是为了让user找article的时候进行懒加载,若是没有这个backref,那么这个lazy属性咱们可能要定义在user里面了,这样很麻烦 # 可是经过导入backref,咱们能够直接在article里面定义,反过来让user去使用,一旦定义在了外面,不反向了就变成article的了 # 等于经过article找user进行懒加载 author = relationship("User", backref=backref("articles", lazy="dynamic")) def __repr__(self): return f"{self.title}" Base.metadata.drop_all() Base.metadata.create_all() user = User(username="guido", age=63) for i in range(10): article = Article(title=f"title{i}") article.author = user session.add(article) session.commit() user = session.query(User).first() # 此时再也不是InstrumentList,而是一个AppendQuery对象 print(type(user.articles)) # <class 'sqlalchemy.orm.dynamic.AppenderQuery'> # 查看一下源码发现,AppenderQuery这个类继承在Query这个类,也就是说Query可以使用的,它都能使用 print(user.articles.filter(Article.id > 5).all()) # [title5, title6, title7, title8, title9] # 也能够动态添加数据 article = Article(title="100") user.articles.append(article) session.commit() # 不用add,直接commit print(user.articles.filter(Article.id > 5).all()) # [title5, title6, title7, title8, title9, 100] ''' lazy有如下参数: 1.select:默认选项,以user.articles为例,若是没有访问user.articles属性,那么SQLAlchemy就不会从数据库中查找文章。一旦访问,就会查找全部文章,最为InstrumentList返回 2.dynamic:返回的不是一个InstrumentList,而是一个AppendQuery对象。 主要使用这两种状况 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_, func from sqlalchemy import Column, Integer, String, ForeignKey, Table, Enum from sqlalchemy.orm import sessionmaker, relationship, backref from pprint import pprint hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) age = Column(Integer) gender = Column(Enum("male", "female","secret"), default="male") Base.metadata.drop_all() Base.metadata.create_all() user1 = User(username="神田空太", age=16, gender="male") user2 = User(username="椎名真白", age=16, gender="female") user3 = User(username="四方茉莉", age=400, gender="female") user4 = User(username="木下秀吉", age=15, gender="secret") user5 = User(username="牧濑红莉栖", age=18, gender="female") session.add_all([user1, user2, user3, user4, user5]) session.commit() # group_by:分组,比方说我想查看每一个年龄对应的人数 print(session.query(User.age, func.count(User.id)).group_by(User.age).all()) ''' 输出结果: [(15, 1), (16, 2), (18, 1), (400, 1)] ''' # having:在group_by分组的基础上进行进一步查询,比方说我想查看年龄大于16的每个年龄段对应的人数 print(session.query(User.age, func.count(User.id)).group_by(User.age).having(User.age > 16).all()) ''' 输出结果: [(18, 1), (400, 1)] ''' # 若是想看看底层的语句是什么写的,能够不加上all()进行查看 print(session.query(User.age, func.count(User.id)).group_by(User.age).having(User.age > 16)) ''' SELECT user.age AS user_age, count(user.id) AS count_1 FROM user GROUP BY user.age HAVING user.age > %(age_1)s 从user表中选出age,计算count(user.id)做为count_1,按照user.age分组,而且user.age要大于咱们指定的值 '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_, func from sqlalchemy import Column, Integer, String, ForeignKey, Table, Enum from sqlalchemy.orm import sessionmaker, relationship, backref from pprint import pprint hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class User(Base): __tablename__ = "user" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) 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")) author = relationship("User", backref=backref("articles", lazy="dynamic")) def __repr__(self): return f"{self.title}" Base.metadata.drop_all() Base.metadata.create_all() user1 = User(username="guido") user2 = User(username="ken") article1 = Article(title="python") article1.author = user1 article2 = Article(title="B") article2.author = user2 article3 = Article(title="go") article3.author = user2 session.add_all([article1, article2, article3]) session.commit()
# 找到全部用户,按照发表文章的数量进行排序 res = session.query(User.username, func.count(Article.id)).join(Article, User.id == Article.uid).\ group_by(User.id).order_by(func.count(Article.id)) print(res) ''' SELECT user.username AS user_username, count(article.id) AS count_1 FROM user INNER JOIN article ON user.id = article.uid GROUP BY user.id ORDER BY count(article.id) ''' print(res.all()) ''' [('guido', 1), ('ken', 2)] '''
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, and_, or_, func from sqlalchemy import Column, Integer, String, ForeignKey, Table, Enum from sqlalchemy.orm import sessionmaker, relationship, backref from pprint import pprint hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) Session = sessionmaker(bind=engine) session = Session() class Girl(Base): id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) anime = Column(String(50), nullable=False) age = Column(Integer, nullable=False) def __repr__(self): return f"{self.name}--{self.anime}--{self.age}" Base.metadata.create_all() girl1 = Girl(name="雨宫优子", anime="悠久之翼", age=16) girl2 = Girl(name="宫村宫子", anime="悠久之翼", age=16) girl3 = Girl(name="古河渚", anime="clannad", age=19) girl4 = Girl(name="牧濑红莉栖", anime="命运石之门", age=18) session.add_all([girl1, girl2, girl3, girl4]) session.commit()
# 下面要寻找和雨宫优子在同一anime,而且age相同的记录 girl = session.query(Girl).filter(Girl.name == "雨宫优子").first() # Girl.anime == girl.anime, Girl.age == girl.age,girl是咱们查找的name="雨宫优子"的记录,Girl则是整个表 # 查找整个表中的anime等于girl.anime 而且 age等于girl.age的记录 expect_girls = session.query(Girl).filter(Girl.anime == girl.anime, Girl.age == girl.age, Girl.name != "雨宫优子").all() print(expect_girls) # [宫村宫子--悠久之翼--16]
# 使用subquery # 这里也可使用label取个别名,固然我这里取得仍是anime ygyz = session.query(Girl.anime.label("anime"), Girl.age).filter(Girl.name == "雨宫优子").subquery() # 这里的ygyz.c的c代指的是column,是一个简写 res = session.query(Girl).filter(Girl.anime == ygyz.c.anime, Girl.age == ygyz.c.age) print(res) ''' SELECT girls.id AS girls_id, girls.name AS girls_name, girls.anime AS girls_anime, girls.age AS girls_age FROM girls, (SELECT girls.anime AS anime, girls.age AS age FROM girls WHERE girls.name = %(name_1)s) AS anon_1 WHERE girls.anime = anon_1.anime AND girls.age = anon_1.age 能够看到除了起了一些名字以外,SQLAlchemy生成的sql语句与咱们以前写的几乎相似 ''' print(res.all()) ''' [雨宫优子--悠久之翼--16, 宫村宫子--悠久之翼--16] '''
这个插件首先要安装,直接pip install flask-sqlalchemy便可api
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" db_url = f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}" # 这个配置不直接与咱们的SQLAlchemy这个类发生关系,而是要添加到app.config里面,这一步是少不了的 # 至于这里的key,做者规定就是这么写的 app.config["SQLALCHEMY_DATABASE_URI"] = db_url # 而且还要加上这一段,否则会弹出警告 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # 接收一个app,今后db便具备了app的功能 db = SQLAlchemy(app) # 创建模型,确定要继承,那么继承谁的,继承自db.Module,至关于以前的Base。这里操做简化了,不须要咱们去建立了 class User(db.Model): __tablename__ = "user" # 能够看到,以前须要导入的统统不须要导入了,都在db下面。不过本质上调用的仍是sqlalchemy模块里的类。 id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), nullable=False) class Article(db.Model): __tablename__ = "article" id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(50), nullable=False) uid = db.Column(db.Integer, db.ForeignKey("user.id")) authror = db.relationship("User", backref="articles") # 因此咱们发现这和SQLAlchemy框架中的使用方法基本上是一致的,只不过咱们在SQLAlchemy中须要导入的,如今所有能够经过db来访问 # 那么如何映射到数据库里面呢?这里也不须要Base.metadata了,直接使用db便可。 db.drop_all() db.create_all()
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" db_url = f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}" # 这个配置不直接与咱们的SQLAlchemy这个类发生关系,而是要添加到app.config里面,这一步是少不了的 # 至于这里的key,做者规定就是这么写的 app.config["SQLALCHEMY_DATABASE_URI"] = db_url # 而且还要加上这一段,否则会弹出警告 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # 接收一个app,今后db便具备了app的功能 db = SQLAlchemy(app) # 创建模型,确定要继承,那么继承谁的,继承自db.Module,至关于以前的Base。这里操做简化了,不须要咱们去建立了 class User(db.Model): __tablename__ = "user" # 能够看到,以前须要导入的统统不须要导入了,都在db下面。不过本质上调用的仍是sqlalchemy模块里的类。 id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), nullable=False) class Article(db.Model): __tablename__ = "article" id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(50), nullable=False) uid = db.Column(db.Integer, db.ForeignKey("user.id")) author = db.relationship("User", backref="articles") # 因此咱们发现这和SQLAlchemy框架中的使用方法基本上是一致的,只不过咱们在SQLAlchemy中须要导入的,如今所有能够经过db来访问 # # 那么如何映射到数据库里面呢?这里也不须要Base.metadata了,直接使用db便可。 # db.drop_all() # db.create_all() # 下面添加数据 user = User(name="guido") article = Article(title="python之父谈python的将来") user.articles.append(article) db.session.add(user) ''' 或者 article.author = user db.session.add(article) ''' db.session.commit() # 跟咱们以前使用SQLAlchemy的流程基本一致
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" db_url = f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}" # 这个配置不直接与咱们的SQLAlchemy这个类发生关系,而是要添加到app.config里面,这一步是少不了的 # 至于这里的key,做者规定就是这么写的 app.config["SQLALCHEMY_DATABASE_URI"] = db_url # 而且还要加上这一段,否则会弹出警告 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # 接收一个app,今后db便具备了app的功能 db = SQLAlchemy(app) # 创建模型,确定要继承,那么继承谁的,继承自db.Module,至关于以前的Base。这里操做简化了,不须要咱们去建立了 class User(db.Model): __tablename__ = "user" # 能够看到,以前须要导入的统统不须要导入了,都在db下面。不过本质上调用的仍是sqlalchemy模块里的类。 id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), nullable=False) def __repr__(self): return f"{self.name}" class Article(db.Model): __tablename__ = "article" id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(50), nullable=False) uid = db.Column(db.Integer, db.ForeignKey("user.id")) author = db.relationship("User", backref="articles") def __repr__(self): return f"{self.tit }" # 如何查找数据呢? # 首先咱们能够想到db.session.query(User),这毫无疑问是能够的,可是咱们的模型继承了db.Model,那么咱们有更简单的方法 # 直接使用User.query便可,就等价于db.session.query(User) users = User.query.all() print(users) # [guido] ''' 排序:User.query.order_by(User.id.desc()).all() 过滤:User.query.filter(User.id == 1).all() 修改:User.query.filter(User.id == 1).first().name == "guido van rossum" 删除:删除的话仍是要依赖db.session()的,找到user,db.session.delete(user) ''' # 另外忘记提了,若是没有指定表名,也就是__tablename__,那么默认会将模型的名字转成小写当成表名。 ''' User-->user 但若是是驼峰命名法,UserModel-->user_model 可是不推荐这样使用,仍是显示的指定比较好,也符合python之禅,明言胜于暗喻。 '''
这是个人项目结构,一个文件夹,里面一个py文件ruby
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine, func from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" engine = create_engine(f"{dialect}+{driver}://{username}:{password}@{hostname}:{port}/{database}") Base = declarative_base(engine) class People(Base): __tablename__ = "People" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(20), nullable=False) # 不可为空 age = Column(Integer, nullable=False) def __repr__(self): return f"{self.name}--{self.age}"
能够看出,这和Django很是相似。若是之后修改模型,那么重复4和5
经常使用命令:
init:建立一个alembic仓库
revision:建立一个新的版本文件
--autogenerate:自动将当前模型的修改,生成迁移脚本
-m:本次迁移作了哪些修改,用户能够指定这个参数,方便回顾
upgrade:将指定版本的迁移文件映射到数据库中,会执行版本文件中的upgrade函数。若是有多个迁移脚本没有被映射到数据库中,那么会执行多个迁移脚本
[head]:表明最新的迁移脚本的版本号
downgrade:降级,咱们每个迁移文件都有一个版本号,若是想退回之前的版本,直接使用alembic downgrade version_id
heads:展现head指向的脚本文件
history:列出全部的迁移版本及其信息
current:展现当前数据库的版本号
经典错误:
FAILED:Target database is not up to date。缘由:主要是heads和current不相同。current落后于heads的版本。解决办法:将current移动到head上,alembic upgrade head
FAILED:can’t locate revision identified by “78ds75ds7s”。缘由:数据库中村的版本号不在迁移脚本文件中。解决办法:删除数据库中alembic_version表的数据,而后从新执行alembic upgrade head
执行upgrade head 时报某个表已经存在的错误。解决办法:1.删除version中全部的迁移文件的代码,修改迁移脚本中建立表的代码
从新建一个项目
hostname = "localhost" port = 3306 database = "satori" username = "root" password = "zgghyys123" dialect = "mysql" driver = "pymysql" SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{username}:{password}@{hostname}:{port}/{database}"
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) @app.route("/index") def hello(): return "hello world" class User(db.Model): __tablename__ = "user" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(50), nullable=False) if __name__ == '__main__': app.run()
# A generic, single database configuration. [alembic] # path to migration scripts script_location = alembic # template used to generate migration files # file_template = %%(rev)s_%%(slug)s # timezone to use when rendering the date # within the migration file as well as the filename. # string value is passed to dateutil.tz.gettz() # leave blank for localtime # timezone = # max length of characters to apply to the # "slug" field #truncate_slug_length = 40 # set to 'true' to run the environment during # the 'revision' command, regardless of autogenerate # revision_environment = false # set to 'true' to allow .pyc and .pyo files without # a source .py file to be detected as revisions in the # versions/ directory # sourceless = false # version location specification; this defaults # to alembic/versions. When using multiple version # directories, initial revisions must be specified with --version-path # version_locations = %(here)s/bar %(here)s/bat alembic/versions # the output encoding used when revision files # are written from script.py.mako # output_encoding = utf-8 sqlalchemy.url = mysql+pymysql://root:zgghyys123@localhost:3306/satori # Logging configuration [loggers] keys = root,sqlalchemy,alembic [handlers] keys = console [formatters] keys = generic [logger_root] level = WARN handlers = console qualname = [logger_sqlalchemy] level = WARN handlers = qualname = sqlalchemy.engine [logger_alembic] level = INFO handlers = qualname = alembic [handler_console] class = StreamHandler args = (sys.stderr,) level = NOTSET formatter = generic [formatter_generic] format = %(levelname)-5.5s [%(name)s] %(message)s datefmt = %H:%M:%S
from __future__ import with_statement from alembic import context from sqlalchemy import engine_from_config, pool from logging.config import fileConfig import sys, os sys.path.append(os.path.dirname(os.path.dirname(__file__))) import start # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config # Interpret the config file for Python logging. # This line sets up loggers basically. fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata target_metadata = start.db.metadata # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option") # ... etc. def run_migrations_offline(): """Run migrations in 'offline' mode. This configures the context with just a URL and not an Engine, though an Engine is acceptable here as well. By skipping the Engine creation we don't even need a DBAPI to be available. Calls to context.execute() here emit the given string to the script output. """ url = config.get_main_option("sqlalchemy.url") context.configure( url=url, target_metadata=target_metadata, literal_binds=True) with context.begin_transaction(): context.run_migrations() def run_migrations_online(): """Run migrations in 'online' mode. In this scenario we need to create an Engine and associate a connection with the context. """ connectable = engine_from_config( config.get_section(config.config_ini_section), prefix='sqlalchemy.', poolclass=pool.NullPool) with connectable.connect() as connection: context.configure( connection=connection, target_metadata=target_metadata ) with context.begin_transaction(): context.run_migrations() if context.is_offline_mode(): run_migrations_offline() else: run_migrations_online()
这个多了一个manage.py,能够类比Django,若是咱们把全部东西都写在一个py文件里面,会很是的凌乱。那这个manage.py是干什么的呢?可让咱们经过命令行来工做
start.py
from flask import Flask app = Flask(__name__) @app.route("/index") def index(): return "hello satori" if __name__ == '__main__': manager.run() # 注意这里是manager.run(),不是app.run()
manage.py
from flask_script import Manager from start import app manager = Manager(app) @manager.command def hello(): print("你好啊") if __name__ == '__main__': app.run()
from flask_script import Manager from start import app manager = Manager(app) @manager.command def hello(): return "你好啊" @manager.option("--name", dest="username") @manager.option("--age", dest="age") def foo(username, age): # 相似于python里的optparse,能够见个人python经常使用模块,里面有介绍 print(f"name={username}, age={age}") if __name__ == '__main__': manager.run()
不传参,使用command,传参使用option
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) class BackendUser(db.Model): __tablename__ = "backend_user" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(50), nullable=False) email = db.Column(db.String(50), nullable=False) # alembic很强大,但这里就不用了,直接使用create_all db.create_all() @app.route("/index") def index(): return "hello satori" if __name__ == '__main__': app.run()
from flask_script import Manager from start import app, BackendUser, db manager = Manager(app) @manager.command def hello(): return "你好啊" @manager.option("--name", dest="username") @manager.option("--email", dest="email") def add_user(username, email): user = BackendUser(username=username, email=email) db.session.add(user) db.session.commit() if __name__ == '__main__': manager.run()
之后就能够经过终端来添加了
在实际的数据库开发中,常常会出现数据表修改的行为。通常咱们不会手动修改数据库,而是去修改orm模型,而后再把模型映射到数据库中。这个时候若是能有一个工具专门作这件事情就很是好了,而flask-migrate就是用来干这个的。flask-migrate是基于alembic的一个封装,并集成到flask当中,而全部的操做都是alembic作的,它能跟踪模型的变化,并将模型映射到数据库中。
from flask_migrate import Migrate, MigrateCommand
manager = Manager(app, db) # 绑定app和db到flask_migrate
manager.add_command("db", MigrateCommand) # 添加Migrate的全部子命令到db下
1.初始化一个环境:python manage.py db init
2.自动检测模型,生成迁移脚本,python manage.py db migrate
3.将迁移脚本映射到数据库中,python manage.py db upgrade