6

I'm writing a "multi tenant" application. It's going to be hosted on different subdomains, and based on which subdomain it's hosted, it should use a different database.

Is it possible to define, in execution time, which database peewee should be using? If I were using django, I'd just write a router that takes care of it, but I haven't found anything similar on peewee.

Am I missing something?

Thanks!

PS: A hack like this How to query several similar databases using Peewee?, where you need to know beforehand which class to invoke wouldn't work fine in my scenario

Community
  • 1
  • 1
g3rv4
  • 19,750
  • 4
  • 36
  • 58
  • Can you do this in flask instead of peewee? For example, using [application factories](http://flask.pocoo.org/docs/0.10/patterns/appfactories/) with [application dispatchers](http://flask.pocoo.org/docs/0.10/patterns/appdispatch/#dispatch-by-subdomain) – Ngenator Dec 22 '14 at 20:37
  • @Ngenator that could certainly work :) please put it as an answer so that I can at least upvote it... I like it! – g3rv4 Dec 22 '14 at 20:39

3 Answers3

4

You can also take a look at the ReadSlave module for an example of changing databases at run-time.

Code:

class ReadSlaveModel(Model):
    @classmethod
    def _get_read_database(cls):
        if not getattr(cls._meta, 'read_slaves', None):
            return cls._meta.database
        current_idx = getattr(cls, '_read_slave_idx', -1)
        cls._read_slave_idx = (current_idx + 1) % len(cls._meta.read_slaves)
        return cls._meta.read_slaves[cls._read_slave_idx]

    @classmethod
    def select(cls, *args, **kwargs):
        query = super(ReadSlaveModel, cls).select(*args, **kwargs)
        query.database = cls._get_read_database()
        return query

    @classmethod
    def raw(cls, *args, **kwargs):
        query = super(ReadSlaveModel, cls).raw(*args, **kwargs)
        if query._sql.lower().startswith('select'):
            query.database = cls._get_read_database()
        return query
gmauch
  • 1,316
  • 4
  • 25
  • 39
coleifer
  • 24,887
  • 6
  • 60
  • 75
  • 1
    Thanks for that @coleifer! Questions: would this affect only selects? also... is there a way to define the database that all my models use in a separate place instead of the model? Ideally, it would be a config I apply (using something like dependency injection) and that would make all my models use that database. In django's ORM, that would be done at a router level. – g3rv4 Dec 23 '14 at 13:08
  • Yeah, it was just meant as an example of how I'd done something similar. – coleifer Dec 23 '14 at 15:04
3

Peewee provides also the possibility to use DB Proxy, where you can switch the DB easily. Peewee Documentation

database_proxy = Proxy()  # Create a proxy for our db.

class BaseModel(Model):
    class Meta:
        database = database_proxy  # Use proxy for our DB.

class User(BaseModel):
    username = CharField()

# Based on configuration, use a different database.
if app.config['DEBUG']:
    database = SqliteDatabase('local.db')
elif app.config['TESTING']:
    database = SqliteDatabase(':memory:')
else:
    database = PostgresqlDatabase('mega_production_db')

# Configure our proxy to use the db we specified in config.
database_proxy.initialize(database)
Roman S.
  • 1,206
  • 15
  • 24
0

Instead of handling this in peewee, you could handle the db selection in flask using application factories with application dispatchers

Ngenator
  • 10,909
  • 4
  • 41
  • 46