Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Foreign Key to Same Table in sqlalchemy

I have a MySQL table, defined in sqlalchemy with following structure:

class User(Base):
    __tablename__ = 'user'
    __table_args__ = {'mysql_charset': 'utf8', 'mysql_engine': 'InnoDB'}
    id = Column(Integer, primary_key=True)
    handle = Column(String(250), nullable=False)
    owned = Column(Boolean(), default=False)
    owner_id = Column(Integer, ForeignKey("user.id"), nullable=True, default=null )
    current_price = Column(Integer, nullable=False, default=1)
    balance = Column(Integer, nullable=False, default=0)

I want a relationship so that the owner_id can either be null, OR if it is set it must refer to a valid user.id, in the same table.

I don't quite understand the sqlalchemy relationship stuff well enough to be able to do it. The special stuff at the top of this page http://docs.sqlalchemy.org/en/latest/orm/relationship_persistence.html seems to suggest that it's possible, but I can't figure it out.

I want to then be able to either add Users like:

u1 = User(handle="bob")
u2 = User(handle="jim", owner=u1)

Thanks for any help!

I should add that sqlalchemy has no problem doing the CREATE TABLE with the correct FOREIGN KEY constraint, and I can manually INSERT data into the table that obeys the rules as I want them in MySQL, it's only using the sqlalchemy model that fails.

EDIT: SOLVED

The 'default=null' on owner_id was causing the problem for some reason. Helpful docs were here: http://docs.sqlalchemy.org/en/rel_1_0/orm/self_referential.html and code example from that page here: http://docs.sqlalchemy.org/en/rel_1_0/orm/examples.html#examples-adjacencylist

For the google spider bots, errors that I got during this process were:

sqlalchemy.exc.IntegrityError: (_mysql_exceptions.IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails (`twitfriends`.`tree`, CONSTRAINT `tree_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `tree` (`id`))') [SQL: u'INSERT INTO tree (parent_id, name) VALUES (%s, %s)'] [parameters: (<sqlalchemy.sql.elements.Null object at 0x7fe7e8c468d0>, 'rootnode')]

And

ArgumentError: Node.next and back-reference Node.prev are both of the same direction <symbol 'ONETOMANY>.  Did you mean to set remote_side on the many-to-one side ?
like image 232
mozboz Avatar asked Jan 15 '16 01:01

mozboz


People also ask

What is foreign key in SQLAlchemy?

A foreign key in SQL is a table-level construct that constrains one or more columns in that table to only allow values that are present in a different set of columns, typically but not always located on a different table.

What is back populates in SQLAlchemy?

Using back_populates is nice if you want to define the relationships on every class, so it's easy to see all the fields just be glancing at the model class, instead of having to look at other classes that define fields via backref.

How does SQLAlchemy define foreign key in flask?

First you need to supply a Primary Key for each model. Then you need to define one Foreign Key which refers to the Primary Key of the other model. Now you can define a relationship with a backref that allows direct access to the related model. In this case, the following 2 lines should look like this: request_id = db.


1 Answers

Since there is only one foreign key for User, I would expect sqlalchemy to automatically figure out the join conditions. You can also add a backref so you can get the other side of the relationship.

class User(Base):
    ...
    owner = relationship('User', remote_side=['id'], backref='owned_users')

Docs

Ex.

u1 = User(handle="bob")
u2 = User(handle="jim", owner=u1)
print u2.owned_users[0] == u1
# True
like image 139
Brendan Abel Avatar answered Oct 08 '22 17:10

Brendan Abel