def Q(**mapping):
"""A Q object represents an AND'd together query using boto3's Attr object, based on a set of keyword arguments that
support the full access to the operations (eq, ne, between, etc) as well as nested attributes.
It can be used input to both scan operations as well as update conditions.
"""
expression = None
while len(mapping):
attr, value = mapping.popitem()
parts = attr.split('__')
attr = Attr(parts.pop(0))
op = 'eq'
while len(parts):
if not hasattr(attr, parts[0]):
# this is a nested field, extend the attr
attr = Attr('.'.join([attr.name, parts.pop(0)]))
else:
op = parts.pop(0)
break
assert len(parts) == 0, "Left over parts after parsing query attr"
op = getattr(attr, op)
try:
attr_expression = op(value)
except TypeError:
# A TypeError calling our attr op likely means we're invoking exists, not_exists or another op that
# doesn't take an arg or takes multiple args. If our value is True then we try to re-call the op
# function without any arguments, if our value is a list we use it as the arguments for the function,
# otherwise we bubble it up.
if value is True:
attr_expression = op()
elif isinstance(value, collections.Iterable):
attr_expression = op(*value)
else:
raise
try:
expression = expression & attr_expression
except TypeError:
expression = attr_expression
return expression
评论列表
文章目录