Improve has_changes
This commit is contained in:
@@ -5,6 +5,7 @@ except ImportError:
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from inspect import isclass
|
from inspect import isclass
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
import six
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import inspect
|
from sqlalchemy import inspect
|
||||||
from sqlalchemy.ext.hybrid import hybrid_property
|
from sqlalchemy.ext.hybrid import hybrid_property
|
||||||
@@ -480,10 +481,13 @@ def getdotattr(obj_or_class, dot_path):
|
|||||||
return last
|
return last
|
||||||
|
|
||||||
|
|
||||||
def has_changes(obj, attr):
|
def has_changes(obj, attrs=None, exclude=None):
|
||||||
"""
|
"""
|
||||||
Simple shortcut function for checking if given attribute of given
|
Simple shortcut function for checking if given attribute(s) of given
|
||||||
declarative model object has changed during the transaction.
|
declarative model object has changed during the transaction. Without
|
||||||
|
parameters this checks if given object has any modificiations. Additionally
|
||||||
|
exclude parameter can be given which check if given object has any changes
|
||||||
|
in any attributes other than the ones given in exclude.
|
||||||
|
|
||||||
|
|
||||||
::
|
::
|
||||||
@@ -500,18 +504,52 @@ def has_changes(obj, attr):
|
|||||||
|
|
||||||
has_changes(user, 'name') # True
|
has_changes(user, 'name') # True
|
||||||
|
|
||||||
|
has_changes(user) # True
|
||||||
|
|
||||||
|
|
||||||
|
You can check multiple attributes as well.
|
||||||
|
::
|
||||||
|
|
||||||
|
|
||||||
|
has_changes(user, ['age']) # True
|
||||||
|
|
||||||
|
has_changes(user, ['name', 'age']) # True
|
||||||
|
|
||||||
|
|
||||||
|
This function also supports excluding certain attributes.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
has_changes(user, exclude=['name']) # False
|
||||||
|
|
||||||
|
has_changes(user, exclude=['age']) # True
|
||||||
|
|
||||||
|
.. versionchanged: 0.26.6
|
||||||
|
Added support for multiple attributes and exclude parameter.
|
||||||
|
|
||||||
:param obj: SQLAlchemy declarative model object
|
:param obj: SQLAlchemy declarative model object
|
||||||
:param attr: Name of the attribute
|
:param attrs: Name(s) of the attribute
|
||||||
.. seealso:: :func:`has_any_changes`
|
.. seealso:: :func:`has_any_changes`
|
||||||
"""
|
"""
|
||||||
return (
|
if attrs:
|
||||||
sa.inspect(obj)
|
if isinstance(attrs, six.string_types):
|
||||||
.attrs
|
return (
|
||||||
.get(attr)
|
sa.inspect(obj)
|
||||||
.history
|
.attrs
|
||||||
.has_changes()
|
.get(attrs)
|
||||||
)
|
.history
|
||||||
|
.has_changes()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return any(has_changes(obj, attr) for attr in attrs)
|
||||||
|
else:
|
||||||
|
if exclude is None:
|
||||||
|
exclude = []
|
||||||
|
return any(
|
||||||
|
attr.history.has_changes()
|
||||||
|
for key, attr in sa.inspect(obj).attrs.items()
|
||||||
|
if key not in exclude
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def has_any_changes(model, columns):
|
def has_any_changes(model, columns):
|
||||||
@@ -536,6 +574,8 @@ def has_any_changes(model, columns):
|
|||||||
|
|
||||||
|
|
||||||
.. versionadded: 0.26.3
|
.. versionadded: 0.26.3
|
||||||
|
.. deprecated:: 0.26.6
|
||||||
|
User :func:`has_changes` instead.
|
||||||
|
|
||||||
:param obj: SQLAlchemy declarative model object
|
:param obj: SQLAlchemy declarative model object
|
||||||
:param attrs: Names of the attributes
|
:param attrs: Names of the attributes
|
||||||
|
@@ -4,7 +4,7 @@ from sqlalchemy.ext.declarative import declarative_base
|
|||||||
from sqlalchemy_utils import has_changes
|
from sqlalchemy_utils import has_changes
|
||||||
|
|
||||||
|
|
||||||
class TestHasChanges(object):
|
class HasChangesTestCase(object):
|
||||||
def setup_method(self, method):
|
def setup_method(self, method):
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ class TestHasChanges(object):
|
|||||||
|
|
||||||
self.Article = Article
|
self.Article = Article
|
||||||
|
|
||||||
|
|
||||||
|
class TestHasChangesWithStringAttr(HasChangesTestCase):
|
||||||
def test_without_changed_attr(self):
|
def test_without_changed_attr(self):
|
||||||
article = self.Article()
|
article = self.Article()
|
||||||
assert not has_changes(article, 'title')
|
assert not has_changes(article, 'title')
|
||||||
@@ -22,3 +24,24 @@ class TestHasChanges(object):
|
|||||||
def test_with_changed_attr(self):
|
def test_with_changed_attr(self):
|
||||||
article = self.Article(title='Some title')
|
article = self.Article(title='Some title')
|
||||||
assert has_changes(article, 'title')
|
assert has_changes(article, 'title')
|
||||||
|
|
||||||
|
|
||||||
|
class TestHasChangesWithMultipleAttrs(HasChangesTestCase):
|
||||||
|
def test_without_changed_attr(self):
|
||||||
|
article = self.Article()
|
||||||
|
assert not has_changes(article, ['title'])
|
||||||
|
|
||||||
|
def test_with_changed_attr(self):
|
||||||
|
article = self.Article(title='Some title')
|
||||||
|
assert has_changes(article, ['title', 'id'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestHasChangesWithExclude(HasChangesTestCase):
|
||||||
|
def test_without_changed_attr(self):
|
||||||
|
article = self.Article()
|
||||||
|
assert not has_changes(article, exclude=['id'])
|
||||||
|
|
||||||
|
def test_with_changed_attr(self):
|
||||||
|
article = self.Article(title='Some title')
|
||||||
|
assert has_changes(article, exclude=['id'])
|
||||||
|
assert not has_changes(article, exclude=['title'])
|
||||||
|
Reference in New Issue
Block a user