Avoiding circular imports¶
How Python imports work¶
When Python imports a file, it evaluates it from top to bottom.
With ForeignKey
columns we
sometimes have to reference tables lower down in the file (which haven’t been
evaluated yet).
The solutions are:
Try and move the referenced table to a different Python file.
Import Table
definitions as early as possible¶
In the entrypoint to your app, at the top of the file, it’s recommended to import your tables.
# main.py
from my_app.tables import Manager, Band
This ensures that the tables are imported, and setup correctly.
Keep table files focused¶
You should try and keep your tables.py
files pretty focused (i.e.
just contain your Table
definitions).
If you have lots of logic alongside your Table
definitions, it might cause
your LazyTableReference
references to evaluate too soon (causing circular
import errors). An example of this is with
create_pydantic_model
:
# tables.py
from piccolo.columns import ForeignKey, Varchar
from piccolo.table import Table
from piccolo.utils.pydantic import create_pydantic_model
class Band(Table):
name = Varchar()
# This automatically gets converted into a LazyTableReference, because a
# string is passed in:
manager = ForeignKey("Manager")
# This is not recommended, as it will cause the LazyTableReference to be
# evaluated before Manager has imported.
# Instead, move this to a separate file, or below Manager.
BandModel = create_pydantic_model(Band)
class Manager(Table):
name = Varchar()
Simplify your schema if possible¶
Even with LazyTableReference
,
you may run into some problems if your schema is really complicated.
An example is when you have two tables, and they have foreign keys to each other.
class Band(Table):
name = Varchar()
manager = ForeignKey("Manager")
class Manager(Table):
name = Varchar()
favourite_band = ForeignKey(Band)
Piccolo should be able to create these tables, and query them. However, some Piccolo tooling may struggle - for example when loading fixtures.
A joining table can help in these situations:
class Band(Table):
name = Varchar()
manager = ForeignKey("Manager")
class Manager(Table):
name = Varchar()
class ManagerFavouriteBand(Table):
manager = ForeignKey(Manager, unique=True)
band = ForeignKey(Band)