首页 > 解决方案 > 如何将 [PRIMARY] 上的 SqlServer 转换为 Sqlalchemy 模型?

问题描述

我在 sqlserver 中有查询,我想使用 sqlalchemy orm 编写一个与之对应的模型。我需要知道如何将 ON [PRIMARY] 转换为 sqlalchemy。

这是我的查询:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[UserModel](
[userid] [nvarchar](255) NULL,
[username] [nvarchar](255) NULL,
[serialnumber] [nvarchar](255) NULL
) ON [PRIMARY]

GO

这是我的模型:

class UserModel(db.Model):
    __tablename__ = 'UserModel'

    userid = Column('userid', Unicode(255))
    username = Column('username', Unicode(255))
    serialnumber = Column('serialnumber', Unicode(255))

任何建议,我将如何实现这一点目前我收到以下错误:

sqlalchemy.exc.ArgumentError: Mapper Mapper|UserModel|UserModel could not assemble any primary key columns for mapped table 'UserModel'

我知道我的模型中没有定义主键,但上面的查询工作正常。所以我想用 sqlalchemy orm 翻译上面的查询。

标签: pythonflasksqlalchemyflask-sqlalchemy

解决方案


您不能使用大多数 ORM 至少直接翻译上述 DDL,因为它们希望 Python 对象对应于数据库中唯一可识别的行。现在,如果您确定例如UserModel.userid唯一标识行,则可以指示 SQLAlchemy 将其用作“主键”:

class UserModel(db.Model):
    __tablename__ = 'UserModel'

    userid = Column('userid', Unicode(255))
    username = Column('username', Unicode(255))
    serialnumber = Column('serialnumber', Unicode(255))

    __mapper_args__ = {
        'primary_key': [userid]
    }

请记住,您对 ORM 撒了谎,任何后果都由您承担。

至于定义表应该存储在 using 中的文件组ON [PRIMARY],您必须稍微扩充一下mssql 方言

from sqlalchemy import Table
from sqlalchemy.schema import CreateTable
from sqlalchemy.ext.compiler import compiles

# Add our custom dialect specific argument
Table.argument_for('mssql', 'on', None)

@compiles(CreateTable, 'mssql')
def compile_create_table(create, compiler, **kw):
    stmt = compiler.visit_create_table(create, **kw)
    filegroup = create.element.kwargs.get('mssql_on')

    if filegroup:
        stmt = stmt.rstrip()  # Prettier output, remove newlines
        filegroup = compiler.preparer.quote(filegroup)
        stmt = f"{stmt} ON {filegroup}\n\n"

    return stmt

并将必要的表参数添加到您的模型定义中:

class UserModel(db.Model):
    ...
    __table_args__ = {
        'mssql_on': 'PRIMARY'
    }

您可以验证生成的 DDL 是否符合要求:

In [4]: print(CreateTable(UserModel.__table__).compile(dialect=engine.dialect))

CREATE TABLE [UserModel] (
        userid NVARCHAR(255) NULL, 
        username NVARCHAR(255) NULL, 
        serialnumber NVARCHAR(255) NULL
) ON [PRIMARY]

请注意,至少根据此 Q/A主要是默认设置,因此ON [PRIMARY]可以省略。


推荐阅读