• sqlalchemy 多对多


    简介

    在 sqlalchemy 中多对多通过中间表来实现,和django的区别是, sqlalchemy 需要自己来实现中间表。

    数据关系介绍:
    小说 <-> 作者, 多对多
    小说 <-> 类型, 多对多

    建表示例:

    base.py , 这个是一个基础表包含了基础字段和基础方法,所有数据模型表可以直接继承

    
    from sqlalchemy import func
    from novel import db, ma
    from typing import List
    
    
    class BaseModel(db.Model):
        """ 基础模型 """
        __abstract__ = True  # 这个声明为抽象表, sqlalchemy 不去创建表
        created_at = db.Column(db.DateTime, default=func.now(), comment="创建时间")
        updated_at = db.Column(db.DateTime, default=func.now(), comment="更新时间")
        deleted_at = db.Column(db.DateTime)
    
        def create(self):
            db.session.add(self)
            db.session.commit()
    
        def update(self):
            """
            更新数据
            :return:
            """
            self.updated_at = func.now()
            db.session.commit()
    
        def delete(self):
            """
            删除单条数据
            :return:
            """
            self.deleted_at = func.now()
            db.session.commit()
    
        @classmethod
        def delete_many(cls, ids: List[int]) -> int:
            """
            删除多条数据
            :param ids: 数据id
            :return: 成功数量
            """
            deleted_count = cls.__class__.query.filter(cls.id.in_(ids)).update({
                cls.__class__.deleted_at: func.now
            }, synchronize_session=False)
            return deleted_count
    

    author.py 用户表

    # -*- coding:utf-8 -*-
    import sqlalchemy
    
    from novel.model.base import BaseModel
    from novel import ma, db
    
    
    class Author(BaseModel):
        """
            小说作者信息
        """
        __tablename__ = "author"
        id = db.Column(db.BigInteger, autoincrement=True, primary_key=True)
        auth_name = db.Column(db.VARCHAR(50), comment="作者名称")
    
        def __init__(self, auth_name: str):
            self.auth_name = auth_name
    
        def __repr__(self):
            return f"id: {self.id} - name: {self.auth_name}"
    
    # 序列化,可以不写
    class AuthorSchema(ma.Schema):
        class Meta:
            model = Author
            # fields = ("id", "auth")
            # 这里是序列化字段, 写了一个简单匿名函数进行展示, fields = ("id", "auth_name", "created_at", "updated_at", "deleted_at"), 或者直接注释掉这一行,也可以达到同样的效果
            fields = tuple(
                filter(lambda x: isinstance(Author.__dict__[x], sqlalchemy.orm.attributes.InstrumentedAttribute),
                       Author.__dict__)
            )
    
    

    novel_type.py 小说类型表

    # -*- coding:utf-8 -*-
    import sqlalchemy
    from novel.model.base import BaseModel
    from novel import ma, db
    
    
    class NovelType(BaseModel):
        """ 小说分类 """
        __tablename__ = "novel_type"
        id = db.Column(db.Integer, autoincrement=True, primary_key=True)
        type_name = db.Column(db.VARCHAR(20), unique=True, nullable=False, comment="分类名称")
    
        def __init__(self, type_name: str):
            self.type_name = type_name
    
        def __repr__(self):
            return f"id: {self.id} - type_name: {self.type_name}"
    
    
    class NovelTypeSchema(ma.Schema):
        class Meta:
            model = NovelType
            fields = tuple(
                filter(lambda x: isinstance(NovelType.__dict__[x], sqlalchemy.orm.attributes.InstrumentedAttribute),
                       NovelType.__dict__)
            )
      # 序列化外键
        novel_type = ma.Nested(NovelTypeSchema, many=True)
        author = ma.Nested(AuthorSchema, many=True)
    
    

    novel.py 小说表

    # -*- coding:utf-8 -*-
    import sqlalchemy
    from novel.model.base import BaseModel
    from novel import ma, db
    
    
    novel_to_type = db.Table(
        'novel_to_type',  # 中间表 表名
        db.metadata,  # 元类的数据
        db.Column("novel_id", db.BigInteger, db.ForeignKey('novel.id')),
        db.Column("novel_type_id", db.Integer, db.ForeignKey("novel_type.id"))
    )
    
    
    novel_to_author = db.Table(
        'novel_to_author',  # 中间表 表名
        db.metadata,  # 元类的数据
        db.Column("novel_id", db.BigInteger, db.ForeignKey('novel.id')),
        db.Column("author_id", db.BigInteger, db.ForeignKey("author.id"))
    )
    
    
    class Novel(BaseModel):
        __tablename__ = "novel"
        id = db.Column(db.BigInteger, autoincrement=True, primary_key=True)
        novel_title = db.Column(db.VARCHAR(50), unique=True, nullable=False, comment="小说标题")
        cover = db.Column(db.VARCHAR(200), nullable=False, comment="小说封面, 存图片的存储路径")
        hot = db.Column(db.Integer, default=0, comment="热度,点击一次加一")
        novel_type = db.relationship("NovelType", backref='novel_type', secondary=novel_to_type)
        author = db.relationship("Author", backref='novel_author', secondary=novel_to_author)
    
        def __init__(self, novel_title: str, cover: str):
            self.novel_title = novel_title
            self.cover = cover
    
        def __repr__(self):
            return f"id: {self.id} - title: {self.novel_title}"
    
    
    class NovelSchema(ma.Schema):
        class Meta:
            model = Novel
            fields = tuple(
                filter(lambda x: isinstance(Novel.__dict__[x], sqlalchemy.orm.attributes.InstrumentedAttribute),
                       Novel.__dict__)
            )
    
    
    

    方法

    1. 添加小说
          novel = Novel(novel_title="测试小说", cover="暂无")
    
    1. 添加作者
         author1 = Author.query.first()
         novel.author.append(author1)
    
    1. 添加类型
       noty= NovelType.query.first()
       novel.novel_type.append(noty)
     ```
    4. 创建
     ```
       novel.create()  # 这里主要提交事务, db.session.commit(), create() 方法中就是调用提交事务的方法
     ```
    5. 查询
     ```
       novel.author 
       novel.novel_type
     ```
    6. 删除关系
     ```
       1. 获取作者对象 author1
       2. 删除
         novel.remove(author1)
       3. 提交事务
         novel.update()
     ```
  • 相关阅读:
    20200902
    20200808
    20200801
    20191017
    LeetCode #974. Subarray Sums Divisible by K 数组
    LeetCode #532. K-diff Pairs in an Array 数组 哈希 双指针
    LeetCode #234. Palindrome Linked List 链表 栈 链表逆置
    LeetCode #307. Range Sum Query
    LeetCode #45. Jump Game II 数组 贪心
    LeetCode #55. Jump Game 数组 贪心 线性DP 回溯
  • 原文地址:https://www.cnblogs.com/ShanCe/p/15379225.html
Copyright © 2020-2023  润新知