Search code examples
pythonpeewee

Peewee circular foreign key dependencies exception


I'm trying to replicate Peewee example app using circular dependences as explained in the docs, despite the creator clearly states this is usually a bad idea. This is the code mainly copied from the docs:

from peewee import *

db = SqliteDatabase(None)

class BaseModel(Model):

class Meta:
    database = db

class User(BaseModel):
    username = CharField()
    # Tweet has not been defined yet so use the deferred reference.
    favorite_tweet = DeferredForeignKey('Tweet', null=True)

class Tweet(BaseModel):
    message = TextField()
    user = ForeignKeyField(User, backref='tweets')


db.init('twitter.db')
db.create_tables([User, Tweet])
User._schema.create_foreign_key(User.favorite_tweet) #Error
db.close()

I'm getting the an exception in the line commented with #Error. This line is needed, as explained in the docs:

When you call create_table we will again encounter the same issue. For this reason peewee will not automatically create a foreign key constraint for any deferred foreign keys.

To create the tables and the foreign-key constraint, you can use the SchemaManager.create_foreign_key() method to create the constraint after creating the tables.

This is the exception I get using Python 3.5.2:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2653, in execute_sql
    cursor.execute(sql, params or ())
sqlite3.OperationalError: near "CONSTRAINT": syntax error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test3.py", line 23, in <module>
    User._schema.create_foreign_key(User.favorite_tweet)
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 4930, in create_foreign_key
    self.database.execute(self._create_foreign_key(field))
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2666, in execute
    return self.execute_sql(sql, params, commit=commit)
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2660, in execute_sql
    self.commit()
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2451, in __exit__    reraise(new_type, new_type(*exc_args), traceback)
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 178, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2653, in execute_sql
    cursor.execute(sql, params or ())
peewee.OperationalError: near "CONSTRAINT": syntax error

Solution

  • Sqlite does not support ALTER TABLE ADD CONSTRAINT -- so when you're using Sqlite you should omit the additional call to create_foreign_key().

    There is a clear NOTE in the docs that says:

    Because SQLite has limited support for altering tables, foreign-key constraints cannot be added to a table after it has been created.