Improve coverage and add more docs
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user