Improve has_changes

This commit is contained in:
Konsta Vesterinen
2014-07-22 11:31:49 +03:00
parent a54844ccb3
commit 549c740932
2 changed files with 75 additions and 12 deletions

View File

@@ -5,6 +5,7 @@ except ImportError:
from functools import partial
from inspect import isclass
from operator import attrgetter
import six
import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.ext.hybrid import hybrid_property
@@ -480,10 +481,13 @@ def getdotattr(obj_or_class, dot_path):
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
declarative model object has changed during the transaction.
Simple shortcut function for checking if given attribute(s) of given
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) # 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 attr: Name of the attribute
:param attrs: Name(s) of the attribute
.. seealso:: :func:`has_any_changes`
"""
return (
sa.inspect(obj)
.attrs
.get(attr)
.history
.has_changes()
)
if attrs:
if isinstance(attrs, six.string_types):
return (
sa.inspect(obj)
.attrs
.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):
@@ -536,6 +574,8 @@ def has_any_changes(model, columns):
.. versionadded: 0.26.3
.. deprecated:: 0.26.6
User :func:`has_changes` instead.
:param obj: SQLAlchemy declarative model object
:param attrs: Names of the attributes

View File

@@ -4,7 +4,7 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utils import has_changes
class TestHasChanges(object):
class HasChangesTestCase(object):
def setup_method(self, method):
Base = declarative_base()
@@ -15,6 +15,8 @@ class TestHasChanges(object):
self.Article = Article
class TestHasChangesWithStringAttr(HasChangesTestCase):
def test_without_changed_attr(self):
article = self.Article()
assert not has_changes(article, 'title')
@@ -22,3 +24,24 @@ class TestHasChanges(object):
def test_with_changed_attr(self):
article = self.Article(title='Some 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'])