使用FreeTDS的SqlAlchemy等效pyodbc连接字符串

28 投票
5 回答
50454 浏览
提问于 2025-04-16 08:48

下面这个代码可以正常运行:

import pyodbc
pyodbc.connect('DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;')

而下面这个代码就会出错:

import sqlalchemy
sqlalchemy.create_engine("mssql://myuser:mypwd@my.db.server:1433/mydb?driver=FreeTDS& odbc_options='TDS_Version=8.0'").connect()

上面的错误信息是:

DBAPIError: (Error) ('08001', '[08001] [unixODBC][FreeTDS][SQL Server]无法连接到数据源 (0) (SQLDriverConnectW)') None None

有没有人能给我指个方向?我能不能简单地告诉sqlalchemy把一个特定的连接字符串传给pyodbc?

请注意:我想保持这个连接不使用DSN。

5 个回答

5

这个方法可以用:

import sqlalchemy
sqlalchemy.create_engine("DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;").connect()

在这种格式下,SQLAlchemy 会忽略连接字符串,直接把它传给 pyodbc。

更新:

抱歉,我忘了说,uri 需要进行 URL 编码,所以,下面这个方法可以用:

import sqlalchemy
sqlalchemy.create_engine("DRIVER%3D%7BFreeTDS%7D%3BServer%3Dmy.db.server%3BDatabase%3Dmydb%3BUID%3Dmyuser%3BPWD%3Dmypwd%3BTDS_Version%3D8.0%3BPort%3D1433%3B").connect()
28

我还是想找到一种方法,可以在sqlalchemy的create_engine语句中用一行代码实现这个功能,不过我找到了一种替代方法,具体可以在这里查看

import pyodbc, sqlalchemy

def connect():
    pyodbc.connect('DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;')

sqlalchemy.create_engine('mssql://', creator=connect)

更新:这是我在自己评论中提到的一个问题,关于无法将参数传递给连接字符串。如果你需要在运行时动态连接到不同的数据库,下面的方法是一个通用的解决方案。我只传递了数据库名称作为参数,但根据需要也可以轻松使用其他参数:

import pyodbc
import os

class Creator:
    def __init__(self, db_name='MyDB'):
        """Initialization procedure to receive the database name"""
        self.db_name = db_name

    def __call__(self):
        """Defines a custom creator to be passed to sqlalchemy.create_engine
           http://stackoverflow.com/questions/111234/what-is-a-callable-in-python#111255"""
        if os.name == 'posix':
            return pyodbc.connect('DRIVER={FreeTDS};'
                                  'Server=my.db.server;'
                                  'Database=%s;'
                                  'UID=myuser;'
                                  'PWD=mypassword;'
                                  'TDS_Version=8.0;'
                                  'Port=1433;' % self.db_name)
        elif os.name == 'nt':
            # use development environment
            return pyodbc.connect('DRIVER={SQL Server};'
                                  'Server=127.0.0.1;'
                                  'Database=%s_Dev;'
                                  'UID=user;'
                                  'PWD=;'
                                  'Trusted_Connection=Yes;'
                                  'Port=1433;' % self.db_name)

def en(db_name):
    """Returns a sql_alchemy engine"""
    return sqlalchemy.create_engine('mssql://', creator=Creator(db_name))
45

@Singletoned 提供的例子在我使用 SQLAlchemy 0.7.2 时并不适用。从 SQLAlchemy 连接 SQL Server 的文档 中可以看到:

如果你需要一个不在上述选项中的连接字符串,可以使用 odbc_connect 关键字来传入一个经过 URL 编码的连接字符串。传入的内容会被解码后直接使用。

所以为了让它工作,我用了:

import urllib
quoted = urllib.quote_plus('DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;')
sqlalchemy.create_engine('mssql+pyodbc:///?odbc_connect={}'.format(quoted))

这同样适用于 Sybase。

注意:在 Python 3 中,urllib 模块被拆分成了几个部分并重新命名。因此,在 Python 2.7 中的这一行:

quoted = urllib.quote_plus

需要改成 Python 3 中的这一行:

quoted = urllib.parse.quote_plus

撰写回答