zoukankan      html  css  js  c++  java
  • SqlAlchemy学习笔记

    前言

      SqlAlchemy 是在python中最有名的ORM(Objet Relational Mapping)框架,主要的任务是把关系数据库的表结构映射到python中的额对象。

      以前python通过原生的sql访问操作数据库,那种方式很繁琐,且没有安全感,现在通过ORM这个壳来访问操作数据库,这个壳具有python的style,壳里面包裹着sql。这样就大大方便了python使用者。

      Alembic是SQLAlchemy数据库迁移工具,由SQLAlchemy作者所创建,是对后台SQLAIchemy数据库执行迁移的事实上的标准工具。换句话说,Alembic可以对SQLAIchemy数据库进行版本控制(类似于git)。

     创建模型类

     1 from sqlalchemy import create_engine,Column,Integer,String
     2 from sqlalchemy.ext.declarative import declarative_base
     3 
     4 # HOSTNAME = '127.0.0.1'
     5 # PORT = '3306'
     6 # DATABASE = 'first_sqlalchemy'
     7 # USERNAME = 'ROOT'
     8 # PASSWORD = '123456'
     9 
    10 engine = create_engine("mysql+pymysql://root:123456@127.0.0.1/first_sqlalchemy?charset=utf8")
    11 BO = declarative_base(engine)
    12 # 1、用declarative_base创建一个ORM基类;
    13 # 2、创建一个ORM模型类,继承自sqlalchemy提供的基类;类中创建属性,跟表中的字段一一映射,
    14 # 这些属性必须是sqlalchemy给我们提供好的数据类型
    15 class Person(BO):
    16     __tablename__ = 'Person'
    17     id = Column(Integer,primary_key=True,autoincrement=True)
    18     name = Column(String(50))
    19     age = Column(Integer)
    20 # 3、将建好的ORM模型类映射到数据库中;
    21 BO.metadata.create_all()

    增删改查

     1 #encoding: utf-8
     2 
     3 from sqlalchemy import create_engine,Column,Integer,String
     4 from sqlalchemy.ext.declarative import declarative_base
     5 from sqlalchemy.orm import sessionmaker
     6 
     7 HOSTNAME = '127.0.0.1'
     8 PORT = '3306'
     9 DATABASE = 'first_sqlalchemy'
    10 USERNAME = 'root'
    11 PASSWORD = '123456'
    12 
    13 # dialect+driver://username:password@host:port/database
    14 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class Person(Base):
    20     __tablename__ = 'person'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     name = Column(String(50))
    23     age = Column(Integer)
    24     country = Column(String(50))
    25     def __str__(self):
    26         return "<Person(name:%s,age:%s,country:%s)>" % (self.name,self.age,self.country)
    27 
    28 
    29 Base.metadata.drop_all()
    30 Base.metadata.create_all()
    31 
    32 #
    33 def add_data():
    34     p1 = Person(name='刘亦菲',age=22,country='America')
    35     p2 = Person(name='李沁',age=20,country='China')
    36     p3 = Person(name='高圆圆',age=23,country='China')
    37     session.add_all([p1,p2,p3]) # 添加多条数据
    38     session.commit() # 提交
    39 
    40 #
    41 def search_data():
    42     # all_person = session.query(Person).all()  # 使用all方法获取结果集中的所有数据
    43     # for p in all_person:
    44     #     print(p)
    45     # all_person = session.query(Person).filter_by(name='wy').all() #过滤器,条件查询
    46     # for x in all_person:
    47     #     print(x)
    48     # all_person = session.query(Person).filter(Person.name=='wy').all()
    49     # for x in all_person:
    50     #     print(x)
    51     person = session.query(Person).first() # 使用first方法获取结果集中的第一条数据
    52     print(person)
    53 #
    54 
    55 def update_data():
    56     person = session.query(Person).first()
    57     person.name = 'wangyi'
    58     session.commit()
    59 
    60 #
    61 def delete_data():
    62     person = session.query(Person).first()
    63     session.delete(person)
    64     session.commit()
    65 
    66 if __name__ == '__main__':
    67 
    68     # add_data()
    69     search_data()
    70     # update_data()
    71     # delete_data()

    条件查询

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_
     3 from sqlalchemy.dialects.mysql import LONGTEXT
     4 from sqlalchemy.ext.declarative import declarative_base
     5 from sqlalchemy.orm import sessionmaker
     6 # 在Python3中才有这个enum模块,在python2中没有
     7 import enum
     8 from datetime import datetime
     9 import random
    10 HOSTNAME = '127.0.0.1'
    11 PORT = '3306'
    12 DATABASE = 'first_sqlalchemy'
    13 USERNAME = 'root'
    14 PASSWORD = '123456'
    15 # dialect+driver://username:password@host:port/database
    16 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    17 engine = create_engine(DB_URI)
    18 Base = declarative_base(engine)
    19 session = sessionmaker(engine)()
    20 
    21 class Article(Base):
    22     __tablename__ = 'article'
    23     id = Column(Integer,primary_key=True,autoincrement=True)
    24     title = Column(String(50),nullable=False)
    25     price = Column(Float,nullable=False)
    26     content = Column(Text)
    27 
    28     def __repr__(self):
    29         return "<Article(title:%s)>" % self.title
    30 
    31 # session.query(Article).filter(Article.id == 1)
    32 # session.query(Article).filter_by(id = 1)
    33 
    34 # 1. equal
    35 # article = session.query(Article).filter(Article.title == "title0").first()
    36 # print(article)
    37 
    38 # 2. not equal
    39 # articles = session.query(Article).filter(Article.title != 'title0').all()
    40 # print(articles)
    41 
    42 # 3. like & ilike(不区分大小写)
    43 # articles = session.query(Article).filter(Article.title.ilike('title%')).all()
    44 # print(articles)
    45 
    46 # 4. in:
    47 # for xxx in xxx
    48 # def _in()
    49 # articles = session.query(Article).filter(Article.title.in_(['title1','title2'])).all()
    50 # print(articles)
    51 
    52 # not in
    53 # articles = session.query(Article).filter(~Article.title.in_(['title1','title2'])).all()
    54 # print(articles)
    55 # articles = session.query(Article).filter(Article.title.notin_(['title1','title2'])).all()
    56 # print(articles)
    57 
    58 # is null
    59 # articles = session.query(Article).filter(Article.content==None).all()
    60 # print(articles)
    61 
    62 # is not null
    63 # articles = session.query(Article).filter(Article.content!=None).all()
    64 # print(articles)
    65 
    66 # and
    67 # articles = session.query(Article).filter(Article.title=='abc',Article.content=='abc').all()
    68 # print(articles)
    69 
    70 # or
    71 articles = session.query(Article).filter(or_(Article.title=='abc',Article.content=='abc'))
    72 print(articles)
    73 
    74 # 以上不写all()会直接打印底层原生的sql语句

    外键

    外键构建和四种约束

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker
     5 
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23 
    24 class Article(Base):
    25     __tablename__ = 'article'
    26     id = Column(Integer,primary_key=True,autoincrement=True)
    27     title = Column(String(50),nullable=False)
    28     content = Column(Text,nullable=False)
    29 
    30     uid = Column(Integer,ForeignKey('user.id', ondelete="CASCADE"))  # 这里uid的数据类型要和user表中的id的数据类型一致
    31 """
    32 外键约束:
    33 1、RESTRICT:默认ondelete=RESTRICT,此时删除主表的被关联数据,会报错,如:
    34 ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint
    35 fails (`first_sqlalchemy`.`article`, CONSTRAINT `article_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`))
    36 2、NO ACTION:在mysql中等同于RESTRICT;
    37 3、CASCADE:级联删除
    38 4、SET NULL:主表数据删除后副表置空。此时从表的外键nullable不能为False。
    39 """
    40 
    41 Base.metadata.drop_all()
    42 Base.metadata.create_all()
    43 
    44 user1 = User(username='刘亦菲')
    45 user2 = User(username='杨幂')
    46 session.add_all([user1,user2])
    47 session.commit()
    48 
    49 article1 = Article(title='hello world',content='这是内容',uid=1)
    50 session.add(article1)
    51 session.commit()

    ORM层外键关联

    实现迅速在另一个表中找到相关联的数据:

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship
     5 
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23     # articles = relationship("Article")
    24     def __repr__(self):
    25         return "<user{id:%s,username:%s}>"%(self.id,self.username)
    26 
    27 class Article(Base):
    28     __tablename__ = 'article'
    29     id = Column(Integer,primary_key=True,autoincrement=True)
    30     title = Column(String(50),nullable=False)
    31     content = Column(Text,nullable=False)
    32     uid = Column(Integer,ForeignKey('user.id'))
    33     author = relationship("User",backref="articles")   # 这两个可以通过backref反转合二为一
    34     def __repr__(self):
    35         return "<article{id:%s,title:%s,content:%s,uid:%s}>"%(self.id,self.title,self.content,self.uid)
    36 
    37 Base.metadata.drop_all()
    38 Base.metadata.create_all()
    39 
    40 user1 = User(username='刘亦菲')
    41 user2 = User(username='杨幂')
    42 session.add_all([user1,user2])
    43 session.commit()
    44 
    45 article1 = Article(title='文章1',content='内容1',uid=1)
    46 article2 = Article(title='文章2',content='内容2',uid=2)
    47 article3 = Article(title='文章3',content='内容3',uid=2)
    48 session.add_all([article1,article2,article3])
    49 session.commit()
    50 
    51 # 对于都有数据的两张表user和article,正常情况下,要拿到第一篇article对应的username,通过如下方式:
    52 # article = session.query(Article).first()
    53 # uid = article.uid
    54 # user = session.query(User).get(uid)
    55 # print(user)
    56 
    57 
    58 # 现在,通过ORM层外键实现:在Article模型中添加 author = relationship("User")
    59 article = session.query(Article).filter(Article.title=="文章3").first()
    60 print(article.author.username) # 杨幂
    61 
    62 
    63 # 一个用户可以写多篇文章,一对多的关系,那么怎么拿到一个用户的所有文章的标题呢?同样,在User中添加 articles = relationship("Article")
    64 
    65 user = session.query(User).filter(User.username=="杨幂").first()
    66 for i in range(len(user.articles)):
    67     print(user.articles[i].title)

    这两个relationship可以通过backref反转合二为一: author = relationship("User",backref="articles"

    ORM层面添加关联数据

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship
     5 
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23     # articles = relationship("Article")
    24     def __repr__(self):
    25         return "<user{id:%s,username:%s}>"%(self.id,self.username)
    26 
    27 class Article(Base):
    28     __tablename__ = 'article'
    29     id = Column(Integer,primary_key=True,autoincrement=True)
    30     title = Column(String(50),nullable=False)
    31     content = Column(Text,nullable=False)
    32     uid = Column(Integer,ForeignKey('user.id'))
    33     author = relationship("User",backref="articles")
    34     def __repr__(self):
    35         return "<article{id:%s,title:%s,content:%s,uid:%s}>"%(self.id,self.title,self.content,self.uid)
    36 
    37 Base.metadata.drop_all()
    38 Base.metadata.create_all()
    39 #
    40 user1 = User(username='刘亦菲')
    41 user2 = User(username='杨幂')
    42 session.add_all([user1,user2])
    43 session.commit()
    44 
    45 article1 = Article(title='文章1',content='内容1',uid=1)
    46 article2 = Article(title='文章2',content='内容2',uid=2)
    47 article3 = Article(title='文章3',content='内容3',uid=2)
    48 session.add_all([article1,article2,article3])
    49 session.commit()
    50 
    51 
    52 # ORM层面给用户添加文章:
    53 article4 = Article(title='文章4',content='内容4')
    54 article5 = Article(title='文章5',content='内容5')
    55 user = User(username='高圆圆') # 顺着id直接新增,可以重名
    56 user.articles.append(article4)
    57 user.articles.append(article5)
    58 session.add(user)
    59 session.commit()
    60 
    61 #ORM层面给文章指定作者
    62 article6 = Article(title='文章6',content='内容6')
    63 user = User(username='李沁')
    64 article6.author = user
    65 session.add(article6)
    66 session.commit()

    添加结果:

    这有个疑问,为什么上面代码56行是append,而64行是赋值?

    这是因为建立外键关联后,默认两张表是一对多的关系,主1从多。具体如下:

     一对一

    将用户的不常用的静态字段如毕业学校,手机号,住址等放到单独的表里,外键关联选择一对一:

    这里一对一的关键:

    user = relationship("User",backref=backref("school",uselist=False))

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship,backref
     5 
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23     # articles = relationship("Article")
    24     def __repr__(self):
    25         return "<user{id:%s,username:%s}>"%(self.id,self.username)
    26 
    27 class Uschool(Base):
    28     '''新增毕业学校表'''
    29     __tablename__ = 'uschool'
    30     id = Column(Integer, primary_key=True, autoincrement=True)
    31     school = Column(String(50),nullable=False)
    32     uid = Column(Integer,ForeignKey("user.id"))
    33 
    34     user = relationship("User",backref=backref("school",uselist=False)) # 要导入backref
    35     # uselist=False 就表明主从表是一对一的关系
    36 
    37 class Article(Base):
    38     __tablename__ = 'article'
    39     id = Column(Integer,primary_key=True,autoincrement=True)
    40     title = Column(String(50),nullable=False)
    41     content = Column(Text,nullable=False)
    42     uid = Column(Integer,ForeignKey('user.id'))
    43     author = relationship("User",backref="articles")
    44     def __repr__(self):
    45         return "<article{id:%s,title:%s,content:%s,uid:%s}>"%(self.id,self.title,self.content,self.uid)
    46 
    47 Base.metadata.drop_all()
    48 Base.metadata.create_all()
    49 
    50 user1 = User(username='刘亦菲')
    51 user2 = User(username='杨幂')
    52 session.add_all([user1,user2])
    53 session.commit()
    54 
    55 article1 = Article(title='文章1',content='内容1',uid=1)
    56 article2 = Article(title='文章2',content='内容2',uid=2)
    57 article3 = Article(title='文章3',content='内容3',uid=2)
    58 session.add_all([article1,article2,article3])
    59 session.commit()
    60 
    61 # ORM层面给用户添加文章:
    62 article4 = Article(title='文章4',content='内容4')
    63 article5 = Article(title='文章5',content='内容5')
    64 user = User(username='高圆圆')
    65 print(type(user.articles)) # <class 'sqlalchemy.orm.collections.InstrumentedList'>
    66 # 默认一对多,user.articles是列表类型
    67 user.articles.append(article4)
    68 user.articles.append(article5)
    69 for i in user.articles:
    70     print(i)
    71     # < article{id: None, title: 文章4, content: 内容4, uid: None} >
    72     # < article{id: None, title: 文章5, content: 内容5, uid: None} >
    73 
    74 # user.articles = article4 #报错 TypeError: Incompatible collection type: Article is not list-like
    75 session.add(user)
    76 session.commit()
    77 #ORM层面给文章指定作者
    78 article6 = Article(title='文章6',content='内容6')
    79 user = User(username='李沁')
    80 print(type(article6.author)) # <class 'NoneType'>
    81 article6.author = user
    82 session.add(article6)
    83 session.commit()
    84 
    85 #这里一对一是假设一个用户只能对应唯一的学校,或许手机号的例子更合适
    86 uschool01 = Uschool(school="清华")
    87 uschool02 = Uschool(school="北大")
    88 user1 = User(username="余承东")
    89 user2 = User(username="李彦宏")
    90 user1.school = uschool01
    91 user2.school = uschool02
    92 session.add(uschool01)
    93 session.add(uschool02)
    94 session.commit(

    ORM层面删除数据

    1 user = session.query(User).first()
    2 session.delete(user)
    3 session.commit()

    将user表的第一个用户刘亦菲删除了,但是article表的对应刘亦菲的uid变为NULL。

    正常情况下载sql层面上是不能删除有外键约束的表数据的,但是在ORM层面上会无视约束,会先把uid置为NULL,然后再去删除主表数据。

    此时要想数据不被ORM删除,只需将从表的uid字段置为nullable=False。非空之后ORM也删不了了。

    当然,如果只删除从表那就没主表什么事了。但如果想删除从表的同时,将主表也一并删除,怎么实现?

    在relationship()中有个参数cascade,可以实现主从表一并删除。

    relationship中的cascade

    在SqlAlchemy中,只要将一个数据添加到sessioon中,和他相关联的数据都可以一起存入到数据库中了。这些是怎么设置的呢?其实是通过relationship的中的一个关键字cascade实现的。如:

    1、save-update:默认选项。在添加一条数据的时候会将其他相关联的数据添加进去;

    2、delete:删除某个模型中数据的时候,也会删除relationship中关联模型的数据;

    3、delete_orphan:写在主表的relationship中,当副表的uid置空时,副表的数据会被删除。只能用在一对多。还需要在副表的relationship中添加single_parent=True参数。

    4、merge:默认选项。当在使用session.merge,合并一个对象的时候,会将使用了relationship相关联的对象也进行merge操作。

    5、expunge:移除操作的时候,会将相关联的对象也进行移除。这个操作只是从session中移除,并不会真正的从数据库中删除。

    6、all:是对save-update, merge, refresh-expire, expunge, delete几种的缩写。

    排序

    对字段进行正序或倒序排序,有三种方式去实现:

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship,backref
     5 from datetime import datetime
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23 
    24 class Article(Base):
    25     __tablename__ = 'article'
    26     id = Column(Integer,primary_key=True,autoincrement=True)
    27     title = Column(String(50),nullable=False)
    28     create_time = Column(DateTime,nullable=False,default=datetime.now)
    29     uid = Column(Integer,ForeignKey('user.id'))
    30     
    31     author = relationship("User",backref=backref("articles",order_by=create_time.desc()))
    32 
    33     # __mapper_args__ = {
    34     #     "order_by": create_time
    35     #     # "order_by": create_time.desc()
    36     # }
    37 
    38     def __repr__(self):
    39         return "<article{id:%s,title:%s,create_time:%s}>"%(self.id,self.title,self.create_time)
    40 # Base.metadata.drop_all()
    41 # Base.metadata.create_all()
    42 # article1 = Article(title="文章1")
    43 # article2 = Article(title="文章2")
    44 # article3 = Article(title="文章3")
    45 # session.add_all([article3,])
    46 # session.commit()
    47 
    48 # 1、方法一
    49 # 正序
    50 # article = session.query(Article).order_by('create_time').all()
    51 article = session.query(Article).order_by(Article.create_time).all()
    52 # 倒序
    53 article = session.query(Article).order_by(Article.create_time.desc()).all()
    54 
    55 # 方法二:直接在模型中通过__mapper_args__指定某个字段的排序方式
    56 # 方法三:直接在relationship()中指定排序方式。
    57 print(article)

    Limit、offset和slice切片

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship,backref
     5 from datetime import datetime
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 
    20 class Article1(Base):
    21     __tablename__ = 'article'
    22     id = Column(Integer,primary_key=True,autoincrement=True)
    23     title = Column(String(50),nullable=False)
    24     create_time = Column(DateTime,nullable=False,default=datetime.now)
    25 
    26 
    27     def __repr__(self):
    28         return "<article{id:%s,title:%s,create_time:%s}>"%(self.id,self.title,self.create_time)
    29 # Base.metadata.drop_all()
    30 # Base.metadata.create_all()
    31 
    32 def add_data():
    33     import time
    34     for i in range(1,11):
    35         article = Article1(title = "文章%s"%i)
    36         session.add(article)
    37         time.sleep(1)
    38         session.commit()
    39 # add_data()
    40 # 倒序取第7,第6两篇文章
    41 articles1 = session.query(Article1).order_by(Article1.create_time.desc()).offset(3).limit(2).all()
    42 # 切片取第3到第5篇文章,注意从0开始
    43 articles2 = session.query(Article1).slice(2,5).all()
    44 # 与上面等价
    45 articles3 = session.query(Article1)[2:5]
    46 
    47 # print(articles1)
    48 # [<article{id:7,title:文章7,create_time:2020-04-14 01:28:22}>, <article{id:6,title:文章6,create_time:2020-04-14 01:28:21}>]

    懒加载

    在一对多,或者多对多的时候,如果想要获取多的这一部分的数据的时候,往往能通过一个属性就可以全部获取了。比如有一个作者,想要或者这个作者的所有文章,那么可以通过user.articles就可以获取所有的。但有时候我们不想获取所有的数据,比如只想获取这个作者今天发表的文章,那么这时候我们可以给relationship传递一个lazy='dynamic',以后通过user.articles获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。
    通过`lazy='dynamic',获取出来的多的那一部分的数据,就是一个’AppenderQuery’对象了。这种对象既可以添加新数据,也可以跟'Query'一样,可以再进行一层过滤。
    总而言之:如果你在获取数据的时候,想要对多的那一边的数据再进行一层过滤,那么这时候就可以考虑使用 lazy='dynamic'。
    lazy可用的选项:
    1. 'select':这个是默认选项。还是拿'user.articles'的例子来讲。如果你没有访问'user.articles'这个属性,那么sqlalchemy就不会从数据库中查找文章。一旦你访问了这个属性,那么sqlalchemy就会立马从数据库中查找所有的文章,并把查找出来的数据组装成一个列表返回。这也是懒加载。
    2. 'dynamic':就是在访问'user.articles'的时候返回回来的不是一个列表,而是'AppenderQuery'对象。

     注意:lazy要写在一对多的情况中"多"的那个relationship()里。

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
     3 from sqlalchemy.dialects.mysql import LONGTEXT
     4 from sqlalchemy.ext.declarative import declarative_base
     5 from sqlalchemy.orm import sessionmaker,relationship,backref
     6 from datetime import datetime
     7 import time
     8 import random
     9 HOSTNAME = '127.0.0.1'
    10 PORT = '3306'
    11 DATABASE = 'first_sqlalchemy'
    12 USERNAME = 'root'
    13 PASSWORD = '123456'
    14 # dialect+driver://username:password@host:port/database
    15 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    16 engine = create_engine(DB_URI)
    17 Base = declarative_base(engine)
    18 session = sessionmaker(engine)()
    19 
    20 
    21 class User(Base):
    22     __tablename__ = 'user1'
    23     id = Column(Integer, primary_key=True, autoincrement=True)
    24     username = Column(String(50),nullable=False)
    25 
    26 
    27 class Article(Base):
    28     __tablename__ = 'article1'
    29     id = Column(Integer, primary_key=True, autoincrement=True)
    30     title = Column(String(50), nullable=False)
    31     create_time = Column(DateTime,nullable=False,default=datetime.now)
    32     uid = Column(Integer,ForeignKey("user1.id"))
    33 
    34     author = relationship("User",backref=backref("articles",lazy="dynamic"))
    35 
    36     def __repr__(self):
    37         return "<Article(title:%s)>" % self.title
    38 
    39 
    40 
    41 def add_data():
    42     Base.metadata.drop_all()
    43     Base.metadata.create_all()
    44     user = User(username='wangyi')
    45     for i in range(1,21):
    46         article = Article(title="文章%s" %i)
    47         article.author = user
    48         session.add(article)
    49         time.sleep(1)
    50         session.commit()
    51 # add_data()
    52 
    53 user = session.query(User).first()
    54 # user.articles是一个Query对象。
    55 print(user.articles.filter(Article.id>10).order_by(Article.create_time.desc()).limit(2).all())
    56 # 可以继续追加数据进去
    57 article =Article(title='文章21')
    58 user.articles.append(article)
    59 session.commit()

    article1表:

    查询扩展

    group_by,having

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
     3 from sqlalchemy.dialects.mysql import LONGTEXT
     4 from sqlalchemy.ext.declarative import declarative_base
     5 from sqlalchemy.orm import sessionmaker,relationship,backref
     6 # 在Python3中才有这个enum模块,在python2中没有
     7 import enum
     8 from datetime import datetime
     9 import random
    10 HOSTNAME = '127.0.0.1'
    11 PORT = '3306'
    12 DATABASE = 'first_sqlalchemy'
    13 USERNAME = 'root'
    14 PASSWORD = '123456'
    15 # dialect+driver://username:password@host:port/database
    16 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    17 engine = create_engine(DB_URI)
    18 Base = declarative_base(engine)
    19 session = sessionmaker(engine)()
    20 
    21 class User(Base):
    22     __tablename__ = 'user2'
    23     id = Column(Integer,primary_key=True,autoincrement=True)
    24     username = Column(String(50),nullable=False)
    25     age = Column(Integer,default=0)
    26     gender = Column(Enum("male","female","secret"),default="male")
    27 
    28 def add_data():
    29     Base.metadata.drop_all()
    30     Base.metadata.create_all()
    31 
    32     user1 = User(username='刘德华',age=18,gender='female')
    33     user2 = User(username='洪金宝',age=17,gender='female')
    34     user3 = User(username="成龙",age=19,gender='female')
    35     user4 = User(username="周润发",age=22,gender='female')
    36     user5 = User(username="甄子丹",age=15,gender='female')
    37     user6 = User(username="张曼玉",age=16,gender='male')
    38     user7 = User(username="王祖贤",age=17,gender='male')
    39 
    40     session.add_all([user1,user2,user3,user4,user5,user6,user7])
    41     session.commit()
    42 
    43 # add_data()
    44 
    45 # 每个年龄的人数
    46 result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age<18).all()
    47 print(result)

    join

    假如有两张表:

     查询文章数最多的前两个用户的姓名、文章标题和具体文章数:

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy.orm import sessionmaker,relationship,backref
     5 from datetime import datetime
     6 HOSTNAME = '127.0.0.1'
     7 PORT = '3306'
     8 DATABASE = 'first_sqlalchemy'
     9 USERNAME = 'root'
    10 PASSWORD = '123456'
    11 
    12 # dialect+driver://username:password@host:port/database
    13 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    14 
    15 engine = create_engine(DB_URI)
    16 Base = declarative_base(engine)
    17 session = sessionmaker(engine)()
    18 
    19 class User(Base):
    20     __tablename__ = 'user3'
    21     id = Column(Integer,primary_key=True,autoincrement=True)
    22     username = Column(String(50),nullable=False)
    23 
    24 class Article(Base):
    25     __tablename__ = 'article3'
    26     id = Column(Integer,primary_key=True,autoincrement=True)
    27     title = Column(String(50),nullable=False)
    28     uid = Column(Integer,ForeignKey('user3.id'))
    29     author = relationship("User",backref = "articles")
    30 
    31     def __repr__(self):
    32         return "<article{id:%s,title:%s}>"%(self.id,self.title)
    33 # Base.metadata.drop_all()
    34 # Base.metadata.create_all()
    35 # user1 = User(username='wangyi')
    36 # user2 = User(username='wenwen')
    37 # user3 = User(username='yanyan')
    38 # user4 = User(username='xian')
    39 # article1 = Article(title="文章1")
    40 # article2 = Article(title="文章2")
    41 # article3 = Article(title="文章3")
    42 # article4 = Article(title="文章4")
    43 # article5 = Article(title="文章5")
    44 # article6 = Article(title="文章6")
    45 # user1.articles.append(article1)
    46 # user1.articles.append(article2)
    47 # user2.articles.append(article3)
    48 # user2.articles.append(article4)
    49 # user2.articles.append(article5)
    50 # user3.articles.append(article6)
    51 #
    52 #
    53 # session.add(user1)
    54 # session.add(user2)
    55 # session.add(user3)
    56 # session.add(user4)
    57 # session.commit()
    58 
    59 # 查询文章数最多的前两个用户的姓名和文章标题:
    60 result = session.query(User.username,func.group_concat(Article.title),func.count(Article.title)).outerjoin(Article,User.id==Article.uid).group_by(User.username).order_by(func.count(Article.title).desc()).limit(2).all()
    61 print(result)
    62 
    63 """
    64 sql语句:
    65 SELECT user3.username AS user3_username, group_concat(article3.title) AS group_concat_1, count(article3.title) AS count_1 
    66 FROM user3 LEFT OUTER JOIN article3 ON user3.id = article3.uid GROUP BY user3.username ORDER BY count(article3.title) DESC 
    67  LIMIT %(param_1)s
    68 """

    子查询subquery

    子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点。不用写多个sql语句就可以实现一些复杂的查询。那么在sqlalchemy中,要实现一个子查询,应该使用以下几个步骤:
    1. 将子查询按照传统的方式写好查询代码,然后在`query`对象后面执行`subquery`方法,将这个查询变成一个子查询。
    2. 在子查询中,将以后需要用到的字段通过`label`方法,取个别名。
    3. 在父查询中,如果想要使用子查询的字段,那么可以通过子查询的返回值上的`c`属性拿到。

     1 #encoding: utf-8
     2 from sqlalchemy import create_engine,Column,Integer,Float,Boolean,DECIMAL,Enum,Date,DateTime,Time,String,Text,func,and_,or_,ForeignKey,Table
     3 from sqlalchemy.dialects.mysql import LONGTEXT
     4 from sqlalchemy.ext.declarative import declarative_base
     5 from sqlalchemy.orm import sessionmaker,relationship,backref
     6 # 在Python3中才有这个enum模块,在python2中没有
     7 import enum
     8 from datetime import datetime
     9 import random
    10 HOSTNAME = '127.0.0.1'
    11 PORT = '3306'
    12 DATABASE = 'first_sqlalchemy'
    13 USERNAME = 'root'
    14 PASSWORD = '123456'
    15 # dialect+driver://username:password@host:port/database
    16 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    17 
    18 engine = create_engine(DB_URI)
    19 Base = declarative_base(engine)
    20 session = sessionmaker(engine)()
    21 
    22 class User(Base):
    23     __tablename__ = 'user4'
    24     id = Column(Integer,primary_key=True,autoincrement=True)
    25     username = Column(String(50),nullable=False)
    26     city = Column(String(50),nullable=False)
    27     age =  Column(Integer,default=0)
    28 
    29     def __repr__(self):
    30         return "<User(username: %s)>" % self.username
    31 
    32 
    33 Base.metadata.drop_all()
    34 Base.metadata.create_all()
    35 
    36 user1 = User(username='李A',city="长沙",age=18)
    37 user2 = User(username='王B',city="长沙",age=18)
    38 user3 = User(username='赵C',city="北京",age=18)
    39 user4 = User(username='张D',city="长沙",age=20)
    40 
    41 session.add_all([user1,user2,user3,user4])
    42 session.commit()
    43 
    44 # 婚恋
    45 # 寻找和李A这个人在同一个城市,并且是同年龄的人
    46 # user = session.query(User).filter(User.username=='李A').first()
    47 # users = session.query(User).filter(User.city==user.city,User.age==user.age).all()
    48 # print(users)
    49 
    50 stmt = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='李A').subquery()
    51 result = session.query(User).filter(User.city==stmt.c.city,User.age==stmt.c.age).all()
    52 print(result)

    flask_sqlalchemy

    flask_sqlalchemy是对SqlAlchemy的封装,使得其更适合于flask框架的应用。

     1 from flask import Flask
     2 from flask_sqlalchemy import SQLAlchemy
     3 app = Flask(__name__)
     4 HOSTNAME = '127.0.0.1'
     5 PORT = '3306'
     6 DATABASE = 'flask_sqlalchemy_demo'
     7 USERNAME = 'root'
     8 PASSWORD = '123456'
     9 # dialect+driver://username:password@host:port/database
    10 DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE)
    11 app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
    12 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    13 db = SQLAlchemy(app)
    14 
    15 class User(db.Model):
    16     __tablename__ = 'user'
    17     # 这个表名不写则默认使用模型类的小写名作为表名,驼峰则用_分开,如 UserModel——> user_model
    18     id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    19     username = db.Column(db.String(50),nullable=False)
    20     def __repr__(self):
    21         return "<user(username:%s)>"%self.username
    22 
    23 class Article(db.Model):
    24     __tablename__ = 'article'
    25     id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    26     title = db.Column(db.String(50),nullable=False)
    27     uid = db.Column(db.Integer,db.ForeignKey('user.id'))
    28     author = db.relationship("User",backref = "articles")
    29 
    30 # db.drop_all()
    31 # db.create_all()
    32 def add_data():
    33 
    34     user1 = User(username="wangyi")
    35     user2 = User(username="wenwen")
    36     article1 = Article(title="文章1")
    37     article2 = Article(title="文章2")
    38     article1.author = user1
    39     article2.author = user2
    40     db.session.add(article1)
    41     db.session.add(article2)
    42     db.session.commit()
    43 # add_data()
    44 
    45 # 单表查询
    46 # users = User.query.order_by(User.id.desc()).all()
    47 # print(users)
    48 
    49 #
    50 # user = User.query.filter(User.username=='wenwen').first()
    51 # user.username = "yanyan"
    52 # db.session.commit()
    53 
    54 #
    55 # user = User.query.filter(User.username=='wenwen').first()
    56 # db.session.delete(user)
    57 # db.session.commit()
    58 
    59 @app.route('/')
    60 def hello_world():
    61     return 'Hello World!'
    62 
    63 
    64 if __name__ == '__main__':
    65     app.run()

  • 相关阅读:
    使用指针的误区之指针未初始化
    实验室react项目名词解释
    生活感悟之大学
    git 快速入门
    口才锻炼
    narcissus
    crest value &minimum
    factorial
    Str_turn
    array_x
  • 原文地址:https://www.cnblogs.com/wangyi0419/p/12688756.html
Copyright © 2011-2022 走看看