12

I am trying to follow this tutorial from SQLAlchemy on how to create entries in and query a MYSQL database in python. When I try and query the database for the first time following along in their adding new objects section to test whether an object has been added to the database (see large code block below), I get the following error: AttributeError: 'Connection' object has no attribute 'contextual_connect'

I can query the database. For example, if I change the final line of code to our_user = session.query(User).filter_by(name='ed') it successfully returns a query object, but I cannot figure out how to get the object I entered into the database out of this query result.

Similarly, if I try to loop over the results as they suggest in their querying section:

for instance in session.query(User).order_by(User.id):
    print instance.name, instance.fullname

I get the same error. How can I fix this particular error and are there any other tutorials on using MYSQL in Python with SQLAlchemy that you could point me to?

My code:

import MySQLdb
from sqlalchemy import create_engine

db1 = MySQLdb.connect(host="127.0.0.1",
                      user="root",
                      passwd="****",
                      db="mydata")



from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)


ed_user = User('ed', 'Ed Jones', 'edspassword') 

from sqlalchemy.orm import sessionmaker
Session = sessionmaker()
Session.configure(bind=db1)

session = Session()
session.add(ed_user)

our_user = session.query(User).filter_by(name='ed').first()

Update/Working Code:

(1) Change to SQLAlchemy engine as discussed by codeape below.

(2) Remember to create the table: Base.metadata.create_all(engine)

(3) Use the "foolproof" version of the User class from SQLAlchemy's tutorial. Note to SQLAlchemy, we (at least I) feel like a fool and would like you to use to always use the foolproof version in the main body of your tutorial and not as an aside that a busy reader might skip over.

All that yields working code:

import MySQLdb
from sqlalchemy import create_engine

engine = create_engine("mysql://user:password@host/database")

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

from sqlalchemy import Column, Integer, String, Sequence

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(12))

    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)



Base.metadata.create_all(engine)

ed_user = User('ed', 'Ed Jones', 'edspassword') 

from sqlalchemy.orm import sessionmaker
Session = sessionmaker()
Session.configure(bind=engine)

session = Session()
session.add(ed_user)



our_user = session.query(User).filter_by(name='ed').first()

print(our_user is ed_user)
Michael
  • 13,244
  • 23
  • 67
  • 115
  • You don't need the ``import MySQLdb`` statement. – codeape Oct 10 '13 at 09:29
  • I had the same issue but I looped over the `sessionmaker` object. The loop should run over the lowercase `session` in this example. That confused me a bit. `for instance in session.query(User).filter_by(name='ed'): print(our_user is ed_user)` – kkuilla Feb 27 '15 at 15:12

3 Answers3

14

You must bind the session to a SQLAlchemy engine, not directly to a MySQLDb connection object.

engine = create_engine("mysql://user:password@host/dbname")
Session.configure(bind=engine)

(You can remove your db1 variable.)

From the tutorial:

The return value of create_engine() is an instance of Engine, and it represents the core interface to the database, adapted through a dialect that handles the details of the database and DBAPI in use.

See also https://docs.sqlalchemy.org/en/latest/orm/tutorial.html

codeape
  • 97,830
  • 24
  • 159
  • 188
  • I made the change you suggested and I got the error: `ProgrammingError: (ProgrammingError) (1146, "Table 'mydata.users' doesn't exist") 'INSERT INTO users (name, fullname, password) VALUES (%s, %s, %s)' ('ed', 'Ed Jones', 'edspassword')` So I looked at the tutorial and added `Base.metadata.create_all(engine)` to create the table in the database after defining the `User` class. This line yields the following error: `CompileError: (in table 'users', column 'name'): VARCHAR requires a length on dialect mysql` – Michael Oct 09 '13 at 23:15
  • Specify length in the ``String`` constructor: ``name = Column(String(length=100))`` – codeape Oct 09 '13 at 23:37
3
from sqlalchemy.orm import sessionmaker

engine = create_engine("mysql://user:password@host/dbname")
Session = sessionmaker(bind=engine)

session = Session()
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
  • 3
    Thank you for this code snippet, which may provide some immediate help. A proper explanation [would greatly improve](https://meta.stackexchange.com/q/114762) its educational value by showing why this is a good solution to the problem, and would make it more useful to future readers with similar, but not identical, questions. Please edit your answer to add explanation, and give an indication of what limitations and assumptions apply. – GrumpyCrouton Oct 26 '17 at 13:38
-1

It's an issue regarding compatibility just like it was mentioned above. Experiencing the same error you can simply downgrade to another working version that will work until the issue is fixed 1.4.46, based on Github feedback. :)

  • 1
    What feedback are you referring to? SQLA does not accept bare DB-API connections as session binds in any current version. – snakecharmerb Mar 04 '23 at 20:50
  • Did you take a look at the github issue directly? They say specifically that it works in ther version 1.4.46 and it did as I already tested it myself. – Alejandro Ortega Mar 05 '23 at 22:03
  • No, because I don't know which issue you re referring to - can you provide the link please? – snakecharmerb Mar 06 '23 at 06:30
  • As I said, I tried this to bind the session and it worked perfectly. But what she is trying to tackle is different because she is reading Pandas read_sql, but this just to showcase that the current version might not be working properly: https://github.com/pandas-dev/pandas/issues/51015 – Alejandro Ortega Mar 07 '23 at 11:47
  • 1
    That issue is referring to [this problem](https://stackoverflow.com/questions/75309237/read-sql-query-throws-optionengine-object-has-no-attribute-execute-with/75309321#75309321). What the OP is trying to do - pass a DB-API connection as a session bind - is completely different. – snakecharmerb Mar 07 '23 at 19:16
  • I know what he is trying to do and I did it already by changing the version, it worked for me. This is my first contribution and you insist is wrong. This why people tend to lurk more than write solutions. – Alejandro Ortega Mar 13 '23 at 20:24