Web後端學習筆記 Flask(6)數據庫

SQLAlchemy一對一關係實現:

在一對多的條件下:給Article表中添加article,只需要將article放入到user的article屬性中,再將user添加到user表中即可,此時的article會自動添加到Article表中。

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False)  # 創建外鍵
    # ondelete表示的是外鍵的約束

    author = relationship("User", backref="articles")    # relationship 一個Article對應一個author

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


article1 = Article(title="new art 1", content="ct111")
article2 = Article(title="new art 2", content="ct222")
article3 = Article(title="new art 3", content="ct333")

user = User(username="ghost")
user.articles.extend([article1, article2, article3])

db_session.add(user)
db_session.commit()
# 此時,user被添加到User表中,而所有的文章添加到了Article表中,uid是當前添加的user

在一對一的條件下,也可以進行添加,例如,通過添加article,實現將user添加到User中

article1 = Article(title="the Knight", content="ktkt111")
user = User(username="knight")
# 一對一直接賦值即可
article1.author = user

db_session.add(article1)
db_session.commit()

一對一關係的實現:
       舉例: 在後臺會存儲用戶的信息,但是用戶信息中有常用的字段(例如,username, id, sex)以及不常用的字段,例如address, email等信息,那麼爲了提高數據庫的查找效率,可以對用戶的存儲進行優化,將常用的用戶信息存放到user表中,將不常用的用戶信息存放到user_extend表中,則這兩個表的關係就是一對一的關係。

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False)  # 創建外鍵
    # ondelete表示的是外鍵的約束

    author = relationship("User", backref="articles")    # relationship 一個Article對應一個author

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)
    
    # 因爲一個User只能對應一個user_extend,必須是一對一的關係
    extend = relationship("UserExtend", uselist=False)  
    # uselist表示使用列表,默認爲True, 表示User下的extend是一個列表,則表示extend不唯一
    # 由於extend需要與user一一對應,所以將uselist參數設置爲False,此時表示extend是唯一的

    def __repr__(self):
        return str(self.id) + " | " + self.username


class UserExtend(Base):
    __tablename__ = "user_extend"
    id = Column(Integer, primary_key=True, autoincrement=True)
    school = Column(String(50), nullable=True)
    address = Column(String(50), nullable=False)
    email = Column(String(50), nullable=False)
    uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICTION"))
    
    # 在orm層面做關聯
    user = relationship("User")


article1 = Article(title="the Knight", content="ktkt111")
user = User(username="knight")

通過這樣的設置,user和user_extend則會成爲一一對應,但是此時不能再設置backref參數爲extend

還有一種方法,即通過backref函數設置backref參數設置。

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref

HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICT"), nullable=False)  # 創建外鍵
    # ondelete表示的是外鍵的約束

    author = relationship("User", backref="articles")    # relationship 一個Article對應一個author

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


class UserExtend(Base):
    __tablename__ = "user_extend"
    id = Column(Integer, primary_key=True, autoincrement=True)
    school = Column(String(50), nullable=True)
    address = Column(String(50), nullable=False)
    email = Column(String(50), nullable=False)
    uid = Column(Integer, ForeignKey("user.id", ondelete="RESTRICTION"))

    # 在orm層面做關聯
    user = relationship("User", backref=backref("extend", uselist=False))


article1 = Article(title="the Knight", content="ktkt111")
user = User(username="knight")

多對多的關係實現:
     舉例:在博客上,一篇文章的標籤有多個,一個標籤也可能對應多篇文章,這是一個典型的多對多的關係。

如果需要定義一個多對多的關係,那麼首先需要將兩個做多對多的模型定義出來,使用Table定義一箇中間表,中間表一般只包含兩個模型的外鍵字段,讓這兩個字段的組合作爲中間表的複合主鍵,在多對多的兩個模型上,隨便選擇一個,做一個relationship,同時定義secondary參數爲中間表。

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中

article_tag = Table(
    "article_tag",         # 數據庫的名字
    Base.metadata,         # 元數據
    Column("article_id", Integer, ForeignKey("article.id"), primary_key=True),
    Column("tag_id", Integer, ForeignKey("tag.id"), primary_key=True),
    # 這個表中沒有主鍵,可以將article_id和tag_id一起作爲一個複合主鍵
    # 假設user表中 article_id/title = 1/"cxcx"
    # tag表中,tag_id / tag_name = 1/"leisure"
    # 則數據表article_tag 中會插入 article_id/tag_id = 1/1
    # 爲了減少數據存儲的冗餘,因該只能插入一次 article_id/tag_id = 1/1,
    # 所以可以將他們的組合作爲一個複合主鍵
)


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    tags = relationship("Tag", backref="articles", secondary=article_tag)

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


class Tag(Base):
    __tablename__ = "tag"
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + "|" + self.name


# 創建表
# Base.metadata.drop_all()
# Base.metadata.create_all()

# 插入數據
# article1 = Article(title="gone to xxx")
# article2 = Article(title="Leave now")
#
# tag1 = Tag(name="scary")
# tag2 = Tag(name="horrible")
# article1.tags.extend([tag1, tag2])
#
# tag3 = Tag(name="funny")
# article2.tags.extend([tag2, tag3])
#
# db_session.add_all([article1, article2])
# db_session.commit()


# 數據查詢
articles = db_session.query(Article).all()
for article in articles:
    tag_str = []
    for tag in article.tags:
        tag_str.append(tag.name)
    print(article.title, " ", tag_str)

查詢的效果:

ORM層面刪除數據注意事項:

       外鍵以及外鍵約束是數據庫層面,下面介紹以下基於ORM層面的約束。例如,在數據庫層面有一個約束叫restrict,代表限制刪除,即如果要刪除父表的數據,但是由於從表也能用到了父表的數據,所以數據庫是拒絕刪除的。但是在ORM層面,如果指定了級聯刪除,那麼ORM就會無視數據庫的RESTRICT約束,先把從表中的數據刪除,然後再將從表中的數據刪除。這樣就實現了級聯刪除。

orm層面刪除數據會無視MySQL層面的外鍵約束,直接會將對應的數據刪除,然後將從表中的外鍵設置爲空,如果想要避免這種行爲,應該將從表中的null設置爲False.

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    uid = Column(Integer, ForeignKey("user.id"), nullable=False)
    author = relationship("User", backref="articles")

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


# Base.metadata.drop_all()
# Base.metadata.create_all()
#
# user1 = User(username="Topic")
# article1 = Article(title="Gone with u")
# article1.author = user1
# db_session.add(article1)
# db_session.commit()


# 在orm層面會直接刪除數據,
# orm會先將article的uid設置爲null,然後再將user表中的數據刪除
# 爲了限制這種默認的行爲,可以將uid的nullable屬性設置爲False
user = db_session.query(User).first()
db_session.delete(user)
db_session.commit()

orm層面的CASCADE刪除

在SQLAlchemy中,只要將一個數據添加到session中,和它相關聯的數據都可以一起存儲到數據庫中。這是通過relationship的時候,有一個關鍵字參數cascade可以設置這些屬性。cascade的屬性值有:

1. save-update:默認值,表示在添加一條數據的時候,會把其他和它相關聯的數據都添加到數據庫中。

2. delete:表示刪掉某一模型中的數據的時候,是否刪除掉使用relationship關聯的數據。

3. delete-orphan:表示當對一個ORM對象解除了父表中的關聯對象的時候,自己便會被刪除掉。當然如果父表中的數據被刪除,自己也會被刪除。這個選項只能用在一對多上,不能用在多對多以及多對一上。並且還需要在子模型的relationship中,增加一個single_parent=True的參數。

4. merge:默認選型。當在使用session.merge合併一個對象的時候,會將使用了relationship相關聯的對象進行merge操作。

5. expunge: 移除操作的時候,會將相關聯的對象也進行移除,這個操作只是從session中移除,並不會真正從數據庫中移除。

6. all:是對save-update,merge,refresh-expire, expunge,delete的集中縮寫

 # 數據庫層面定義
 uid = Column(Integer, ForeignKey("user.id", cascade="save-update, delete"))

如果需要實現,刪除文章的時候,將相關的作者刪除,則可以設置cascade

class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    # 數據庫層面定義
    uid = Column(Integer, ForeignKey("user.id"))

    # orm層面定義
    author = relationship("User", backref="articles", cascade="save-update, delete")

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)

如果需要實現,刪除文章的時候,刪除相關的作者,或者刪除作者的時候,同時刪除相關的文章,則可以在user中也定義一個relationship.

class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    articles = relationship("Article", cascade="save-update,delete")

    def __repr__(self):
        return str(self.id) + " | " + self.username


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    # 數據庫層面定義
    uid = Column(Integer, ForeignKey("user.id"))

    # orm層面定義
    author = relationship("User", cascade="save-update,delete")

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)

例如,可以再定義一張表,comment:

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    # 這裏可以用backref函數在子表中實現
    articles = relationship("Article", cascade="save-update,delete")  # user刪除,對應的article會刪除
    comments = relationship("Comment")    # user刪除,對應的comment不會刪除

    def __repr__(self):
        return str(self.id) + " | " + self.username


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    # 數據庫層面定義
    uid = Column(Integer, ForeignKey("user.id"))

    # orm層面定義
    author = relationship("User", cascade="save-update,delete")

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


class Comment(Base):
    __tablename__ = "comment"
    id = Column(Integer, primary_key=True, autoincrement=True)
    content = Column(String(50), nullable=False)
    uid = Column(Integer, ForeignKey("user.id"))

    author = relationship("User")

    def __repr__(self):
        return str(self.id) + " | " + self.content


# Base.metadata.drop_all()
# Base.metadata.create_all()

user1 = User(username="Top")
article1 = Article(title="Gone with wind")
article2 = Article(title="Jane")
comment1 = Comment(content="good")
comment2 = Comment(content="great works")

user1.articles.append(article1)
user1.articles.append(article2)

user1.comments.append(comment1)
user1.comments.append(comment2)
db_session.add(user1)
db_session.commit()

 數據庫中的排序:三種排序方法:

1. orderby

在數據庫中插入數據:

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    create_time = Column(DateTime, nullable=False, default=datetime.now)

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time)


# Base.metadata.drop_all()
# Base.metadata.create_all()

# article = Article(title="title3")
# db_session.add(article)
# db_session.commit()

articles = db_session.query(Article).order_by(Article.create_time.desc())  # 反向排序
# articles = db_session.query(Article).order_by("~article.create_time")  # 反向排序
for article in articles:
    print(article)

排序結果:

2. 定義模型的時候,傳遞orderby參數

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    create_time = Column(DateTime, nullable=False, default=datetime.now)

    # 定義排序的方式
    __mapper_args__ = {
        "order_by": create_time.desc()
    }

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time)


# Base.metadata.drop_all()
# Base.metadata.create_all()

# article = Article(title="title3")
# db_session.add(article)
# db_session.commit()

articles = db_session.query(Article).all()  # 反向排序
# articles = db_session.query(Article).order_by("~article.create_time")  # 反向排序
for article in articles:
    print(article)


3. 在定義relationship的時候,可以傳遞order_by參數,指定排序方式
    在存在主表以及父表的時候,通過relationship中的參數指定排序方式

    首先在表中插入數據:

示例代碼:

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref
from datetime import datetime
import random
from sqlalchemy import Table


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    create_time = Column(DateTime, nullable=False, default=datetime.now)

    uid = Column(Integer, ForeignKey("user.id"))

    # 通過user拿到user下的所有的文章的時候,可以通過時間排序
    author = relationship("User", backref=backref("articles", order_by=create_time.desc()))

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time)


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


# Base.metadata.drop_all()
# Base.metadata.create_all()

# article1 = Article(title="title1")
# article2 = Article(title="title2")

# user = db_session.query(User).filter(User.username == "toc").first()
# user.articles.append(article2)
#
# db_session.add(user)
# db_session.commit()

user = db_session.query(User).first()
articles = user.articles
for article in articles:
    print(article)

查詢結果:

排序的默認方式是從小到大,如果需要反過來,可以使用這個字段的desc()方法。

limit,offset,以及切片操作:

limit:可以限制每次查找的時候只查詢幾條數據

offset:可以限制查詢數據的時候過濾掉前面多少條數據

slice:可以對query()對象使用切片操作

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref
from datetime import datetime
import random
from sqlalchemy import Table
import time


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    create_time = Column(DateTime, nullable=False, default=datetime.now)

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.create_time)


# Base.metadata.drop_all()
# Base.metadata.create_all()

# 插入數據
# for x in range(100):
#     title = "title" + str(x+1)
#     article = Article(title=title)
#     time.sleep(1)
#     db_session.add(article)
#     db_session.commit()
#     print("current {}".format(x))

# # 查詢limit
articles = db_session.query(Article).limit(10).all()
for article in articles:
    print(article)


# 查詢offset
print("-"*50)
articles1 = db_session.query(Article).offset(10).limit(10).all()  # 從第11條開始,查找10條
for article in articles1:
    print(article)

# 查詢slice
print("-"*50)
articles2 = db_session.query(Article).slice(20, 30).all()
for article in articles2:
    print(article)

數據查詢懶加載技術:
       在一對多,或者多對多的時候,如果想要獲取多的這一部分的數據的時候,通常來講,通過一個屬性就可以全部獲取,例如上面用到的user.artices就可以獲取全部的文章。但是有的時候並不像獲取全部的數據,指向獲取這個作者今天發佈的文章,或者只是想展示少部分的數據。可以通過給relationship傳遞一個lazy=dynamic,那麼以後通過user.articles獲取到的就不是一個列表,而是一個AppendQuery對象,可以對這個對象在進行一層過濾和排序操作。

       如果採用將所有的數據從數據庫中拿出來再進行過濾的話,就會比較耗費性能。上述的方法稱爲懶加載。

# -*- coding: utf-8 -*-

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, func
from sqlalchemy import Text, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref
from datetime import datetime
import random
from sqlalchemy import Table
import time


HOST_NAME = "127.0.0.1"
PORT = "3306"
DATABASE = "cms"
USERNAME = "root"
PASSWORD = "root1234"

# dialect+driver://username:password@host:port/database

DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{database}".format(
    username=USERNAME, password=PASSWORD, host=HOST_NAME, port=PORT, database=DATABASE
)

# 創建數據庫引擎
engine = create_engine(DB_URI)
Base = declarative_base(engine)   # 通過繼承Base創建ORM模型/ 創建基類

db_session = sessionmaker(engine)()   # 創建會話,才能實現增刪改查
# 1. 創建ORM模型,必須繼承自SQLAlchemy:
# 2. 在ORM中創建一些屬性,跟表中的字段一一映射,這些屬性必須是SQLAlchemy提供的數據類型
# 3. 將創建好的ORM模型映射到數據庫中


class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(50), nullable=False)

    def __repr__(self):
        return str(self.id) + " | " + self.username


class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)

    # 數據庫層面定義
    uid = Column(Integer, ForeignKey("user.id"))

    # orm層面定義
    author = relationship("User", backref=backref("articles", lazy="dynamic"))  # 懶加載

    def __repr__(self):
        return "<article>" + str(self.id) + " | " + self.title + " | " + " | " + str(self.uid)


user = db_session.query(User).first()
print(type(user.articles))
articles = user.articles.filter(Article.id > 50).all()   # user.articles可以直接使用filter進行過濾
for article in articles:
    print(article)

# user.articles 是一個<class 'sqlalchemy.orm.dynamic.AppenderQuery'>
# 所以除了可以使用filter的方法
# 也可以使用append方法添加新的數據,再次commit到數據庫中。

article_new = Article(title="new article")
user.articles.append(article_new)
db_session.commit()

lazy的屬性值:

1. select, 默認值,例如,如果沒有訪問user.articles,sqlalchemy就不會從數據庫中查找數據,一旦訪問了這個屬性,sqlalchemy就會從數據庫查找所有的數據,返回的數據是一個list對象,這也是懶加載。

2. dynamic:在訪問user.articles屬性的時候,返回的是一個AppendQuery對象。

-----------------------------------------------------------------------------------------------------------

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章