【SQLAlchemy】03-SQLAlchemy関連

6805 ワード

いい風は力を借りて,私を青雲に送ってくれた.
SQLAlchemyを使用して外部キーを作成するのは簡単です.サブテーブルにフィールドを追加します.タイプは関連する親テーブルのフィールドタイプと一致します.
外部キー
class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))

上のコードParentChildは外部キー関係を確立し、サブテーブルの外部キーparent_idは親テーブルのプライマリキーidに関連しているので、現在のフィールドタイプは親テーブルのidタイプと一致する必要があり、次にForeignKey('parent.id')のパラメータはテーブル名である.フィールド名は、モデル名に書かないでください.フィールド名:
 parent_id = Column(Integer, ForeignKey('parent.id'))

外部キー制約:
  • RESTRICT:親テーブルデータが削除され、削除がブロックされます.デフォルトはこれです.
  • NO ACTION:MySQLで、同じくRESTRICT.
  • CASCADE:カスケード削除.
  • SET NULL:親テーブルデータが削除され、子テーブルデータがNULLに設定されます.

  • サンプルコード:
    parent_id = Column(Integer, ForeignKey("parent.id", ondelete="CASCADE"))
    

    一対多
    class User(Base):
        __tablename__ = 'user'
        id = Column(Integer,primary_key=True,autoincrement=True)
        username = Column(String(50),nullable=False)
    
        # articles = relationship("Article")
    
    class Article(Base):
        __tablename__ = 'article'
        id = Column(Integer,primary_key=True,autoincrement=True)
        title = Column(String(50),nullable=False)
        content = Column(Text,nullable=False)
    
        author = relationship("User",backref="articles")
    

    上記のコードは、user--articleが1対多の関係であることを示している.すなわち、1人が複数の文章を発表することができるので、authorの外部キーフィールドがuser表のプライマリキーに関連付けられ、relationshipを提供している.このクラスは属性を定義することができる.後で関連するテーブルにアクセスするときに直接属性アクセスでアクセスできます.
    注:relationshipの最初のパラメータはモデル名であり、backrefは逆クエリを表します.たとえば、次のようになります.
  • マルチクラスクエリークラス
  • article = session.query(Article).first()
    #         
    user = article.author
    print(user.username)
    
  • クエリーのクラス
  • user = session.query(User).first()
    articles = user.articles
    
    backref:主にクエリー・マルチクラスとして使用されます.このパラメータをマルチクラスのrelationshipで使用しない場合は、クラスでrelationshipを定義する必要があります.たとえば、次のようにします.
    class User(Base):
        __tablename__ = 'user'
        id = Column(Integer,primary_key=True,autoincrement=True)
        username = Column(String(50),nullable=False)
        
       #     
        articles = relationship("Article")
    

    一対一sqlalchemyで、2つのモデルを1対1の関係にマッピングする場合は、親モデルで参照を指定するときに、uselist=Falseというパラメータを渡す必要があります.親モデルに、後でこれをモデルから参照するときは、リストではなくオブジェクトであることを伝えます.
    class User(Base):
        __tablename__ = 'user'
        id = Column(Integer,primary_key=True,autoincrement=True)
        username = 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",backref="extend")
    

    コードにより、1対1の関係は2つのクラスでrelationshipを定義しているが、親パラメータの複数の1つのuselist=Falseは、結果セットではなく1対1の関係がオブジェクトであることを示している.1対のマルチプロセスではTrueがデフォルトである.2つのクラスがrelationshipを定義しているため、同様にサブクラスのみで定義されるように簡略化することができる.コードは以下の通りである.
    from sqlalchemy.orm import backref
    class UserExtend(Base):
        ......
        user = relationship("User",backref=backref("extend",uselist=False))
    

    多対多
  • 多対多の関係は、中間テーブルを介して彼らの関係をバインドする必要があります.
  • まず2つの多対多のモデルを定義する
  • Tableを使用して中間テーブルを定義し、中間テーブルは一般的に2つのモデルを含む外部キーフィールドであり、2つを複合プライマリキーとして使用する.
  • マルチペアを作成する必要がある2つのモデルのうち任意に1つのモデルを選択し、3つの関係をバインドするためにrelationship属性を定義し、relationshipを使用する場合、secondary= を入力する必要があります.

  • サンプルコード、記事対応ラベル:
    # ------------------------   ------------------------------
    article_tag = Table(
        "article_tag", #   
        Base.metadata,
        Column("article_id", Integer, ForeignKey("article.id"), primary_key=True), # article  
        Column("tag_id", Integer, ForeignKey("tag.id"), primary_key=True)  # tag  
    )
    
    # -----------------------Article----------------------------
    class Article(Base):
        __tablename__ = "article"
        id = Column(Integer, primary_key=True, autoincrement=True)
        title = Column(String(50), nullable=False)
        content = Column(Text, nullable=False)
    
        #     ,     ,     article  
        tags = relationship("Tag", backref="articles", secondary=article_tag)
    
    # -----------------------Tag--------------------------------
    class Tag(Base):
        __tablename__ = "tag"
        id = Column(Integer, primary_key=True, autoincrement=True)
        name = Column(String(50), nullable=False)
    

    ORMレベルでのデータ削除
    ORMレベルでデータを削除するとmysqlレベルの外部キー制約は無視されます.対応するデータは直接削除され、テーブルの外部キーからNULLに設定されます.このような行為を回避するには、テーブルの外部キーのnullable=Falseから空にブロックする必要があります.
    SQLAlchemyでは、セッションに1つのデータを追加すれば、彼に関連付けられたデータをデータベースに一緒に保存できます.これらはどのように設定されていますか?実はrelationshipを通じて、これらの属性を設定できるキーワードパラメータcascadeがあります.
    user = relationship("User",backref="extend",cascade="save-update,delete") #        
    
  • save-update:デフォルトのオプション.データを追加すると、他の関連データがデータベースに追加されます.この動作はsave-updateプロパティによって影響されます.
  • user = User(...)
    article = Article(...)
    article.author = user
    session.add(article) #       article,  user    commit        
    session.commit()
    
  • delete:あるモデルのデータを削除するときにrelationshipを使用して関連するデータも削除するかどうかを示す.
  • delete-orphan:親テーブルの関連オブジェクトを1つのORMオブジェクトに対して解除すると、自分が削除されることを示します.もちろん、親テーブルのデータが削除されると、自分も削除されます.このオプションは1対多にしか使用できません.多対多および多対一には使用できません.さらに、サブモデルのrelationshipにおいて、single_parent=Trueのパラメータを追加する必要がある.
  • class Article(Base):
        ......
        author = relationship("User",backref=backref("articles",cascade="all"),cascade="save-update",single_parent=True,ondelete='')
    
  • merge:デフォルトのオプション.session.mergeを使用してオブジェクトを結合すると、relationshipを使用して関連付けられたオブジェクトもmerge操作されます.
  • expunge:削除操作すると、関連するオブジェクトも削除されます.この操作はsessionから削除されるだけで、データベースから削除されることはありません.
  • all:save-update, merge, refresh-expire, expunge, deleteのいくつかの略語です.