日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

第五章:Flask数据库操作

發布時間:2024/8/1 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第五章:Flask数据库操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第五章:Flask數據庫操作

1、SQLALchemy的介紹

SQLAlchemy 是 Python 中一個通過 ORM 操作數據庫的框架。

SQLAlchemy對象關系映射器提供了一種方法,用于將用戶定義的Python類與數據庫表相關聯,并將這些類(對象)的實例與其對應表中的行相關聯。它包括一個透明地同步對象及其相關行之間狀態的所有變化的系統,稱為工作單元,以及根據用戶定義的類及其定義的彼此之間的關系表達數據庫查詢的系統。

可以讓我們使用類和對象的方式操作數據庫,從而從繁瑣的 sql 語句中解脫出來。

ORM 就是 Object Relational Mapper 的簡寫,就是關系對象映射器的意思。

架構圖

安裝

先確保你已經安裝了以下軟件:

mysql:如果是在windows上,到官網下載。如果是ubuntu,通過命令sudo apt-get install mysql-server libmysqlclient-dev -yq進行下載安裝。
MySQLdb:MySQLdb是用Python來操作mysql的包,因此通過pip來安裝,命令如下:pip install mysql-python。如果您用的是Python 2.x,請安裝MySQLdb。

pymysql:pymysql是用Python來操作mysql的包,因此通過pip來安裝,命令如下:pip3 install pymysql。

SQLAlchemy:SQLAlchemy是一個數據庫的ORM框架,我們在后面會用到。安裝命令為:pip3 install SQLAlchemy。

連接數據庫

from sqlalchemy import create_engine # 數據庫的配置變量 HOSTNAME = '127.0.0.1' PORT = '3306' DATABASE = 'test' USERNAME = 'root' PASSWORD = '123123' DB_URI = 'mysql+mysqldb://{}:{}@{}?charset=utf8mb4:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE) # 創建數據庫引擎 engine = create_engine(DB_URI) #創建連接 with engine.connect() as con: rs = con.execute('SELECT 1') print rs.fetchone()

2、創建ORM映射

ORM:Object Relationship Mapping

創建一個類,一個類對應了一個數據庫中的一張表,類的數據屬性對應了表中的字段名,這個類稱為映射類。 根據映射類創建出一個一個的對象,每個對象對應了表中的一條實際的數據。

1、主動創建映射

使用Declarative系統映射的類是根據基類定義的,換句話說每個映射類需要繼承這個基類。我們使用 declarative_base() 函數可以創建這個基類,如下所示:

#1、創建基類 from sqlalchemy.ext.declarative import declarative_base engine = create_engine(DB_URI) Base = declarative_base(engine) #2、用這個`Base`類作為基類來寫自己的ORM類。要定義`__tablename__`類屬性,來指定這個模型映射到數據庫中的表名。 class Person(Base): __tablename__ ='person' #3. 創建屬性來映射到表中的字段,所有需要映射到表中的屬性都應該為Column類型: class Person(Base): __tablename__ ='person' #2.在這個ORM模型中創建一些屬性,來跟表中的字段進行 一一 映射。這些屬性必須是sqlalchemy給我們提供好的數據類型 id = Column(Integer,primary_key=True,autoincrement=True) name = Column(String(50)) age = Column(Integer) country = Column(String(50)) #4. 使用`Base.metadata.create_all()`來將模型映射到數據庫中。 Base.metadata.create_all() #5. 一旦使用`Base.metadata.create_all()`將模型映射到數據庫中后,即使改變了模型的字段,也不會重新映射了。

SQLAlchemy常用數據類型

  • Integer:整形,映射到數據庫中是int類型。
  • Float:浮點類型,映射到數據庫中是flfloat類型。他占據的32位。
  • Double:雙精度浮點類型,映射到數據庫中是double類型,占據64位 (SQLALCHEMY中沒有)。
  • String:可變字符類型,映射到數據庫中是varchar類型.
  • Boolean:布爾類型,映射到數據庫中的是tinyint類型。
  • DECIMAL:定點類型。是專門為了解決浮點類型精度丟失的問題的。在存儲錢相關的字段的時候建議大家都使用這個數據類型。并且這個類型使用的時候需要傳遞兩個參數,第一個參數是用來標記這個字段總能能存儲多少個數字,第二個參數表示小數點后有多少位。
  • Enum:枚舉類型。指定某個字段只能是枚舉中指定的幾個值,不能為其他值。在ORM模型中,使用Enum來作為枚舉。
  • Date:存儲時間,只能存儲年月日。映射到數據庫中是date類型。在Python代碼中,可以使用datetime.date 來指定。
  • DateTime:存儲時間,可以存儲年月日時分秒毫秒等。映射到數據庫中也是datetime類型。在Python代碼中,可以使用 datetime.datetime 來指定。
  • Time:存儲時間,可以存儲時分秒。映射到數據庫中也是time類型。在Python代碼中,可以使用datetime.time 來創建值。
  • Text:存儲長字符串。一般可以存儲6W多個字符。如果超出了這個范圍,可以使用LONGTEXT類型。映射到數據庫中就是text類型。
  • LONGTEXT:長文本類型,映射到數據庫中是longtext類型。
  • 注意:這個類型屬于Mysql方言里面的

    #定義一個枚舉類 class TagEnum(enum.Enum): python="PYHTON" flask="FLASK" django ="DJANGO" #創建一個ORM模型 說明基于sqlalchemy 映射到mysql數據庫的常用字段類型有哪些? Base = declarative_base(engine) class News(Base): __tablename__='news' id = Column(Integer,primary_key=True,autoincrement=True) price1 = Column(Float) #存儲數據時存在精度丟失問題 price2 = Column(DECIMAL(10,4)) title = Column(String(50)) is_delete =Column(Boolean) tag1 =Column(Enum('PYTHON','FLASK','DJANGO')) #枚舉常規寫法 tag2 =Column(Enum(TagEnum)) #枚舉另一種寫法 create_time1=Column(Date) create_time2=Column(DateTime) create_time3=Column(Time) content1 =Column(Text) content2 =Column(LONGTEXT) # Base.metadata.drop_all() # Base.metadata.create_all() #新增數據到表news中 a1 = News(price1=1000.0078,price2=1000.0078,title='測試數據',is_delete=True,tag1="PYTHON",tag2=TagEnum.flask, create_time1=date(2018,12,12),create_time2=datetime(2019,2,20,12,12,30),create_time3=time(hour=11,minute=12,second=13), content1="hello",content2 ="hello hi nihao")

    Column常用參數

  • primary_key:True設置某個字段為主鍵。
  • autoincrement:True設置這個字段為自動增長的。
  • default:設置某個字段的默認值。在發表時間這些字段上面經常用。
  • nullable:指定某個字段是否為空。默認值是True,就是可以為空。
  • unique:指定某個字段的值是否唯一。默認是False。
  • onupdate:在數據更新的時候會調用這個參數指定的值或者函數。在第一次插入這條數據的時候,不會用 onupdate的值,只會使用default的值。常用于是 update_time 字段(每次更新數據的時候都要更新該字段值)。
  • name:指定ORM模型中某個屬性映射到表中的字段名。如果不指定,那么會使用這個屬性的名字來作為字段名。如果指定了,就會使用指定的這個值作為表字段名。這個參數也可以當作位置參數,在第1個參數來指定。
  • 案例:

    class News(Base): __tablename__ = 'news' id = Column(Integer,primary_key=True,autoincrement=True) create_time = Column(DateTime,default=datetime.now) read_count = Column(Integer,default=11) title = Column(String(50),name='my_title',nullable=False) telephone = Column(String(11),unique=True) update_time = Column(DateTime,onupdate=datetime.now,default=datetime.now)

    2、自動從數據庫中映射

    from datetime import datetime from sqlalchemy.ext.automap import automap_base from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine # 數據庫連接url DB_CONNECT_STRING = 'mysql+pymysql://root:123123@localhost:3306/test' # 創建引擎 engine = create_engine(DB_CONNECT_STRING, echo=True) # 自動映射 Base = automap_base() Base.prepare(engine,reflect=True) # 獲取所有表的映射類 tables = Base.classes.keys() # print(tables) # 獲取指定t_movies表(確保表名沒有問題) --> movie實體類 movie = Base.classes.t_movies # 查看映射信息 print(movie.__dict__) # 獲取所有字段或屬性 keys = movie.__table__.columns.keys() print(keys)

    3、數據的CRUD操作

    用session做數據的增刪改查操作:

    1、 構建session對象:

    所有和數據庫的ORM操作都必須通過一個叫做 session 的會話對象來實現,通過以下代碼來獲取會話對象:

    from sqlalchemy.orm import sessionmaker engine = create_engine(DB_URI) Base = declarative_base(engine) session = sessionmaker(engine)()# 注意,返回的是一個函數

    **2、添加對象: **

    #創建對象,也即創建一條數據: p1 = Person(name='momo1',age=19,country='china') # 將這個對象添加到`session`會話對象中: session.add(p1) # 將session中的對象做commit操作(提交): session.commit() # 一次性添加多條數據: p1 = Person(name='momo1',age=19,country='china') p2 = Person(name='momo2',age=20,country='china') session.add_all([p1,p2]) session.commit()

    3、 查找對象:

    # 查找某個模型對應的那個表中所有的數據: all_person = session.query(Person).all() # 使用filter_by來做條件查詢 all_person = session.query(Person).filter_by(name='momo1').all() # 使用filter來做條件查詢 all_person = session.query(Person).filter(Person.name=='momo1').all() # 使用get方法查找數據,get方法是根據id來查找的,只會返回一條數據或者None person = session.query(Person).get(primary_key) # 使用first方法獲取結果集中的第一條數據 person = session.query(Person).first()

    filter過濾條件

    過濾是數據提取的一個很重要的功能,以下對一些常用的過濾條件進行解釋,并且這些過濾條件都是只能通過filter 方法實現的:

  • equals : ==
  • news= session.query(News).filter(News.title == "title1").first()
  • not equals : !=
  • query(User).filter(User.name != 'ed')
  • like & ilike [不區分大小寫]:
  • query(User).filter(User.name.like('%ed%'))
  • in:
  • query(User).filter(User.name.in_(['ed','wendy','jack']))
  • not in:
  • query(User).filter(~User.name.in_(['ed','wendy','jack']))
  • is null:
  • query(User).filter(User.name==None) # 或者是 query(User).filter(User.name.is_(None))
  • is not null:
  • query(User).filter(User.name != None) # 或者是 query(User).filter(User.name.isnot(None))
  • and:
  • query(User).filter(and_(User.name=='ed',User.fullname=='Ed Jones')) # 或者是傳遞多個參數 query(User).filter(User.name=='ed',User.fullname=='Ed Jones') # 或者是通過多次filter操作 query(User).filter(User.name=='ed').filter(User.fullname=='Ed Jones')
  • or:
  • query(User).filter(or_(User.name=='ed',User.name=='wendy'))

    聚合函數

    • func.count:統計行的數量。

    • func.avg:求平均值。

    • func.max:求最大值。

    • func.min:求最小值。

    • func.sum:求和。

    #3.mysql聚合函數 r = session.query(func.count(News.id)).first() print(r) r = session.query(func.max(News.price)).first() print(r) r = session.query(func.min(News.price)).first() print(r) r = session.query(func.avg(News.price)).first() print(r) r = session.query(func.sum(News.price)).first() print(r)

    4、修改對象:

    首先從數據庫中查找對象,然后將這條數據修改為你想要的數據,最后做commit操作就可以修改數據了。

    person = session.query(Person).first() person.name = 'laoliu' session.commit()

    5、刪除對象:

    將需要刪除的數據從數據庫中查找出來,然后使用 session.delete 方法將這條數據從session中刪除,最后做commit操作就可以了。

    person = session.query(Person).first() session.delete(person) session.commit()

    4ORM的關聯關系

    1、表的外鍵關聯

    使用SQLAlchemy創建外鍵非常簡單。在從表中增加一個字段,指定這個字段外鍵的是哪個表的哪個字段就可以了。從表中外鍵的字段,必須和主表的主鍵字段類型保持一致。

    這種關聯只關注數據表之間的外鍵關聯,不考慮Python對象之間的關聯關系.

    # 主表 / 從表 # user/news class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) def __repr__(self): return "<User(uname:%s)>" % self.uname class News(Base): __tablename__ = 'news' id = Column(Integer,primary_key=True,autoincrement=True) title = Column(String(50),nullable=False) content = Column(Text,nullable=False) uid = Column(Integer,ForeignKey("user.id"))

    外鍵的刪除選項

  • RESTRICT:若子表中有父表對應的關聯數據,刪除父表對應數據,會阻止刪除。默認項
  • NO ACTION:在MySQL中,同RESTRICT。
  • CASCADE:級聯刪除。
  • SET NULL:父表對應數據被刪除,子表對應數據項會設置為NULL。
  • # 父表/從表 # user/news class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) def __repr__(self): return "<User(uname:%s)>" % self.uname class News(Base): __tablename__ = 'news' id = Column(Integer,primary_key=True,autoincrement=True) title = Column(String(50),nullable=False) content = Column(Text,nullable=False)# 設置刪除選項 # uid = Column(Integer,ForeignKey("user.id",ondelete='RESTRICT')) # uid = Column(Integer,ForeignKey("user.id",ondelete='NO ACTION')) # uid = Column(Integer,ForeignKey("user.id",ondelete='CASCADE')) uid = Column(Integer,ForeignKey("user.id",ondelete='SET NULL')) def __repr__(self): return "<News(title:%s,content=%s)>" % (self.title,self.content) Base.metadata.drop_all() Base.metadata.create_all() user = User(uname='momo') session.add(user) session.commit() news1= News(title='AAA',content='123',uid=1) news2= News(title='BBB',content='456',uid=1) session.add_all([news1,news2]) session.commit()

    2ORM中的一對多/多對一

    mysql表級別的外鍵,還不夠爽,必須拿到一個表的外鍵,然后通過這個外鍵再去另外一張表中查找,這樣太麻煩了。

    SQLAlchemy提供了一個 relationship ,這個類可以定義屬性,以后在訪問相關聯的表的時候就直接可以通過屬性訪問的方式就可以訪問得到了。另外,可以通過 backref 來指定反向訪問的屬性名稱。newss是指有多篇新聞。他們之間的關系是一個“一對多”的關系。

    #創建ORM模型 Base = declarative_base(engine) # 主表 / 從表 # user/news class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) # newss=relationship("News") #這種寫法不是最優的,通常會把它通過反向聲明的方式寫在“多”的那一方 def __repr__(self): return "<User(uname:%s)>" % self.uname class News(Base): __tablename__ = 'news' id = Column(Integer,primary_key=True,autoincrement=True) title = Column(String(50),nullable=False) content = Column(Text,nullable=False) #外鍵 uid = Column(Integer,ForeignKey("user.id")) #正向author = relationship("User") #正向 和 反向在一起 表明兩個模型之間的關系 author = relationship("User",backref="newss") def __repr__(self): return "<News(title:%s,content=%s)>" % (self.title,self.content) # Base.metadata.drop_all() # Base.metadata.create_all()

    3ORM中的一對一

    在sqlalchemy中,如果想要將兩個模型映射成一對一的關系,那么應該在父模型中,指定引用的時候,要傳遞一個 uselist=False 這個參數進去。就是告訴父模型,以后引用這個從模型的時候,不再是一個列表了,而是一個對象了。

    方法一:參照一對多關聯,加上uselist

    class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) extend = relationship("UserExtend",uselist=False) class UserExtend(Base): __tablename__ = 'user_extend' id = Column(Integer, primary_key=True, autoincrement=True) school = Column(String(50)) uid = Column(Integer,ForeignKey("user.id")) user = relationship("User")

    方法二:

    class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) class UserExtend(Base): __tablename__ = 'user_extend' id = Column(Integer, primary_key=True, autoincrement=True) school = Column(String(50)) uid = Column(Integer,ForeignKey("user.id")) user = relationship("User",backref=backref("extend",uselist=False))

    4ORM中的多對多

  • 多對多的關系需要通過一張中間表來綁定他們之間的關系。
  • 先把兩個需要做多對多的模型定義出來
  • 使用Table定義一個中間表,中間表一般就是包含兩個模型的外鍵字段就可以了,并且讓他們兩個來作為一個“復合主鍵”。
  • 在兩個需要做多對多的模型中隨便選擇一個模型,定義一個relationship屬性,來綁定三者之間的關系,在使用relationship的時候,需要傳入一個secondary=中間表對象名
  • #表3 中間表 news_tag = Table( "news_tag", Base.metadata, Column("news_id",Integer,ForeignKey("news.id"),primary_key=True), Column("tag_id",Integer,ForeignKey("tag.id"),primary_key=True) )#表1 class News(Base): __tablename__ = 'news' id = Column(Integer,primary_key=True,autoincrement=True)title = Column(String(50),nullable=False) #產生關系 寫法1 # tags = relationship("Tag",backref="newss",secondary=news_tag) def __repr__(self): return "<News(title:%s)>" % self.title #表2 class Tag(Base): __tablename__ = 'tag' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) # 產生關系 寫法2 newss = relationship("News",backref="tags",secondary=news_tag) def __repr__(self): return "<Tag(name:%s)>" % self.name

    5SQLALchemy的高級

    1、排序

  • order_by方法排序:可以指定根據模型中某個屬性進行排序,"模型名.屬性名.desc()"代表的是降序排序。
  • # 倒序排序 articles2 = session.query(Article).order_by(Article.create_time.desc()).all() print(articles2)
  • 在定義模型的時候指定排序:有些時候,不想每次在查詢的時候都用order_by方法,可以在定義模型的時候就指定排序的方式。
  • 一、模型對象定義中加排序

    #排序方式2:定義模型時,指定排序方式 class Article(Base): __tablename__ = 'article' id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) __mapper_args__ = { # "order_by": create_time #正序 "order_by": create_time.desc() #倒序 }def __repr__(self): return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time)

    二、在relationship的方法中order_by屬性

    #排序方式3:涉及兩表時,定義模型時,用relationship方法中的order_by屬性指定排序方式 class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True, autoincrement=True) uname = Column(String(50),nullable=False) class Article(Base): __tablename__ = 'article' id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) uid = Column(Integer,ForeignKey("user.id")) # author = relationship("User", backref=backref("articles",order_by=create_time)) #正序 author = relationship("User", backref=backref("articles",order_by=create_time.desc())) #倒序 def __repr__(self): return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time)

    2、分頁查詢

  • limit:可以限制查詢的時候只查詢前幾條數據。 屬top-N查詢
  • articles = session.query(Article).limit(10).all() print(articles)
  • offffset:可以限制查找數據的時候過濾掉前面多少條。可指定開始查詢時的偏移量。
  • #offset:可以限制查找數據的時候過濾掉前面多少條。可指定開始查詢時的偏移量。 articles = session.query(Article).offset(10).limit(10).all()
  • 切片:可以對Query對象使用切片操作,來獲取想要的數據。
    可以使用 slice(start,stop) 方法來做切片操作。
    也可以使用 [start:stop] 的方式來進行切片操作。
    一般在實際開發中,中括號的形式是用得比較多的。
  • #實現分頁 from sqlalchemy.orm.query import Query def oper3(): articles = session.query(Article).order_by(Article.id.desc()).slice(0,10).all() print(articles) def oper4(): articles = session.query(Article).order_by(Article.id.desc())[0:10] print(articles)

    3、懶加載

    在一對多,或者多對多關系的時候,如果想要獲取多的一方這一部分的數據的時候,往往能通過一個屬性就可以全部獲取了。

    如有一個作者,想要這個作者的所有文章,通過user.articles就可以獲取所有的。

    但有時候我們不想獲取所有的數據,如只想獲取這個作者今天發表的文章,那么這時候我們可以給relationship方法添加屬性lazy=‘dynamic’,以后通過user.articles獲取到的就不是一個列表,而是一個AppenderQuery對象了。這樣就可以對這個對象再進行一層過濾和排序等操作。

    通過 lazy='dynamic' ,獲取出來的多的那一部分的數據,就是一個 AppenderQuery 對象了。這種對象既可以添加新數據,也可以跟 Query 一樣,可以再進行一層過濾。

    class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True, autoincrement=True) uname = Column(String(50),nullable=False) class Article(Base): __tablename__ = 'article' id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) create_time = Column(DateTime, nullable=False, default=datetime.now) uid = Column(Integer,ForeignKey("user.id")) # author = relationship("User", backref=backref("articles")) #懶加載 author = relationship("User", backref=backref("articles",lazy="dynamic")) def __repr__(self): return "<Article(title:%s,create_time:%s)>" % (self.title,self.create_time) def add_data(): Base.metadata.drop_all() Base.metadata.create_all() user = User(uname='莫莫') for x in range(100): article = Article(title="title %s" % x) article.author = user session.add(article)session.commit() from sqlalchemy.orm.collections import InstrumentedList def oper1(): user = session.query(User).first() print(type(user.articles)) #<class 'sqlalchemy.orm.collections.InstrumentedList'> print(user.articles) #懶加載 from sqlalchemy.orm.dynamic import AppenderQuery def oper2(): user = session.query(User).first() print(type(user.articles)) #<class 'sqlalchemy.orm.dynamic.AppenderQuery'> print(user.articles) #辨析 AppenderQuery 和 Query from sqlalchemy.orm.query import Query def oper3(): user = session.query(User) print(type(user)) #<class 'sqlalchemy.orm.query.Query'> print(user) #sql語句 #有2層意思 #1.是一個Query對象。可以調用Query對象的方法 #2.是一個AppenderQuery對象。可以繼續追加數據進去 def oper4(): user = session.query(User).first()#可以調用Query對象的方法 print(type(user)) print(user.articles.filter(Article.id>=50).all()) # article = Article(title='title 100') # user.articles.append(article)#2.是一個AppenderQuery對象。可以繼續追加數據進去 # session.commit() if __name__ == '__main__': # add_data() # oper1() # oper2() # oper3() oper4()

    4、分組和過濾

    group_by:

    根據某個字段進行分組。如想要根據年齡進行分組,來統計每個分組分別有多少人

    r = session.query(User.age,func.count(User.id)).group_by(User.age).all()

    having:

    having是對分組查找結果作進一步過濾。如只想要看未成年人的人數,那么可以首先對年齡進行分組統計人數,然后再對分組進行having過濾。

    r = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age < 18).all()

    5、子查詢

    子查詢即select語句中還有select。

    那么在sqlalchemy中,要實現一個子查詢,需以下幾個步驟:

  • 將子查詢按照傳統的方式寫好查詢代碼,然后在 query 對象后面執行 subquery 方法,將這個查詢變成一個子查詢。

  • 在子查詢中,將以后需要用到的字段通過 label 方法,取個別名。

  • 在父查詢中,如果想要使用子查詢的字段,那么可以通過子查詢的返回值上的 c 屬性拿到(c=Column)。

  • class User(Base): __tablename__ = 'user' id = Column(Integer,primary_key=True,autoincrement=True) uname = Column(String(50),nullable=False) city = Column(String(50),nullable=False) age = Column(Integer,default=0) def __repr__(self): return "<User(username: %s)>" % self.uname def add_data(): Base.metadata.drop_all() Base.metadata.create_all() user1 = User(uname='老肖',city="貴陽",age=18) user2 = User(uname='王二',city="貴陽",age=18) user3 = User(uname='張三',city="北京",age=18) user4 = User(uname='趙四',city="貴陽",age=20) session.add_all([user1,user2,user3,user4]) session.commit() # 相親類網站:同城交友 之珍愛網 #需求: 尋找和 “老肖” 這個人在同一個城市,并且是同年齡的人 #實現思路1:傳統方式 def oper1(): u = session.query(User).filter(User.uname == '老肖').first() users = session.query(User).filter(User.city==u.city,User.age==u.age).all() print(users) #實現思路2:子查詢方式 #原生sql:select `user`.id,`user`.uname,`user`.city,`user`.age from user, # (select `user`.city,`user`.age from user where uname='老肖') as yige # where `user`.city=yige.city AND `user`.age=yige.age def oper2():# stmt = session.query(User.city.label('city'), User.age.label('age')).filter(User.uname == '老肖').subquery() # result = session.query(User).filter(User.city == stmt.c.city, User.age == stmt.c.age) # print(result) #查看sql語句 stmt = session.query(User.city.label('city'), User.age.label('age')).filter(User.uname == '老肖').subquery() result = session.query(User).filter(User.city == stmt.c.city, User.age == stmt.c.age).all() print(result) # 查看結果

    6、Flask-SQLAlchemy

    Flask-SQLAlchemy的使用_對SQLAlchemy進行了封裝和優化:

    • Flask-SQLAlchemy是Flask框架的一個插件,
    • Flask-SQLAlchemy是對SQLAlchemy進行了一個簡單的封裝的一個插件,
    • 使得我們在Flask中使用sqlalchemy更加的簡單。

    1.安裝:

    pip install flask-sqlalchemy

    2.Flask-SQLAlchemy的使用要點:

    2.1 數據庫連接

    數據庫初始化不再是通過create_engine。

  • 跟sqlalchemy一樣,定義好數據庫連接字符串DB_URI。

  • 將這個定義好的數據庫連接字符串DB_URI,通過 SQLALCHEMY_DATABASE_URI 這個key名配置到 app.config中。

  • 代碼:

    app.config["SQLALCHEMY_DATABASE_URI"] = DB_URI
  • 使用 flask_sqlalchemy.SQLAlchemy 這個類定義一個對象,并將 app 傳入進去。
  • 代碼:

    db = SQLAlchemy(app)

    2.2 創建ORM模型類

    之前都是通過Base = declarative_base()來初始化一個基類,然后再繼承,在Flask-SQLAlchemy中更加簡單了。

  • 還是跟使用sqlalchemy一樣,定義模型。現在不再是需要使用 delarative_base 來創建一個基類。而是使用 db.Model 來作為基類。
  • 在模型類中, Column 、 String 、 Integer 以及 relationship 等,都不需要導入了,直接使用 db 下面相應的屬性名就可以了。
  • 在定義模型的時候,可以不寫 tablename ,那么 flask_sqlalchemy 會默認使用當前的模型的名字轉換成小寫來作為表的名字, 并且如果這個模型的名字用到了多個單詞并且使用了駝峰命名法,那么會在多個單詞之間使用下劃線來進行連接,雖然flflask_sqlalchemy給我們提供了這個特性,但是不推薦使用。(增強代碼可讀性,提高團隊合作效率)
  • 2.3 ORM模型映射到數據庫表

    寫完模型類后,要將模型映射到數據庫的表中,使用以下代碼即可

  • 刪除數據庫表:db.drop_all()

  • 創建數據庫表:db.create_all()

  • 2.4 session的使用

    以后session也不需要使用 sessionmaker 來創建了, 直接使用 db.session 就可以了,操作這個session的時候就跟之前的 sqlalchemy 的 session 是一樣的。

    2.5添加數據

    這時候就可以在數據庫中看到已經生成了對應表了 ,添加數據和之前的沒有區別,只是session成為了一個db的屬性

    2.6 查詢數據:

    1.單表查詢

    查詢數據不再是之前的session.query方法了,而是將query屬性放在了db.Model上,所以查詢就是通過“模型名.query”的方式進行查詢了, query 就跟之前的sqlalchemy中的query方法是一樣用的。

    2.多表查詢

    如果查找數據涉及多個模型,只能使用db.session.query(模型名).all() 這種方式

    2.7 修改數據:

    修改數據和之前的沒有區別,只是session成為了一個db的屬性
    2.8 刪除數據

    刪除數據跟添加數據和修改數據類似,只不過session是db的一個屬性而已

    from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) HOSTNAME = '127.0.0.1' PORT = '3306' DATABASE = 'test' USERNAME = 'root' PASSWORD = '123123' DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}? charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #1.連接數據庫 db = SQLAlchemy(app) #2.創建ORM模型 class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer,primary_key=True,autoincrement=True) uname = db.Column(db.String(50),nullable=False) def __repr__(self): return "<User(uname: %s)>" % self.uname 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") #3.刪除表 db.drop_all() #4.創建表 db.create_all() #5.添加數據 user = User(uname='莫莫') article = Article(title='華為5G 算法突破了,俄羅斯小伙突破的') article.author = user db.session.add(article) db.session.commit() #6.查詢數據 # users = User.query.all() #等價于 db.session.query(User).all() # print(users) #在query屬性之后 可以用 order_by 、 filter、filter_by、group_by、having等方法進行更復雜的單表查詢#若要進行更復雜的多表查詢,只能使用db.session.query(User).all() 這種方式 #如 order_by users = User.query.order_by(User.id.desc()).all() print(users) #7.修改數據 user = User.query.filter(User.uname=='露露').first() user.uname = '探探' db.session.commit() #8.刪除數據 user = User.query.filter(User.uname=='探探').first() db.session.delete(user) db.session.commit() @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()

    3、Flask-SQLAlchemyalembic結合

    在之前的數據庫操作中,我們新增一個字段是不是每次都得刪除數據庫表,然后再重新將新創建的數據庫表映射到數據庫中。這樣操作是不是很蛋疼?是吧?于是sqlalchemy作者拜爾為了解決這一問題,開發了alembic這一遷移工具。

    步驟一:安裝****alembic

    pip install alembic

    步驟二:配置好數據庫連接文件 如****confifig.py

    HOSTNAME = '127.0.0.1' PORT = '3306' DATABASE = 'test' USERNAME = 'root' PASSWORD = '123123' DB_URI ="mysql+pymysql://{username}:{password}@{host}:{port}/{db}? charset=utf8".format(username=USERNAME,password=PASSWORD,host=HOSTNAME,port=PORT,db=DATABASE) SQLALCHEMY_DATABASE_URI = DB_URI

    步驟三:注冊confifig.py文件到Flask項目

    import config app = Flask(__name__) app.config.from_object(config) class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer,primary_key=True,autoincrement=True) uname = db.Column(db.String(50),nullable=False) age = db.Column(db.Integer) gender=db.Column(db.String(2))

    步驟四:創建一個倉庫

    alembic init [倉庫的名字]

    注意:先進入虛擬環境,然后cd到當前項目中

    步驟五:修改配置文件alembic.ini和env.py

    sqlalchemy.url = mysql+pymysql://root:123123@localhost/test?charset=utf8 import os import sys import alembic_demo # 把當前項目路徑加入到path中 sys.path.append(os.path.dirname(os.path.dirname(__file__))) target_metadata = alembic_demo.Base.metadata

    步驟六:自動生成遷移文件
    將當前模型中的狀態生成遷移文件。

    alembic revision --autogenerate -m "提示信息"

    步驟七:映射到數據庫中
    使用alembic upgrade head將剛剛生成的遷移文件,真正映射到數據庫中。

    alembic upgrade head

    步驟八:以后如果修改了模型,重復67步驟

    總結

    以上是生活随笔為你收集整理的第五章:Flask数据库操作的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。