lundi 6 avril 2020

What's a design pattern for initializing a Peewee model class with db connection in Python?

I'm using Peewee as ORM provider for my Python 3.x projects. As suggested in their Quickstart page I go for the simple design where I define a model.py module containing all my model definitions e.g.

-------------------- model.py ---------------------
from peewee import *
from playhouse.db_url import connect

db = connect('sqlite:///some/folder/people.db')

class BaseModel(Model):
    class Meta:
        database = db # uses the "people.db" database

class Person(BaseModel):
    name = CharField()
    birthday = DateField()

----------------------------------------------------

basically db has module scope and it's hard-coded. I will have multiple separate entry point main CLI or scripts that would like to set this db differently e.g. UIT, UT and PROD different databases.

As I see it I have the following possible alternatives to "inject" the db connection instance dynamically to my model:

  1. Use the process environment as a session to put and read the connection URL i.e. os.environ['DATABASE'] = 'sqlite:///some/folder/people.db'. This solution is ok-ish but seems a bit hacky to me abusing the env as an application session.
  2. Wrap the model creation code (for all model classes) into a function and pass the db as parameter. This is cleaner but then I lose the module class import facility i.e. I can no longer do from model import Person.
  3. Have all model classes take the db as a constructor argument, even cleaner than the previous one but incurs into a lot of error-prone boilerplate code as all model classes would now need to define a constructor and pass the db connection instance along the model tree.
  4. Make db a class attribute of BaseModel which can be set from the scripts then I don't know how it can be accessed from the nested class Meta.

For example:

 class BaseModel(Model):
     db = connect('sqlite:///some/folder/people.db') # default        

     class Meta:
         database = db # doesn't see the enclosing's class attribute db 

Aucun commentaire:

Enregistrer un commentaire