[Python-modules-commits] [flask-sqlalchemy] 01/04: Import flask-sqlalchemy_2.1.orig.tar.gz
Orestis Ioannou
oorestisime-guest at moszumanska.debian.org
Tue Feb 23 09:32:34 UTC 2016
This is an automated email from the git hooks/post-receive script.
oorestisime-guest pushed a commit to branch master
in repository flask-sqlalchemy.
commit e9968569ed80011b3477f96fcbced951c1223f3c
Author: Orestis Ioannou <orestis at oioannou.com>
Date: Thu Feb 18 05:32:35 2016 +0100
Import flask-sqlalchemy_2.1.orig.tar.gz
---
CHANGES | 62 +++++--
Flask_SQLAlchemy.egg-info/PKG-INFO | 18 +-
Flask_SQLAlchemy.egg-info/requires.txt | 3 +-
LICENSE | 2 +-
PKG-INFO | 18 +-
README | 48 ++++-
docs/_static/flask-sqlalchemy-small.png | Bin
docs/api.rst | 13 ++
docs/binds.rst | 3 +-
docs/conf.py | 24 +--
docs/config.rst | 128 ++++++++-----
docs/contexts.rst | 16 +-
docs/models.rst | 4 +-
docs/quickstart.rst | 6 +-
docs/signals.rst | 29 ++-
flask_sqlalchemy/__init__.py | 320 ++++++++++++++++++++++----------
setup.cfg | 16 +-
setup.py | 19 +-
test_sqlalchemy.py | 205 +++++++++++++++++++-
19 files changed, 694 insertions(+), 240 deletions(-)
diff --git a/CHANGES b/CHANGES
index 0723758..8d241b5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,40 +1,74 @@
Changelog
----------
+=========
Here you can see the full list of changes between each Flask-SQLAlchemy
release.
-Version 0.17
-````````````
+Version 3.0
+-----------
-*In development*
+In development, codename Dubnium
+
+Version 2.1
+-----------
+
+Released on October 23rd 2015, codename Caesium
+
+- Table names are automatically generated in more cases, including
+ subclassing mixins and abstract models.
+- Allow using a custom MetaData object.
+- Add support for binds parameter to session.
+
+Version 2.0
+-----------
+
+Released on August 29th 2014, codename Bohrium
+
+- Changed how the builtin signals are subscribed to skip non Flask-SQLAlchemy
+ sessions. This will also fix the attribute error about model changes
+ not existing.
+- Added a way to control how signals for model modifications are tracked.
+- Made the ``SignallingSession`` a public interface and added a hook
+ for customizing session creation.
+- If the ``bind`` parameter is given to the signalling session it will no
+ longer cause an error that a parameter is given twice.
+- Added working table reflection support.
+- Enabled autoflush by default.
+- Consider ``SQLALCHEMY_COMMIT_ON_TEARDOWN`` harmful and remove from docs.
+
+Version 1.0
+-----------
+
+Released on July 20th 2013, codename Aurum
- Added Python 3.3 support.
- Dropped 2.5 compatibility.
+- Various bugfixes
+- Changed versioning format to do major releases for each update now.
Version 0.16
-````````````
+------------
- New distribution format (flask_sqlalchemy)
- Added support for Flask 0.9 specifics.
Version 0.15
-````````````
+------------
- Added session support for multiple databases
Version 0.14
-````````````
+------------
- Make relative sqlite paths relative to the application root.
Version 0.13
-````````````
+------------
- Fixed an issue with Flask-SQLAlchemy not selecting the correct binds.
Version 0.12
-````````````
+------------
- Added support for multiple databases.
- Expose Flask-SQLAlchemy's BaseQuery as `db.Query`.
- Set default query_class for `db.relation`, `db.relationship`, and
@@ -42,12 +76,12 @@ Version 0.12
- Improved compatibility with Flask 0.7.
Version 0.11
-````````````
+------------
- Fixed a bug introduced in 0.10 with alternative table constructors.
Version 0.10
-````````````
+------------
- Added support for signals.
- Table names are now automatically set from the class name unless
@@ -61,18 +95,18 @@ Version 0.10
This makes it possible to omit the metadata.
Version 0.9
-```````````
+-----------
- applied changes to pass the Flask extension approval process.
Version 0.8
-```````````
+-----------
- added a few configuration keys for creating connections.
- automatically activate connection recycling for MySQL connections.
- added support for the Flask testing mode.
Version 0.7
-```````````
+-----------
- Initial public release
diff --git a/Flask_SQLAlchemy.egg-info/PKG-INFO b/Flask_SQLAlchemy.egg-info/PKG-INFO
index d1fa2b4..3b587dd 100644
--- a/Flask_SQLAlchemy.egg-info/PKG-INFO
+++ b/Flask_SQLAlchemy.egg-info/PKG-INFO
@@ -1,10 +1,10 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: Flask-SQLAlchemy
-Version: 1.0
+Version: 2.1
Summary: Adds SQLAlchemy support to your Flask application
Home-page: http://github.com/mitsuhiko/flask-sqlalchemy
-Author: Armin Ronacher
-Author-email: armin.ronacher at active-4.com
+Author: Phil Howell
+Author-email: phil at quae.co.uk
License: BSD
Description:
Flask-SQLAlchemy
@@ -15,7 +15,7 @@ Description:
Links
`````
- * `documentation <http://packages.python.org/Flask-SQLAlchemy>`_
+ * `documentation <http://flask-sqlalchemy.pocoo.org>`_
* `development version
<http://github.com/mitsuhiko/flask-sqlalchemy/zipball/master#egg=Flask-SQLAlchemy-dev>`_
@@ -25,6 +25,12 @@ Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
diff --git a/Flask_SQLAlchemy.egg-info/requires.txt b/Flask_SQLAlchemy.egg-info/requires.txt
index d07e166..fd75ba5 100644
--- a/Flask_SQLAlchemy.egg-info/requires.txt
+++ b/Flask_SQLAlchemy.egg-info/requires.txt
@@ -1,3 +1,2 @@
-setuptools
Flask>=0.10
-SQLAlchemy
\ No newline at end of file
+SQLAlchemy>=0.7
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 562f7eb..49fcac3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010 by Armin Ronacher.
+Copyright (c) 2014 by Armin Ronacher.
Some rights reserved.
diff --git a/PKG-INFO b/PKG-INFO
index d1fa2b4..3b587dd 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,10 +1,10 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: Flask-SQLAlchemy
-Version: 1.0
+Version: 2.1
Summary: Adds SQLAlchemy support to your Flask application
Home-page: http://github.com/mitsuhiko/flask-sqlalchemy
-Author: Armin Ronacher
-Author-email: armin.ronacher at active-4.com
+Author: Phil Howell
+Author-email: phil at quae.co.uk
License: BSD
Description:
Flask-SQLAlchemy
@@ -15,7 +15,7 @@ Description:
Links
`````
- * `documentation <http://packages.python.org/Flask-SQLAlchemy>`_
+ * `documentation <http://flask-sqlalchemy.pocoo.org>`_
* `development version
<http://github.com/mitsuhiko/flask-sqlalchemy/zipball/master#egg=Flask-SQLAlchemy-dev>`_
@@ -25,6 +25,12 @@ Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
diff --git a/README b/README
index 5120fe9..0899ec5 100644
--- a/README
+++ b/README
@@ -1,3 +1,47 @@
-Flask-SQLAlchemy
-Adds SQLAlchemy support to Flask. Under development.
+ // Flask-SQLAlchemy //
+
+
+ ~ What is Flask-SQLAlchemy?
+
+ Flask-SQLAlchemy is a Flask microframework extension which adds
+ support for the SQLAlchemy SQL toolkit/ORM.
+
+ ~ What's the latest version?
+
+ 2.0 is the most recent stable version. 2.1 is slated for release in early February.
+
+ ~ What do I need?
+
+ SQLAlchemy, and Flask 0.10 or later. `pip` or `easy_install` will
+ install them for you if you do `pip install Flask-SQLAlchemy`.
+ We encourage you to use a virtualenv. Check the docs for complete
+ installation and usage instructions.
+
+ ~ Where are the docs?
+
+ Go to http://flask-sqlalchemy.pocoo.org/ for a prebuilt version
+ of the current documentation. Otherwise build them yourself
+ from the sphinx sources in the docs folder.
+
+ ~ Where are the tests?
+
+ Good that you're asking. To run the tests use the
+ `test_sqlalchemy.py` file:
+
+ $ python test_sqlalchemy.py
+
+ If you just want one particular testcase to run you can provide
+ it on the command line:
+
+ $ python test_sqlalchemy.py PaginationTestCase
+
+ In case you have `tox` installed, you can also run that to have
+ virtualenvs created automatically and tests run inside of them
+ at your convenience. Running just `tox` is enough:
+
+ $ tox
+
+ ~ Where can I get help?
+
+ Join us on the #pocoo IRC channel on irc.freenode.net.
diff --git a/docs/_static/flask-sqlalchemy-small.png b/docs/_static/flask-sqlalchemy-small.png
old mode 100755
new mode 100644
diff --git a/docs/api.rst b/docs/api.rst
index cf1c804..1e6e76b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -27,6 +27,13 @@ Models
Optionally declares the bind to use. `None` refers to the default
bind. For more information see :ref:`binds`.
+ .. attribute:: __tablename__
+
+ The name of the table in the database. This is required by SQLAlchemy;
+ however, Flask-SQLAlchemy will set it automatically if a model has a
+ primary key defined. If the ``__table__`` or ``__tablename__`` is set
+ explicitly, that will be used instead.
+
.. autoclass:: BaseQuery
:members: get, get_or_404, paginate, first_or_404
@@ -55,6 +62,12 @@ Models
doesn’t contain any rows. This results in an execution of the
underlying query.
+Sessions
+````````
+
+.. autoclass:: SignallingSession
+ :members:
+
Utilities
`````````
diff --git a/docs/binds.rst b/docs/binds.rst
index 154e546..3c57a1b 100644
--- a/docs/binds.rst
+++ b/docs/binds.rst
@@ -69,4 +69,5 @@ a table object directly you will have to put it in there::
)
If you specified the `__bind_key__` on your models you can use them exactly the
-you are used to. The model connects to the specified database connection itself.
+way you are used to. The model connects to the specified database connection
+itself.
diff --git a/docs/conf.py b/docs/conf.py
index d99a841..a45e1f5 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -42,7 +42,7 @@ master_doc = 'index'
# General information about the project.
project = u'Flask-SQLAlchemy'
-copyright = u'2010-2011, Armin Ronacher'
+copyright = u'2010-2014, Armin Ronacher'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -51,10 +51,10 @@ import pkg_resources
try:
release = pkg_resources.get_distribution('Flask-SQLAlchemy').version
except pkg_resources.DistributionNotFound:
- print 'To build the documentation, The distribution information of'
- print 'Flask-SQLAlchemy has to be available. Either install the package'
- print 'into your development environment or run "setup.py develop"'
- print 'to setup the metadata. A virtualenv is recommended!'
+ print('To build the documentation, The distribution information of')
+ print('Flask-SQLAlchemy has to be available. Either install the package')
+ print('into your development environment or run "setup.py develop"')
+ print('to setup the metadata. A virtualenv is recommended!')
sys.exit(1)
del pkg_resources
@@ -232,13 +232,13 @@ pygments_style = 'flask_theme_support.FlaskyStyle'
# fall back if theme is not there
try:
__import__('flask_theme_support')
-except ImportError, e:
- print '-' * 74
- print 'Warning: Flask themes unavailable. Building with default theme'
- print 'If you want the Flask themes, run this command and build again:'
- print
- print ' git submodule update --init'
- print '-' * 74
+except ImportError as e:
+ print('-' * 74)
+ print('Warning: Flask themes unavailable. Building with default theme')
+ print('If you want the Flask themes, run this command and build again:')
+ print()
+ print(' git submodule update --init')
+ print('-' * 74)
pygments_style = 'tango'
html_theme = 'default'
diff --git a/docs/config.rst b/docs/config.rst
index 446efff..6ac5bf8 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -14,48 +14,53 @@ A list of configuration keys currently understood by the extension:
.. tabularcolumns:: |p{6.5cm}|p{8.5cm}|
-================================= =========================================
-``SQLALCHEMY_DATABASE_URI`` The database URI that should be used for
- the connection. Examples:
-
- - ``sqlite:////tmp/test.db``
- - ``mysql://username:password@server/db``
-``SQLALCHEMY_BINDS`` A dictionary that maps bind keys to
- SQLAlchemy connection URIs. For more
- information about binds see :ref:`binds`.
-``SQLALCHEMY_ECHO`` If set to `True` SQLAlchemy will log all
- the statements issued to stderr which can
- be useful for debugging.
-``SQLALCHEMY_RECORD_QUERIES`` Can be used to explicitly disable or
- enable query recording. Query recording
- automatically happens in debug or testing
- mode. See :func:`get_debug_queries` for
- more information.
-``SQLALCHEMY_NATIVE_UNICODE`` Can be used to explicitly disable native
- unicode support. This is required for
- some database adapters (like PostgreSQL
- on some Ubuntu versions) when used with
- inproper database defaults that specify
- encoding-less databases.
-``SQLALCHEMY_POOL_SIZE`` The size of the database pool. Defaults
- to the engine's default (usually 5)
-``SQLALCHEMY_POOL_TIMEOUT`` Specifies the connection timeout for the
- pool. Defaults to 10.
-``SQLALCHEMY_POOL_RECYCLE`` Number of seconds after which a
- connection is automatically recycled.
- This is required for MySQL, which removes
- connections after 8 hours idle by
- default. Note that Flask-SQLAlchemy
- automatically sets this to 2 hours if
- MySQL is used.
-``SQLALCHEMY_MAX_OVERFLOW`` Controls the number of connections that
- can be created after the pool reached
- its maximum size. When those additional
- connections are returned to the pool,
- they are disconnected and discarded.
-``SQLALCHEMY_COMMIT_ON_TEARDOWN`` Commit session when the app context is
- torn down, unless there was an exception.
-================================= =========================================
+================================== =========================================
+``SQLALCHEMY_DATABASE_URI`` The database URI that should be used for
+ the connection. Examples:
+
+ - ``sqlite:////tmp/test.db``
+ - ``mysql://username:password@server/db``
+``SQLALCHEMY_BINDS`` A dictionary that maps bind keys to
+ SQLAlchemy connection URIs. For more
+ information about binds see :ref:`binds`.
+``SQLALCHEMY_ECHO`` If set to `True` SQLAlchemy will log all
+ the statements issued to stderr which can
+ be useful for debugging.
+``SQLALCHEMY_RECORD_QUERIES`` Can be used to explicitly disable or
+ enable query recording. Query recording
+ automatically happens in debug or testing
+ mode. See :func:`get_debug_queries` for
+ more information.
+``SQLALCHEMY_NATIVE_UNICODE`` Can be used to explicitly disable native
+ unicode support. This is required for
+ some database adapters (like PostgreSQL
+ on some Ubuntu versions) when used with
+ improper database defaults that specify
+ encoding-less databases.
+``SQLALCHEMY_POOL_SIZE`` The size of the database pool. Defaults
+ to the engine's default (usually 5)
+``SQLALCHEMY_POOL_TIMEOUT`` Specifies the connection timeout for the
+ pool. Defaults to 10.
+``SQLALCHEMY_POOL_RECYCLE`` Number of seconds after which a
+ connection is automatically recycled.
+ This is required for MySQL, which removes
+ connections after 8 hours idle by
+ default. Note that Flask-SQLAlchemy
+ automatically sets this to 2 hours if
+ MySQL is used.
+``SQLALCHEMY_MAX_OVERFLOW`` Controls the number of connections that
+ can be created after the pool reached
+ its maximum size. When those additional
+ connections are returned to the pool,
+ they are disconnected and discarded.
+``SQLALCHEMY_TRACK_MODIFICATIONS`` If set to ``True``, Flask-SQLAlchemy will
+ track modifications of objects and emit
+ signals. The default is ``None``, which
+ enables tracking but issues a warning
+ that it will be disabled by default in
+ the future. This requires extra memory
+ and should be disabled if not needed.
+================================== =========================================
.. versionadded:: 0.8
The ``SQLALCHEMY_NATIVE_UNICODE``, ``SQLALCHEMY_POOL_SIZE``,
@@ -68,6 +73,11 @@ A list of configuration keys currently understood by the extension:
.. versionadded:: 0.17
The ``SQLALCHEMY_MAX_OVERFLOW`` configuration key was added.
+.. versionadded:: 2.0
+ The ``SQLALCHEMY_TRACK_MODIFICATIONS`` configuration key was added.
+.. versionchanged:: 2.1
+ ``SQLALCHEMY_TRACK_MODIFICATIONS`` will warn if unset.
+
Connection URI Format
---------------------
@@ -101,3 +111,37 @@ Oracle::
SQLite (note the four leading slashes)::
sqlite:////absolute/path/to/foo.db
+
+Using custom MetaData and naming conventions
+--------------------------------------------
+
+You can optionally construct the :class:`SQLAlchemy` object with a custom
+:class:`~sqlalchemy.schema.MetaData` object.
+This allows you to, among other things,
+specify a `custom constraint naming convention
+<http://docs.sqlalchemy.org/en/latest/core/constraints.html#constraint-naming-conventions>`_.
+Doing so is important for dealing with database migrations (for instance using
+`alembic <https://alembic.readthedocs.org>`_ as stated
+`here <http://alembic.readthedocs.org/en/latest/naming.html>`_. Since SQL
+defines no standard naming conventions, there is no guaranteed nor effective
+compatibility by default among database implementations. You can define a
+custom naming convention like this as suggested by the SQLAlchemy docs::
+
+ from sqlalchemy import MetaData
+ from flask import Flask
+ from flask.ext.sqlalchemy import SQLAlchemy
+
+ convention = {
+ "ix": 'ix_%(column_0_label)s',
+ "uq": "uq_%(table_name)s_%(column_0_name)s",
+ "ck": "ck_%(table_name)s_%(constraint_name)s",
+ "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
+ "pk": "pk_%(table_name)s"
+ }
+
+ metadata = MetaData(naming_convention=convention)
+ db = SQLAlchemy(app, metadata=metadata)
+
+For more info about :class:`~sqlalchemy.schema.MetaData`,
+`check out the official docs on it
+<http://docs.sqlalchemy.org/en/latest/core/metadata.html>`_.
diff --git a/docs/contexts.rst b/docs/contexts.rst
index 1318a61..edf12bb 100644
--- a/docs/contexts.rst
+++ b/docs/contexts.rst
@@ -16,7 +16,7 @@ object globally, how does the latter learn about the former? The answer
is the :meth:`~SQLAlchemy.init_app` function::
from flask import Flask
- from flask.ext.sqlalchemy import SQLAlchemy
+ from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
@@ -26,28 +26,28 @@ is the :meth:`~SQLAlchemy.init_app` function::
return app
-What it does it preparing the application to work with
+What it does is prepare the application to work with
:class:`SQLAlchemy`. However that does not now bind the
:class:`SQLAlchemy` object to your application. Why doesn't it do that?
Because there might be more than one application created.
So how does :class:`SQLAlchemy` now really know about your application?
-You will have to setup a request context. If you are working inside a
-Flask view function, that automatically happens. However if you are
+You will have to setup an application context. If you are working inside
+a Flask view function, that automatically happens. However if you are
working inside the interactive shell, you will have to do that yourself
-(see `Creating a Request Context
-<http://flask.pocoo.org/docs/shell/#creating-a-request-context>`_).
+(see `Creating an Application Context
+<http://flask.pocoo.org/docs/appcontext/#creating-an-application-context>`_).
In a nutshell, do something like this:
>>> from yourapp import create_app
>>> app = create_app()
->>> app.test_request_context().push()
+>>> app.app_context().push()
Inside scripts it makes also sense to use the with-statement::
def my_function():
- with app():
+ with app.app_context():
user = db.User(...)
db.session.add(user)
db.session.commit()
diff --git a/docs/models.rst b/docs/models.rst
index fa6eea4..fc11130 100644
--- a/docs/models.rst
+++ b/docs/models.rst
@@ -103,9 +103,9 @@ when SQLAlchemy will load the data from the database:
query as the parent using a `JOIN` statement.
- ``'subquery'`` works like ``'joined'`` but instead SQLAlchemy will
use a subquery.
-- ``'dynamic'`` is special and useful if you have may items. Instead of
+- ``'dynamic'`` is special and useful if you have many items. Instead of
loading the items SQLAlchemy will return another query object which
- you can further refine before loading them items. This is usually
+ you can further refine before loading the items. This is usually
what you want if you expect more than a handful of items for this
relationship.
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index e32a58a..a1726f4 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -6,7 +6,7 @@ Quickstart
.. currentmodule:: flask.ext.sqlalchemy
Flask-SQLAlchemy is fun to use, incredibly easy for basic applications, and
-readily extends for larger applications. For the complete guide, checkout out
+readily extends for larger applications. For the complete guide, checkout
the API documentation on the :class:`SQLAlchemy` class.
A Minimal Application
@@ -22,7 +22,7 @@ provides a class called `Model` that is a declarative base which can be
used to declare models::
from flask import Flask
- from flask.ext.sqlalchemy import SQLAlchemy
+ from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
@@ -41,7 +41,7 @@ used to declare models::
def __repr__(self):
return '<User %r>' % self.username
-To create the initial database, just import the `db` object from a
+To create the initial database, just import the `db` object from an
interactive Python shell and run the
:meth:`SQLAlchemy.create_all` method to create the
tables and database:
diff --git a/docs/signals.rst b/docs/signals.rst
index 04e95f6..6a577b3 100644
--- a/docs/signals.rst
+++ b/docs/signals.rst
@@ -1,27 +1,24 @@
Signalling Support
==================
-.. versionadded:: 0.10
-
-Starting with Flask-SQLAlchemy 0.10 you can now connect to signals to get
-notifications when certain things happen.
+Connect to the following signals to get notified before and after changes are committed to the database.
+These changes are only tracked if ``SQLALCHEMY_TRACK_MODIFICATIONS`` is enabled in the config.
-The following two signals exist:
+.. versionadded:: 0.10
+.. versionchanged:: 2.1
+ ``before_models_committed`` is triggered correctly.
+.. deprecated:: 2.1
+ This will be disabled by default in a future version.
.. data:: models_committed
- This signal is sent when changed models where committed to the
- database. The sender is the application that emitted the changes
- and the models and an operation identifier are passed as list of tuples
- in the form ``(model, operation)`` to the receiver in the `changes`
- parameter.
+ This signal is sent when changed models were committed to the database.
+
+ The sender is the application that emitted the changes.
+ The receiver is passed the ``changes`` parameter with a list of tuples in the form ``(model instance, operation)``.
- The model is the instance of the model that was sent to the database
- and the operation is ``'insert'`` when a model was inserted,
- ``'delete'`` when the model was deleted and ``'update'`` if any
- of the columns where updated.
+ The operation is one of ``'insert'``, ``'update'``, and ``'delete'``.
.. data:: before_models_committed
- Works exactly the same as :data:`models_committed` but is emitted
- right before the committing takes place.
+ This signal works exactly like :data:`models_committed` but is emitted before the commit takes place.
diff --git a/flask_sqlalchemy/__init__.py b/flask_sqlalchemy/__init__.py
index 9309244..a6b67eb 100644
--- a/flask_sqlalchemy/__init__.py
+++ b/flask_sqlalchemy/__init__.py
@@ -5,7 +5,7 @@
Adds basic SQLAlchemy support to your application.
- :copyright: (c) 2012 by Armin Ronacher, Daniel Neuhäuser.
+ :copyright: (c) 2014 by Armin Ronacher, Daniel Neuhäuser.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement, absolute_import
@@ -14,20 +14,20 @@ import re
import sys
import time
import functools
+import warnings
import sqlalchemy
from math import ceil
from functools import partial
-from flask import _request_ctx_stack, abort
+from flask import _request_ctx_stack, abort, has_request_context, request
from flask.signals import Namespace
from operator import itemgetter
from threading import Lock
-from sqlalchemy import orm, event
+from sqlalchemy import orm, event, inspect
from sqlalchemy.orm.exc import UnmappedClassError
-from sqlalchemy.orm.session import Session
-from sqlalchemy.event import listen
+from sqlalchemy.orm.session import Session as SessionBase
from sqlalchemy.engine.url import make_url
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
-from flask.ext.sqlalchemy._compat import iteritems, itervalues, xrange, \
+from flask_sqlalchemy._compat import iteritems, itervalues, xrange, \
string_types
# the best timer function for the platform
@@ -42,6 +42,9 @@ except ImportError:
_app_ctx_stack = None
+__version__ = '2.1'
+
+
# Which stack should we use? _app_ctx_stack is new in 0.9
connection_stack = _app_ctx_stack or _request_ctx_stack
@@ -130,16 +133,37 @@ def _calling_context(app_path):
return '<unknown>'
-class _SignallingSession(Session):
+class SignallingSession(SessionBase):
+ """The signalling session is the default session that Flask-SQLAlchemy
+ uses. It extends the default session system with bind selection and
+ modification tracking.
+
+ If you want to use a different session you can override the
+ :meth:`SQLAlchemy.create_session` function.
- def __init__(self, db, autocommit=False, autoflush=False, **options):
- self.app = db.get_app()
- self._model_changes = {}
- Session.__init__(self, autocommit=autocommit, autoflush=autoflush,
- bind=db.engine,
- binds=db.get_binds(self.app), **options)
+ .. versionadded:: 2.0
+
+ .. versionadded:: 2.1
+ The `binds` option was added, which allows a session to be joined
+ to an external transaction.
+ """
+
+ def __init__(self, db, autocommit=False, autoflush=True, app=None, **options):
+ #: The application that this session belongs to.
+ self.app = app = db.get_app()
+ track_modifications = app.config['SQLALCHEMY_TRACK_MODIFICATIONS']
+ bind = options.pop('bind', None) or db.engine
+ binds = options.pop('binds', None) or db.get_binds(app)
+
+ if track_modifications is None or track_modifications:
+ _SessionSignalEvents.register(self)
+
+ SessionBase.__init__(
+ self, autocommit=autocommit, autoflush=autoflush,
+ bind=bind, binds=binds, **options
+ )
- def get_bind(self, mapper, clause=None):
+ def get_bind(self, mapper=None, clause=None):
# mapper is None if someone tries to just get a connection
if mapper is not None:
info = getattr(mapper.mapped_table, 'info', {})
@@ -147,60 +171,74 @@ class _SignallingSession(Session):
if bind_key is not None:
state = get_state(self.app)
return state.db.get_engine(self.app, bind=bind_key)
- return Session.get_bind(self, mapper, clause)
+ return SessionBase.get_bind(self, mapper, clause)
class _SessionSignalEvents(object):
-
- def register(self):
- listen(Session, 'before_commit', self.session_signal_before_commit)
- listen(Session, 'after_commit', self.session_signal_after_commit)
- listen(Session, 'after_rollback', self.session_signal_after_rollback)
+ @classmethod
+ def register(cls, session):
+ if not hasattr(session, '_model_changes'):
+ session._model_changes = {}
+
+ event.listen(session, 'before_flush', cls.record_ops)
+ event.listen(session, 'before_commit', cls.record_ops)
+ event.listen(session, 'before_commit', cls.before_commit)
+ event.listen(session, 'after_commit', cls.after_commit)
+ event.listen(session, 'after_rollback', cls.after_rollback)
+
+ @classmethod
+ def unregister(cls, session):
+ if hasattr(session, '_model_changes'):
+ del session._model_changes
+
+ event.remove(session, 'before_flush', cls.record_ops)
+ event.remove(session, 'before_commit', cls.record_ops)
+ event.remove(session, 'before_commit', cls.before_commit)
+ event.remove(session, 'after_commit', cls.after_commit)
+ event.remove(session, 'after_rollback', cls.after_rollback)
@staticmethod
- def session_signal_before_commit(session):
- d = session._model_changes
- if d:
- before_models_committed.send(session.app, changes=d.values())
+ def record_ops(session, flush_context=None, instances=None):
+ try:
+ d = session._model_changes
+ except AttributeError:
+ return
- @staticmethod
- def session_signal_after_commit(session):
- d = session._model_changes
- if d:
- models_committed.send(session.app, changes=d.values())
- d.clear()
+ for targets, operation in ((session.new, 'insert'), (session.dirty, 'update'), (session.deleted, 'delete')):
+ for target in targets:
+ state = inspect(target)
+ key = state.identity_key if state.has_identity else id(target)
+ d[key] = (target, operation)
@staticmethod
- def session_signal_after_rollback(session):
- session._model_changes.clear()
-
-
-class _MapperSignalEvents(object):
-
- def __init__(self, mapper):
- self.mapper = mapper
-
- def register(self):
- listen(self.mapper, 'after_delete', self.mapper_signal_after_delete)
- listen(self.mapper, 'after_insert', self.mapper_signal_after_insert)
- listen(self.mapper, 'after_update', self.mapper_signal_after_update)
+ def before_commit(session):
+ try:
+ d = session._model_changes
+ except AttributeError:
+ return
- def mapper_signal_after_delete(self, mapper, connection, target):
- self._record(mapper, target, 'delete')
+ if d:
+ before_models_committed.send(session.app, changes=list(d.values()))
- def mapper_signal_after_insert(self, mapper, connection, target):
- self._record(mapper, target, 'insert')
+ @staticmethod
+ def after_commit(session):
+ try:
+ d = session._model_changes
+ except AttributeError:
+ return
- def mapper_signal_after_update(self, mapper, connection, target):
- self._record(mapper, target, 'update')
+ if d:
+ models_committed.send(session.app, changes=list(d.values()))
+ d.clear()
@staticmethod
- def _record(mapper, target, operation):
- s = orm.object_session(target)
- if isinstance(s, _SignallingSession):
- pk = tuple(mapper.primary_key_from_instance(target))
- s._model_changes[pk] = (target, operation)
+ def after_rollback(session):
+ try:
+ d = session._model_changes
+ except AttributeError:
+ return
+ d.clear()
class _EngineDebuggingSignalEvents(object):
@@ -211,8 +249,8 @@ class _EngineDebuggingSignalEvents(object):
self.app_package = import_name
def register(self):
- listen(self.engine, 'before_cursor_execute', self.before_cursor_execute)
- listen(self.engine, 'after_cursor_execute', self.after_cursor_execute)
+ event.listen(self.engine, 'before_cursor_execute', self.before_cursor_execute)
+ event.listen(self.engine, 'after_cursor_execute', self.after_cursor_execute)
def before_cursor_execute(self, conn, cursor, statement,
parameters, context, executemany):
@@ -227,9 +265,9 @@ class _EngineDebuggingSignalEvents(object):
if queries is None:
queries = []
setattr(ctx, 'sqlalchemy_queries', queries)
- queries.append( _DebugQueryTuple( (
+ queries.append(_DebugQueryTuple((
statement, parameters, context._query_start_time, _timer(),
- _calling_context(self.app_package) ) ) )
+ _calling_context(self.app_package))))
def get_debug_queries():
@@ -393,16 +431,50 @@ class BaseQuery(orm.Query):
abort(404)
return rv
- def paginate(self, page, per_page=20, error_out=True):
+ def paginate(self, page=None, per_page=None, error_out=True):
"""Returns `per_page` items from page `page`. By default it will
abort with 404 if no items were found and the page was larger than
1. This behavor can be disabled by setting `error_out` to `False`.
+ If page or per_page are None, they will be retrieved from the
+ request query. If the values are not ints and ``error_out`` is
+ true, it will abort with 404. If there is no request or they
+ aren't in the query, they default to page 1 and 20
+ respectively.
+
Returns an :class:`Pagination` object.
"""
+
+ if has_request_context():
+ if page is None:
+ try:
+ page = int(request.args.get('page', 1))
+ except (TypeError, ValueError):
+ if error_out:
+ abort(404)
+
+ page = 1
+
+ if per_page is None:
+ try:
+ per_page = int(request.args.get('per_page', 20))
+ except (TypeError, ValueError):
+ if error_out:
+ abort(404)
+
+ per_page = 20
+ else:
+ if page is None:
+ page = 1
+
+ if per_page is None:
+ per_page = 20
+
if error_out and page < 1:
abort(404)
+
items = self.limit(per_page).offset((page - 1) * per_page).all()
+
if not items and page != 1 and error_out:
abort(404)
@@ -478,24 +550,51 @@ class _EngineConnector(object):
return rv
-def _defines_primary_key(d):
- """Figures out if the given dictonary defines a primary key column."""
- return any(v.primary_key for k, v in iteritems(d)
- if isinstance(v, sqlalchemy.Column))
+def _should_set_tablename(bases, d):
+ """Check what values are set by a class and its bases to determine if a
+ tablename should be automatically generated.
+
+ The class and its bases are checked in order of precedence: the class
+ itself then each base in the order they were given at class definition.
+
+ Abstract classes do not generate a tablename, although they may have set
+ or inherited a tablename elsewhere.
+
+ If a class defines a tablename or table, a new one will not be generated.
... 564 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/flask-sqlalchemy.git
More information about the Python-modules-commits
mailing list