Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PonyORM - multiple model files

Tags:

python

ponyorm

I want to separate my model classes into separate files in a models directory. I would like to have a separate file for:

  • general (authentication and global classes/tables)
  • requisitions (tables used for requisitions)
  • workorders (tables used for workorders)
  • sales_orders (tables used for sales orders)
  • ...etc

I'm not sure how to structure my project to make that happen.

I've tried putting my main imports into init.py in the directory and them importing those into the individual model files, but I don't know where to put my db.generate_mapping() so that all classes are available. I'm guessing this is a best practice for a large application. I've got about 150 tables in my app at this point.

Any help/pointers would be appreciated.

like image 938
Jim Steil Avatar asked Jul 30 '18 20:07

Jim Steil


1 Answers

You can use the following project structure:

# /myproject
#     settings.py
#     main.py
#     /models
#         __init__.py
#         base.py
#         requisitions.py
#         workorders.py
#         sales_orders.py

settings.py is a file with database settings:

# settings.py
db_params = {'provider': 'sqlite', 'filename': ':memory:'}

main.py is a file when you start application. You put db.generate_mapping here:

# main.py
from pony import orm
import settings
from models import db
from your_favorite_web_framework import App

# orm.set_sql_degug(True)
db.bind(**settings.db_params)
db.generate_mapping(create_tables=True)

with orm.db_session:
    orm.select(u for u in db.User).show()

if __name__ == '__main__':
    app = App()
    app.run()

Note that it is not necessary to implicitly import all models, as they are accessible as attributes of db object (like db.User)

You can put db object in base.py (or general.py), where you define your core models:

# base.py
from pony import orm

db = orm.Database()

class User(db.Entity):
    name = Required(str)
    orders = Set('Order')

Note that in User model I can refer to Order model defined in another module. You can also write it as

    orders = Set(lambda: db.Order)

Unfortunately, IDEs like PyCharm at this moment cannot recognize that db.Order refers to specific Order class. You can import and use Order class directly, but in some cases it will lead to problem with cyclic imports.

In other model files you import db from .base:

# workorders.py
from pony import orm
from .base import db

class Order(db.Entity):
    description = Optional(str)
    user = Required('User')

In /models/__init__.py you import all modules to ensure that all models classes are defined before generate_mapping is called:

# /models/__init__.py
from .base import db
from . import workorders
...

And then you can write

from models import db

And access models as db attributes like db.User, db.Order, etc.

If you want to refer models directly in your code instead of accessing them as db attributes, you can import all models in __init__.py:

# /models/__init__.py
from .base import db, User
from .workorders import Order
...

And then you can import model classes as:

from models import db, User, Order, ...
like image 97
Alexander Kozlovsky Avatar answered Nov 07 '22 17:11

Alexander Kozlovsky