SqlAlchemy эквивалент строки соединения podbcc с использованием FreeTDS
Следующие работы:
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:[email protected]:1433/mydb?driver=FreeTDS& odbc_options='TDS_Version=8.0'").connect()
Сообщение об ошибке выше:
DBAPIError: (Ошибка) ('08001', '[08001] [unixODBC] [FreeTDS] [SQL Server] Не удается подключиться к источнику данных (0) (SQLDriverConnectW)') None None
Кто-нибудь может указать мне в правильном направлении? Есть ли способ, которым я могу просто сказать sqlalchemy передать конкретную строку подключения через pyodbc?
Обратите внимание: Я хочу сохранить этот DSN-меньше.
Ответы
Ответ 1
Пример @Singletoned не будет работать для меня с SQLAlchemy 0.7.2. Из документов SQLAlchemy для подключения к SQL Server:
If you require a connection string that is outside the options presented above, use the odbc_connect keyword to pass in a urlencoded connection string. What gets passed in will be urldecoded and passed directly.
Поэтому, чтобы это работало, я использовал:
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
должен быть изменен на эту строку в python3:
quoted = urllib.parse.quote_plus
Ответ 2
Я по-прежнему заинтересован в том, чтобы сделать это в одной строке в 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))
Ответ 3
Это работает:
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.
Update:
Извините, я забыл, что 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()
Ответ 4
Внутренне "my.db.server: 1433" передается как часть строки подключения, например SERVER=my.db.server:1433;
.
К сожалению, unixODBC/FreeTDS не будет принимать порт в бит SERVER. Вместо этого он хочет SERVER=my.db.server;PORT=1433;
Чтобы использовать синтаксис sqlalchemy для строки подключения, вы должны указать порт в качестве параметра.
sqlalchemy.create_engine("mssql://myuser:[email protected]:1433/mydb?driver=FreeTDS& odbc_options='TDS_Version=8.0'").connect()
становится:
sqlalchemy.create_engine("mssql://myuser:[email protected]/mydb?driver=FreeTDS&port=1433& odbc_options='TDS_Version=8.0'").connect()
Ответ 5
Чтобы передать различные параметры вашей функции соединения, это похоже на то, что строка формата может делать то, что вы хотите:
def connect(server, dbname, user, pass):
pyodbc.connect('DRIVER={FreeTDS};Server=%s;Database=%s;UID=%s;PWD=%s;TDS_Version=8.0;Port=1433;' % (server, dbname, user, pass))
И вы тогда назовёте его чем-то вроде:
connect('myserver', 'mydatabase', 'myuser', 'mypass')
Дополнительная информация о строках формата приведена здесь: http://docs.python.org/library/string.html#formatstrings