# 鏈接數據庫須要建立引擎 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