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 raw SQL Alchemy #110

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/panels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,14 @@ Shows SQL queries run during the current request.
For additional details on query recording see the
:py:func:`~flask_sqlalchemy.get_debug_queries` documentation.

If you use raw sqlalchemy with `Flask-SQLAlchemy-Session`_ pass the engine
in like DebugToolbarExtension(app, sqlalchemy_engine=engine)


.. image:: _static/screenshot-sqlalchemy-panel.png

.. _Flask-SQLAlchemy: http://flask-sqlalchemy.pocoo.org/

.. _Flask-SQLAlchemy-Session: https://pypi.python.org/pypi/Flask-SQLAlchemy-Session

Logging
-------
Expand Down
18 changes: 15 additions & 3 deletions flask_debugtoolbar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ class DebugToolbarExtension(object):

_redirect_codes = [301, 302, 303, 304]

def __init__(self, app=None):
def __init__(self, app=None, sqlalchemy_engine=None):
self.app = app
self.engine = sqlalchemy_engine
self.debug_toolbars = {}

# Configure jinja for the internal templates and add url rules
Expand Down Expand Up @@ -80,8 +81,19 @@ def init_app(self, app):

app.add_url_rule('/_debug_toolbar/static/<path:filename>',
'_debug_toolbar.static', self.send_static_file)

app.register_blueprint(module, url_prefix='/_debug_toolbar/views')
if self.engine:
# use 'internal' API from flask_sqlalchemy to install events.
# maybe re-implement this for flask-debugtoolbar
from flask_sqlalchemy import _EngineDebuggingSignalEvents, _record_queries
if _record_queries(app):
_EngineDebuggingSignalEvents(
engine=self.engine,
import_name=app.import_name).register()

app.register_blueprint(
module,
url_prefix='/_debug_toolbar/views',
sqlalchemy_engine=self.engine)

def _default_config(self, app):
return {
Expand Down
21 changes: 19 additions & 2 deletions flask_debugtoolbar/panels/sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
from flask_debugtoolbar.utils import format_fname, format_sql
import itsdangerous

_engine = None

@module.record_once
def store_engine(state):
global _engine
_engine = state.options.get('sqlalchemy_engine')


def get_engine():
if _engine is not None:
return _engine
elif sqlalchemy_available:
return SQLAlchemy().get_engine(current_app)

_ = lambda x: x

Expand Down Expand Up @@ -60,7 +73,7 @@ def recording_enabled():

def is_available():
return (json_available and sqlalchemy_available
and extension_used() and recording_enabled())
and (extension_used() or (_engine is not None)) and recording_enabled())


def get_queries():
Expand Down Expand Up @@ -110,6 +123,7 @@ def content(self):
return self.render('panels/sqlalchemy_error.html', {
'json_available': json_available,
'sqlalchemy_available': sqlalchemy_available,
'sqlalchemy_engine_available': _engine is not None,
'extension_used': extension_used(),
'recording_enabled': recording_enabled(),
})
Expand All @@ -125,6 +139,7 @@ def content(self):
})
return self.render('panels/sqlalchemy.html', {'queries': data})


# Panel views


Expand All @@ -133,7 +148,9 @@ def content(self):
defaults=dict(explain=True))
def sql_select(explain=False):
statement, params = load_query(request.args['query'])
engine = SQLAlchemy().get_engine(current_app)
engine = get_engine()
if engine is None:
return 'No SQLAlchemy engine has been configured.'

if explain:
if engine.driver == 'pysqlite':
Expand Down
35 changes: 35 additions & 0 deletions test/basic_app_plain_sqlalchemy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from flask import Flask, render_template
from flask_debugtoolbar import DebugToolbarExtension
from sqlalchemy import Column, Integer, create_engine
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base

app = Flask('basic_app_plain_sqlalchemy')
app.debug = True
app.config['SECRET_KEY'] = 'abc123'

# make sure these are printable in the config panel
app.config['BYTES_VALUE'] = b'\x00'
app.config['UNICODE_VALUE'] = u'\uffff'


engine = create_engine('sqlite://')
toolbar = DebugToolbarExtension(app, sqlalchemy_engine=engine)


Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)


@app.route('/')
def index():
Base.metadata.create_all(engine)
session = Session(engine)
session.query(Foo).filter_by(id=1).all()
return render_template('basic_app.html')


if __name__ == '__main__':
app.run()