SQLAlchemy的使用(二)--使用Automap

使用SQLAlchemy四部曲:

首先总结上一章的内容:

  1. 使用create_engine()连接数据库
  2. Base = declarative_base() 生成orm基类,用于创建classes
  3. Base.metadata.create_all(engine) 关联engine使用metadata创建数据库表
  4. 使用 session = Session(engine) 创建一个会话,便于后面对数据库进行实际操作

接下来学习使用automap来提取数据库中已经存在的表的数据,这是一个sqlalchemy.ext.declarative的拓展,能够根据已有的数据库表结构生成映射关系classes


基本使用方法:

类似于生成declarative base class,在这里我们使用automap_base()去生成Base,然后使用Base.prepare()去reflect schema并且产生映射关系



使用MetaData从已有的数据库表生成映射关系:

from sqlalchemy import Metadata
from sqlalchemy.ext.automap import automap_base, name_for_collection_relationship
metadata = MetaData() #先生成我们自己的MetaData对象
metadata.reflect(engine, only=['tbDeployment']) #通过engine将tables反映到metadata上,可以使用only=[]来提取指定的tables
Base = automap_base(metadata=metadata) #从metadata中生成所有的映射关系为Base
Base.prepare()  #设置被映射的类和关系
De = Base.classes.tbDeployment #将表映射到类上
session = Session(engine) #生成一个会话,便于查询
for result in session.query(De).all():
    print(result.DeploymentID)

这里发现一个问题,如果在metadata.reflect中,不加only指定tables,就会报错:property name collision using automap when more than one foreign key refers to the same column.
Base.prepare()其实是使用参数name_for_scalar_relationship和name_for_collection_relationship来自动建立表之间的关系的,所以这里要消除collision,我们需要修改name_for_collection_relationship:

def _name_for_collection_relationship(base, local_cls, referred_cls, constraint):
    if constraint.name:
        return constraint.name.lower()
    # if this didn't work, revert to the default behavior
    return name_for_collection_relationship(base, local_cls, referred_cls, constraint)
...
Base.prepare(name_for_collection_relationship=_name_for_collection_relationship) #下面使用重写的命名规则,用于消除collision

这里根据上面的bug,学习重写命名规则:
下面示例代码描述了automap如何决策产生命名:

import re
import inflect

def camelize_classname(base, tablename, table):
    "Produce a 'camelized' class name, e.g. "
    "'words_and_underscores' -> 'WordsAndUnderscores'"

    return str(tablename[0].upper() + \
            re.sub(r'_([a-z])', lambda m: m.group(1).upper(), tablename[1:]))

_pluralizer = inflect.engine()
def pluralize_collection(base, local_cls, referred_cls, constraint):
    "Produce an 'uncamelized', 'pluralized' class name, e.g. "
    "'SomeTerm' -> 'some_terms'"

    referred_name = referred_cls.__name__
    uncamelized = re.sub(r'[A-Z]',
                         lambda m: "_%s" % m.group(0).lower(),
                         referred_name)[1:]
    pluralized = _pluralizer.plural(uncamelized)
    return pluralized

from sqlalchemy.ext.automap import automap_base

Base = automap_base()

engine = create_engine("sqlite:///mydatabase.db")

Base.prepare(engine, reflect=True,
            classname_for_table=camelize_classname,
            name_for_collection_relationship=pluralize_collection
    )

你可能感兴趣的:(数据库,SQLAlchemy)