14
14
import sys
15
15
import time
16
16
import functools
17
+ import warnings
17
18
import sqlalchemy
18
19
from math import ceil
19
20
from functools import partial
24
25
from sqlalchemy import orm , event
25
26
from sqlalchemy .orm .exc import UnmappedClassError
26
27
from sqlalchemy .orm .session import Session as SessionBase
27
- from sqlalchemy .event import listen
28
28
from sqlalchemy .engine .url import make_url
29
29
from sqlalchemy .ext .declarative import declarative_base , DeclarativeMeta
30
30
from flask .ext .sqlalchemy ._compat import iteritems , itervalues , xrange , \
@@ -146,20 +146,20 @@ class SignallingSession(SessionBase):
146
146
147
147
def __init__ (self , db , autocommit = False , autoflush = True , ** options ):
148
148
#: The application that this session belongs to.
149
- self .app = db .get_app ()
149
+ self .app = app = db .get_app ()
150
+ track_modifications = app .config ['SQLALCHEMY_TRACK_MODIFICATIONS' ]
150
151
self ._model_changes = {}
151
- #: A flag that controls whether this session should keep track of
152
- #: model modifications. The default value for this attribute
153
- #: is set from the ``SQLALCHEMY_TRACK_MODIFICATIONS`` config
154
- #: key.
155
- self .emit_modification_signals = \
156
- self .app .config ['SQLALCHEMY_TRACK_MODIFICATIONS' ]
157
152
bind = options .pop ('bind' , None ) or db .engine
158
- SessionBase .__init__ (self , autocommit = autocommit , autoflush = autoflush ,
159
- bind = bind ,
160
- binds = db .get_binds (self .app ), ** options )
161
153
162
- def get_bind (self , mapper , clause = None ):
154
+ if track_modifications is None or track_modifications :
155
+ _SessionSignalEvents .register (self )
156
+
157
+ SessionBase .__init__ (
158
+ self , autocommit = autocommit , autoflush = autoflush ,
159
+ bind = bind , binds = db .get_binds (self .app ), ** options
160
+ )
161
+
162
+ def get_bind (self , mapper = None , clause = None ):
163
163
# mapper is None if someone tries to just get a connection
164
164
if mapper is not None :
165
165
info = getattr (mapper .mapped_table , 'info' , {})
@@ -171,11 +171,17 @@ def get_bind(self, mapper, clause=None):
171
171
172
172
173
173
class _SessionSignalEvents (object ):
174
-
175
- def register (self ):
176
- listen (SessionBase , 'before_commit' , self .session_signal_before_commit )
177
- listen (SessionBase , 'after_commit' , self .session_signal_after_commit )
178
- listen (SessionBase , 'after_rollback' , self .session_signal_after_rollback )
174
+ @classmethod
175
+ def register (cls , session ):
176
+ event .listen (session , 'before_commit' , cls .session_signal_before_commit )
177
+ event .listen (session , 'after_commit' , cls .session_signal_after_commit )
178
+ event .listen (session , 'after_rollback' , cls .session_signal_after_rollback )
179
+
180
+ @classmethod
181
+ def unregister (cls , session ):
182
+ event .remove (session , 'before_commit' , cls .session_signal_before_commit )
183
+ event .remove (session , 'after_commit' , cls .session_signal_after_commit )
184
+ event .remove (session , 'after_rollback' , cls .session_signal_after_rollback )
179
185
180
186
@staticmethod
181
187
def session_signal_before_commit (session ):
@@ -202,33 +208,38 @@ def session_signal_after_rollback(session):
202
208
203
209
204
210
class _MapperSignalEvents (object ):
205
-
206
- def __init__ (self , mapper ):
207
- self .mapper = mapper
208
-
209
- def register (self ):
210
- listen (self .mapper , 'after_delete' , self .mapper_signal_after_delete )
211
- listen (self .mapper , 'after_insert' , self .mapper_signal_after_insert )
212
- listen (self .mapper , 'after_update' , self .mapper_signal_after_update )
213
-
214
- def mapper_signal_after_delete (self , mapper , connection , target ):
215
- self ._record (mapper , target , 'delete' )
216
-
217
- def mapper_signal_after_insert (self , mapper , connection , target ):
218
- self ._record (mapper , target , 'insert' )
219
-
220
- def mapper_signal_after_update (self , mapper , connection , target ):
221
- self ._record (mapper , target , 'update' )
211
+ @classmethod
212
+ def register (cls , mapper ):
213
+ event .listen (mapper , 'after_delete' , cls .mapper_signal_after_delete )
214
+ event .listen (mapper , 'after_insert' , cls .mapper_signal_after_insert )
215
+ event .listen (mapper , 'after_update' , cls .mapper_signal_after_update )
216
+
217
+ @classmethod
218
+ def unregister (cls , mapper ):
219
+ event .remove (mapper , 'after_delete' , cls .mapper_signal_after_delete )
220
+ event .remove (mapper , 'after_insert' , cls .mapper_signal_after_insert )
221
+ event .remove (mapper , 'after_update' , cls .mapper_signal_after_update )
222
+
223
+ @classmethod
224
+ def mapper_signal_after_delete (cls , mapper , connection , target ):
225
+ cls ._record (mapper , target , 'delete' )
226
+
227
+ @classmethod
228
+ def mapper_signal_after_insert (cls , mapper , connection , target ):
229
+ cls ._record (mapper , target , 'insert' )
230
+
231
+ @classmethod
232
+ def mapper_signal_after_update (cls , mapper , connection , target ):
233
+ cls ._record (mapper , target , 'update' )
222
234
223
235
@staticmethod
224
236
def _record (mapper , target , operation ):
225
237
s = orm .object_session (target )
226
- if isinstance (s , SignallingSession ) and s . emit_modification_signals :
238
+ if isinstance (s , SignallingSession ):
227
239
pk = tuple (mapper .primary_key_from_instance (target ))
228
240
s ._model_changes [pk ] = (target , operation )
229
241
230
242
231
-
232
243
class _EngineDebuggingSignalEvents (object ):
233
244
"""Sets up handlers for two events that let us track the execution time of queries."""
234
245
@@ -237,8 +248,8 @@ def __init__(self, engine, import_name):
237
248
self .app_package = import_name
238
249
239
250
def register (self ):
240
- listen (self .engine , 'before_cursor_execute' , self .before_cursor_execute )
241
- listen (self .engine , 'after_cursor_execute' , self .after_cursor_execute )
251
+ event . listen (self .engine , 'before_cursor_execute' , self .before_cursor_execute )
252
+ event . listen (self .engine , 'after_cursor_execute' , self .after_cursor_execute )
242
253
243
254
def before_cursor_execute (self , conn , cursor , statement ,
244
255
parameters , context , executemany ):
@@ -680,32 +691,21 @@ class User(db.Model):
680
691
a custom function which will define the SQLAlchemy session's scoping.
681
692
"""
682
693
683
- def __init__ (self , app = None ,
684
- use_native_unicode = True ,
685
- session_options = None ):
686
- self .use_native_unicode = use_native_unicode
687
-
694
+ def __init__ (self , app = None , use_native_unicode = True , session_options = None ):
688
695
if session_options is None :
689
696
session_options = {}
690
697
691
- session_options .setdefault (
692
- 'scopefunc' , connection_stack .__ident_func__
693
- )
694
-
698
+ session_options .setdefault ('scopefunc' , connection_stack .__ident_func__ )
699
+ self .use_native_unicode = use_native_unicode
695
700
self .session = self .create_scoped_session (session_options )
701
+ self .Query = BaseQuery
696
702
self .Model = self .make_declarative_base ()
697
703
self ._engine_lock = Lock ()
704
+ self .app = app
705
+ _include_sqlalchemy (self )
698
706
699
707
if app is not None :
700
- self .app = app
701
708
self .init_app (app )
702
- else :
703
- self .app = None
704
-
705
- _include_sqlalchemy (self )
706
- _MapperSignalEvents (self .mapper ).register ()
707
- _SessionSignalEvents ().register ()
708
- self .Query = BaseQuery
709
709
710
710
@property
711
711
def metadata (self ):
@@ -753,7 +753,14 @@ def init_app(self, app):
753
753
app .config .setdefault ('SQLALCHEMY_POOL_RECYCLE' , None )
754
754
app .config .setdefault ('SQLALCHEMY_MAX_OVERFLOW' , None )
755
755
app .config .setdefault ('SQLALCHEMY_COMMIT_ON_TEARDOWN' , False )
756
- app .config .setdefault ('SQLALCHEMY_TRACK_MODIFICATIONS' , True )
756
+ track_modifications = app .config .setdefault ('SQLALCHEMY_TRACK_MODIFICATIONS' , None )
757
+
758
+ if track_modifications is None :
759
+ track_modifications = True
760
+ warnings .warn ('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.' )
761
+
762
+ if track_modifications :
763
+ _MapperSignalEvents .register (self .mapper )
757
764
758
765
if not hasattr (app , 'extensions' ):
759
766
app .extensions = {}
0 commit comments