Improve coverage and add more docs

This commit is contained in:
Konsta Vesterinen
2014-05-07 14:38:19 +03:00
parent 64a31b4478
commit 2193d27d7b
2 changed files with 53 additions and 9 deletions

View File

@@ -43,18 +43,28 @@ def dependencies(obj, foreign_keys=None):
The common use case is checking for all dependent objects before deleting The common use case is checking for all dependent objects before deleting
parent object and inform the user if there are dependent objects with parent object and inform the user if there are dependent objects with
ondelete='RESTRICT' foreign keys. If this kind of checking is not used ondelete='RESTRICT' foreign keys. If this kind of checking is not used
it will lead to nasty IntegrityErrors being raised. This can be achieved it will lead to nasty IntegrityErrors being raised.
as follows::
In the following example we delete given user if it doesn't have any
foreign key restricted dependencies.
::
from sqlalchemy_utils import get_referencing_foreign_keys
user = session.query(User).get(some_user_id)
deps = list( deps = list(
dependencies( dependencies(
user, user,
( (
fk for fk in get_referencing_foreign_keys(obj) fk for fk in get_referencing_foreign_keys(User)
# On most databases RESTRICT is the default mode hence we # On most databases RESTRICT is the default mode hence we
# check for None values also # check for None values also
if fk.ondelete='RESTRICT' or fk.ondelete is None if fk.ondelete == 'RESTRICT' or fk.ondelete is None
) )
).limit(5) ).limit(5)
) )
@@ -62,6 +72,8 @@ def dependencies(obj, foreign_keys=None):
if deps: if deps:
# Do something to inform the user # Do something to inform the user
pass pass
else:
session.delete(user)
:param obj: SQLAlchemy declarative model object :param obj: SQLAlchemy declarative model object
@@ -73,6 +85,8 @@ def dependencies(obj, foreign_keys=None):
.. note:: .. note::
This function does not support exotic mappers that use multiple tables This function does not support exotic mappers that use multiple tables
.. seealso:: :func:`get_referencing_foreign_keys`
.. versionadded: 0.26.0 .. versionadded: 0.26.0
""" """
if foreign_keys is None: if foreign_keys is None:
@@ -142,6 +156,7 @@ def get_referencing_foreign_keys(mixed):
# or textitem table. # or textitem table.
get_referencing_foreign_keys(Article) get_referencing_foreign_keys(Article)
.. seealso:: :func:`get_tables`
""" """
if isinstance(mixed, sa.Table): if isinstance(mixed, sa.Table):
tables = [mixed] tables = [mixed]

View File

@@ -1,5 +1,5 @@
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy_utils.functions.orm import dependencies from sqlalchemy_utils import dependencies, get_referencing_foreign_keys
from tests import TestCase from tests import TestCase
@@ -15,7 +15,9 @@ class TestDependencies(TestCase):
__tablename__ = 'article' __tablename__ = 'article'
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
author_id = sa.Column(sa.Integer, sa.ForeignKey('user.id')) author_id = sa.Column(sa.Integer, sa.ForeignKey('user.id'))
owner_id = sa.Column(sa.Integer, sa.ForeignKey('user.id')) owner_id = sa.Column(
sa.Integer, sa.ForeignKey('user.id', ondelete='SET NULL')
)
author = sa.orm.relationship(User, foreign_keys=[author_id]) author = sa.orm.relationship(User, foreign_keys=[author_id])
owner = sa.orm.relationship(User, foreign_keys=[owner_id]) owner = sa.orm.relationship(User, foreign_keys=[owner_id])
@@ -23,15 +25,17 @@ class TestDependencies(TestCase):
class BlogPost(self.Base): class BlogPost(self.Base):
__tablename__ = 'blog_post' __tablename__ = 'blog_post'
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
author_id = sa.Column(sa.Integer, sa.ForeignKey('user.id')) owner_id = sa.Column(
sa.Integer, sa.ForeignKey('user.id', ondelete='CASCADE')
)
author = sa.orm.relationship(User) owner = sa.orm.relationship(User)
self.User = User self.User = User
self.Article = Article self.Article = Article
self.BlogPost = BlogPost self.BlogPost = BlogPost
def test_multiple_refs(self): def test_returns_all_dependent_objects(self):
user = self.User(first_name=u'John') user = self.User(first_name=u'John')
articles = [ articles = [
self.Article(author=user), self.Article(author=user),
@@ -48,6 +52,31 @@ class TestDependencies(TestCase):
assert articles[2] in deps assert articles[2] in deps
assert articles[3] in deps assert articles[3] in deps
def test_with_foreign_keys_parameter(self):
user = self.User(first_name=u'John')
objects = [
self.Article(author=user),
self.Article(),
self.Article(owner=user),
self.Article(author=user, owner=user),
self.BlogPost(owner=user)
]
self.session.add_all(objects)
self.session.commit()
deps = list(
dependencies(
user,
(
fk for fk in get_referencing_foreign_keys(self.User)
if fk.ondelete == 'RESTRICT' or fk.ondelete is None
)
).limit(5)
)
assert len(deps) == 2
assert objects[0] in deps
assert objects[3] in deps
class TestDependenciesWithCompositeKeys(TestCase): class TestDependenciesWithCompositeKeys(TestCase):
def create_models(self): def create_models(self):