Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support deferring configuration of database to after initialization #69

Open
xiaq opened this issue Apr 25, 2013 · 16 comments
Open

Support deferring configuration of database to after initialization #69

xiaq opened this issue Apr 25, 2013 · 16 comments

Comments

@xiaq
Copy link

xiaq commented Apr 25, 2013

Peewee allows you to do this, by passing None to __init__:

from peewee import *
db = SqliteDatabase(None)
db.init('a.db')

Flask-SQLAlchemy too, by leaving out the app argument:

db = SQLAlchemy()
db.init_app(app)

This is important if you need to create the app in a function instead of in the module global, which makes unit testing easier and is better practice. The complete form for the above example is:

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    return app

Deferring configuration of database still allows you to put db in the module global and use db.Model as base class for ORM models.

@xiaq
Copy link
Author

xiaq commented Apr 25, 2013

I found out the author is precisely that of Peewee, so I needn't have explained this much. :-)

I also identified a problem. A deferred Peewee database still needs to have its type (sqlite/postgre/...) specified. Seems Peewee needs to be enhanced so that a deferred peewee.Database can has its type unknown.

@emosenkis
Copy link

+1. My unit tests run twice as long because they are making a connection to the MySQL database for every simulated request. Using a config that points to an in-memory SQLite database doubles the speed, but it would probably still be much faster if it could be told not to connect until later. Here's the MySQL query log created by running unit tests:

Time                 Id Command    Argument
130728 21:45:13   146 Connect   schdl@localhost on schdl
          146 Query set autocommit=0
          146 Quit  
          147 Connect   schdl@localhost on schdl
          147 Query set autocommit=0
          147 Quit  
          148 Connect   schdl@localhost on schdl
          148 Query set autocommit=0
          148 Quit  
          149 Connect   schdl@localhost on schdl
          149 Query set autocommit=0
          149 Quit  
130728 21:45:14   150 Connect   schdl@localhost on schdl
          150 Query set autocommit=0
          150 Quit  
          151 Connect   schdl@localhost on schdl
          151 Query set autocommit=0
          151 Quit  
          152 Connect   schdl@localhost on schdl
          152 Query set autocommit=0
          152 Quit  
          153 Connect   schdl@localhost on schdl
          153 Query set autocommit=0
          153 Quit  
          154 Connect   schdl@localhost on schdl
          154 Query set autocommit=0
          154 Quit  
          155 Connect   schdl@localhost on schdl
          155 Query set autocommit=0
          155 Quit  
          156 Connect   schdl@localhost on schdl
          156 Query set autocommit=0
          156 Quit  
          157 Connect   schdl@localhost on schdl
          157 Query set autocommit=0
          157 Quit  
          158 Connect   schdl@localhost on schdl
          158 Query set autocommit=0
          158 Quit  
          159 Connect   schdl@localhost on schdl
          159 Query set autocommit=0
          159 Quit

@dmr
Copy link

dmr commented Aug 21, 2013

What is the status of this feature?
Are there any forks which implemented this?
Is there a reason why flask-peewee handles is differently?

@coleifer
Copy link
Owner

coleifer commented Oct 7, 2013

I need to fix this. Will try and get things cleaned up in the next day or two.

@mangrish
Copy link

+1. What's the workaround that people are doing when they use application factories? global instance?

@xiaq
Copy link
Author

xiaq commented Nov 11, 2013

@mangrish Build a proxy class. A bit clumsy, though.

@xiaq
Copy link
Author

xiaq commented Nov 11, 2013

@coleifer Seems this has been implemented with f387f73? It has been some time since I used flask-peewee so I'm not quite sure - have been using raw peewee lately...

It would be nice if the deferred configuration of engine is implemented in the peewee proper though :)

@xiaq
Copy link
Author

xiaq commented Nov 11, 2013

Ah... not quite there yet. You still need to specify the app when initializing the database:

import flask, flask_peewee
app = flask.Flask(__name__)
db = flask_peewee.Database(app)

better make it possible to write this, a la Flask-SQLAlchemy:

import flask, flask_peewee

db = flask_peewee.Database()

def create_app():
    app = flask.Flask(__name__)
    db.init_app(app)
    return db

I'll probably send a PR tonight (UTC+8 here :)...

@xiaq
Copy link
Author

xiaq commented Nov 11, 2013

Ah, harder than I though...

flask_peewee.Database needs to have its Model determined before init_app is called. Which is not possible without determining the database engine...

So better implement deferred engine selection in peewee... :)

@arnuschky
Copy link

Crossposting: I think that this issue is related to #103

It would be great if we could find a way to do configuration independent of a given app, and independent of the usage of flask at all (i.e., only use the peewee models in a separate non-web app).

EDIT: I just realized that github does the pingback automagically for you, thus sorry for the noise.

@lmas
Copy link
Contributor

lmas commented Jan 10, 2014

Anyone found a better, "clean" solution yet?

@arnuschky
Copy link

No. Would be interested in this as well, same use-case as mentioned by @xiaq this time.

Not sure if this can be solved without substantial changes in peewee.

@arnuschky
Copy link

So, I found a (hacky) solution for this. In my app, I use a init_app method as proposed by @xiaq. All my models extend peewee.Model. The code below, when placed in the init_app method, will scan the package for all classes that extend peewee.Model. If it finds such a class, it will monkey-patch the newly created database object into the Model's meta info.

    for _, name, _ in pkgutil.iter_modules(package_path):
        m = importlib.import_module('%s.%s' % (package_name, name))
        for item in dir(m):
            item = getattr(m, item)
            if item.__class__ == Model.__class__:
                item._meta.database = self.database

Code needs of the package path and name, eg., the package with all your models.

Not pretty, but it works. This allows us also to get around get_model_class and some other things from Database()

@coleifer
Copy link
Owner

coleifer commented Jun 1, 2014

Have you guys tried using the peewee Proxy object? That will probably work. Maybe I will fiinally fix this...

@arnuschky
Copy link

Works like a charm. Much nicer than my hack (but I was soo proud! ;) )
Thanks a bunch @coleifer

@kolanos
Copy link

kolanos commented Aug 11, 2014

Is there an example somewhere on how to use the Proxy object with flask-peewee? flask-peewee checks to see if the engine is a subclass of Database, which Proxy is not. It also requires a name parameter which it will attempt to pass to Proxy during initialization. Do I need to override flask-peewee 's Database class?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants