简体   繁体   中英

Associating an SQLAlchemy object with an existing record (Python/Pyramid)

When attempting to add a Widget to the (SQLite) DB, and associate it with an already existing User as defined below:

class Widget(Base):
    __tablename__ = 'widgets'
    id = Column(Integer, primary_key=True)
    kind = Column(Text)
    user = Column(Text, ForeignKey('users.name'))

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(Text, unique=True)

@view_config(route_name='name', renderer='json')
def add_widget(request):
    user_name = 'foo'
    user = request.dbsession.query(User).filter_by(name=user_name).one()
    new_widget = Widget(kind='bar', user=user)

I receive the error sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 1 - probably unsupported type. [SQL: 'INSERT INTO widgets (kind, user) VALUES (?, ?)'] [parameters: ('bar', <example.models.user.User object at 0x1050bdghd>)] sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 1 - probably unsupported type. [SQL: 'INSERT INTO widgets (kind, user) VALUES (?, ?)'] [parameters: ('bar', <example.models.user.User object at 0x1050bdghd>)]

I can add the value for user.name directly, but this breaks the relationship. For example, widget.user.name would give an error like 'str' object has no attribute 'repository'

The backref attribute will do what you need. Add a relationship to user class as follows:

class User(Base):
    ...
    widget = sqlalchemy.orm.relationship('Widget', backref='user')

With backref attribute sqlalchemy will add a reference to your Widget class which will point User object:

user = request.dbsession.query(User).filter_by(name=user_name).one()
new_widget = Widget(kind='bar', user=user)

Your Widget class has a user attribute which is of type Text , which is basically a string attribute on the Python side of things and is something like VARCHAR column in the database. You can not assign a User object to an attribute which expects to be a string.

It also appears that you're trying to create a foreign key relationship using the users.name column - this is certainly possible but is quite unusual considering you also have a surrogate primary key on your User model.

You need to set up a relationship between your two ORM classes:

class Widget(Base):
    __tablename__ = 'widgets'
    id = Column(Integer, primary_key=True)
    kind = Column(Text)
    user_id = Column(Integer, ForeignKey('users.id'))
    user = sqlalchemy.orm.relationship('User', backref='widgets')

then you'll be able to do any of the following:

new_widget = Widget(kind='bar', user=user)
new_widget = Widget(kind='bar', user_id=user.id)
user.widgets.append(Widget(kind='bar'))
new_widget.user_id = user.id
new_widget.user = user

You can also set up things from the other end as @metmirr suggested, but the magic ingredient here is sqlalchemy.orm.relationship , not the backref which you may or may not choose to have.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM