python - mssql - sqlalchemy database support
Equivalente de SqlAlchemy de la cadena de conexión pyodbc usando FreeTDS (5)
Los siguientes trabajos:
import pyodbc
pyodbc.connect(''DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;'')
Lo siguiente falla:
import sqlalchemy
sqlalchemy.create_engine("mssql://myuser:[email protected]:1433/mydb?driver=FreeTDS& odbc_options=''TDS_Version=8.0''").connect()
El mensaje de error de arriba es:
DBAPIError: (Error) (''08001'', ''[08001] [unixODBC] [FreeTDS] [SQL Server] No se puede conectar con la fuente de datos (0) (SQLDriverConnectW)'') Ninguna Ninguna
¿Puede alguien indicarme el camino correcto? ¿Hay alguna manera de que le diga simplemente a sqlalchemy que pase una cadena de conexión específica a través de pyodbc?
Tenga en cuenta: Quiero mantener este DSN-menos.
El ejemplo de @Singletoned no funcionaría para mí con SQLAlchemy 0.7.2. De los documentos de SQLAlchemy para conectarse a 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.
Así que para hacerlo funcionar utilicé:
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))
Esto debería aplicarse a Sybase también.
NOTA: En Python 3, el módulo urllib se ha dividido en partes y se le ha cambiado el nombre. Así, esta línea en python 2.7:
quoted = urllib.quote_plus
tiene que ser cambiado a esta línea en python3:
quoted = urllib.parse.quote_plus
Esto funciona:
import sqlalchemy
sqlalchemy.create_engine("DRIVER={FreeTDS};Server=my.db.server;Database=mydb;UID=myuser;PWD=mypwd;TDS_Version=8.0;Port=1433;").connect()
En ese formato, SQLAlchemy simplemente ignora la cadena de conexión y la pasa directamente a pyodbc.
Actualizar:
Lo siento, olvidé que el uri tiene que estar codificado con url, por lo tanto, los siguientes trabajos:
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()
Internamente, "my.db.server: 1433" se pasa como parte de una cadena de conexión como SERVER=my.db.server:1433;
.
Desafortunadamente, unixODBC / FreeTDS no aceptará un puerto en el bit SERVIDOR. En su lugar, quiere SERVER=my.db.server;PORT=1433;
Para usar la sintaxis de sqlalchemy para una cadena de conexión, debe especificar el puerto como parámetro.
sqlalchemy.create_engine("mssql://myuser:[email protected]:1433/mydb?driver=FreeTDS& odbc_options=''TDS_Version=8.0''").connect()
se convierte en:
sqlalchemy.create_engine("mssql://myuser:[email protected]/mydb?driver=FreeTDS&port=1433& odbc_options=''TDS_Version=8.0''").connect()
Para pasar varios parámetros a su función de conexión, parece que la cadena de formato podría hacer lo que usted desea:
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))
Y luego lo llamarías con algo como:
connect(''myserver'', ''mydatabase'', ''myuser'', ''mypass'')
Más información sobre cadenas de formato está aquí: http://docs.python.org/library/string.html#formatstrings
Todavía estoy interesado en una forma de hacer esto en una línea dentro de la declaración create_engine
, pero encontré la siguiente solución detallada aquí :
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)
ACTUALIZACIÓN : aborda una inquietud que planteé en mi propio comentario acerca de no poder pasar argumentos a la cadena de conexión. La siguiente es una solución general si necesita conectarse dinámicamente a diferentes bases de datos en tiempo de ejecución. Solo paso el nombre de la base de datos como parámetro, pero se podrían usar parámetros adicionales según sea necesario:
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://.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))