2017-02-17 2 views
1

Lorsque vous tentez d'ajouter un Widget au (SQLite) DB, et l'associer à un déjà existant User tel que défini ci-dessous:Associer un objet SQLAlchemy avec un enregistrement existant (Python/Pyramid)

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) 

Je reçois l'erreur 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>)]

Je peux directement ajouter la valeur pour user.name, mais cela interrompt la relation. Par exemple, widget.user.name donnerait une erreur comme 'str' object has no attribute 'repository'

Répondre

0

Votre classe Widget a un attribut user qui est de type Text, qui est essentiellement un attribut de chaîne sur le côté Python des choses et est quelque chose comme la colonne VARCHAR dans la base de données. Vous ne pouvez pas affecter un objet Utilisateur à un attribut qui s'attend à être une chaîne.

Il semble également que vous essayez de créer une relation de clé étrangère en utilisant la colonne users.name - ceci est certainement possible, mais est tout à fait inhabituel étant donné que vous avez également une clé primaire de remplacement sur votre modèle User.

Vous devez créer un relationship entre vos deux classes ORM:

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') 

alors vous serez en mesure de faire une des opérations suivantes:

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 

Vous pouvez également configurer les choses de l'autre côté, comme suggéré par @metmirr, mais l'ingrédient magique ici est sqlalchemy.orm.relationship, pas le backref que vous pouvez choisir ou non.

0

L'attribut backref fera ce dont vous avez besoin. Ajouter une relation à la classe utilisateur comme suit:

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

Avec backref attribut sqlalchemy ajoutera une référence à votre classe Widget qui pointera objet utilisateur:

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