Search code examples
pythonpython-modulepeewee

Modularizing peewee


Suppose I have a couple of simple models residing in food.py:

import peewee as pw

db = pw.SqliteDatabase('food.db')

class BaseModel(pw.Model):
    class Meta:
        database = db

class Taco(BaseModel):
    has_cheese = pw.BooleanField()

class Spaghetti(BaseModel):
    has_meatballs = pw.BooleanField()

db.connect()

# populate with some data if table doesn't exist
from random import random
if not Taco.table_exists():
    db.create_table(Taco)
    for _ in range(10):
        Taco.create( has_cheese = (random() < 0.5) )
    db.commit()
if not Spaghetti.table_exists():
    db.create_table(Spaghetti)
    for _ in range(10):
        Spaghetti.create( has_meatballs = (random() < 0.5) )
    db.commit()

Afterwards, I have food.py and food.db. But let's say the Taco and Spaghetti models are becoming large and complicated, so I'd like to split them into different files. Specifically, I'd like to create a food folder in my PYTHONPATH with the typical hierarchy:

food/
    - __init__.py
    - BaseModel.py
    - Taco.py
    - Spaghetti.py
    - db/
        - food.db

I'd like to put the models into their respective .py files and have an __init__.py file that looks something like this:

import peewee as pw

db = pw.SqliteDatabase('./db/food.db')

from . import BaseModel
from . import Taco
from . import Spaghetti

db.connect()

However, this clearly doesn't work because BaseModel.py can't access db. If it is possible to modularize multiple peewee models in this manner, what is the correct way to do so?


Solution

  • Apparently the trick is to connect to the database in the BaseModel.py file. I will give a full outline of the module contents. Assume that the top-level folder is named food and lives in the PYTHONPATH. Finally assume that food.db exists in food/db/food.db and has been populated (e.g., as in the bottom of the very first code block in the question).

    Here are the module files:

    __init__.py

    from Taco import Taco
    from Spaghetti import Spaghetti
    

    BaseModel.py

    import peewee as pw
    db = pw.SqliteDatabase('/abs/path/to/food/db/food.db')
    
    class BaseModel(pw.Model):
        class Meta:
            database = db
    

    Taco.py

    import peewee as pw
    from BaseModel import BaseModel
    
    class Taco(BaseModel):
        has_cheese = pw.BooleanField()
    

    Spaghetti.py

    import peewee as pw
    from BaseModel import BaseModel
    
    class Spaghetti(BaseModel):
        has_meatballs = pw.BooleanField()
    

    Now, for example, you can write a script (residing outside the module folder, of course), like:

    main.py

    import food
    
    for t in food.Taco.select():
        print "Taco", t.id, ("has" if t.has_cheese else "doesn't have"), "cheese"
    

    produces:

    Taco 1 has cheese
    Taco 2 has cheese
    Taco 3 has cheese
    Taco 4 doesn't have cheese
    Taco 5 doesn't have cheese
    Taco 6 has cheese
    Taco 7 has cheese
    Taco 8 has cheese
    Taco 9 doesn't have cheese
    Taco 10 doesn't have cheese