Skip to content

Latest commit

 

History

History
144 lines (95 loc) · 4.63 KB

conditional.rst

File metadata and controls

144 lines (95 loc) · 4.63 KB

Conditional Operations

Some DynamoDB operations (UpdateItem, PutItem, DeleteItem) support the inclusion of conditions. The user can supply a condition to be evaluated by DynamoDB before the operation is performed. See the official documentation for more details.

Suppose that you have defined a Thread Model for the examples below.

from pynamodb.models import Model
from pynamodb.attributes import (
    UnicodeAttribute, NumberAttribute
)


class Thread(Model):
    class Meta:
        table_name = 'Thread'

    forum_name = UnicodeAttribute(hash_key=True)
    subject = UnicodeAttribute(range_key=True)
    views = NumberAttribute(default=0)

Condition Expressions

PynamoDB supports creating condition expressions from attributes using a mix of built-in operators and method calls. Any value provided will be serialized using the serializer defined for that attribute. See the comparison operator and function reference for more details.

DynamoDB Condition PynamoDB Syntax Example
= == Thread.forum_name == 'Some Forum'
<> != Thread.forum_name != 'Some Forum'
< < Thread.views < 10
<= <= Thread.views <= 10
> > Thread.views > 10
>= >= Thread.views >= 10
BETWEEN between( lower , upper ) Thread.views.between(1, 5)
IN is_in( *values ) Thread.subject.is_in('Subject', 'Other Subject')
attribute_exists ( path ) exists() Thread.forum_name.exists()
attribute_not_exists ( path ) does_not_exist() Thread.forum_name.does_not_exist()
attribute_type ( path , type ) is_type() Thread.forum_name.is_type()
begins_with ( path , substr ) startswith( prefix ) Thread.subject.startswith('Example')
contains ( path , operand ) contains( item ) Thread.subject.contains('foobar')
size ( path) size( attribute ) size(Thread.subject) == 10
AND & (Thread.views > 1) & (Thread.views < 5)
OR | (Thread.views < 1) | (Thread.views > 5)
NOT ~ ~Thread.subject.contains('foobar')

Conditions expressions using nested list and map attributes can be created with Python's item operator []:

from pynamodb.models import Model
from pynamodb.attributes import (
    ListAttribute, MapAttribute, UnicodeAttribute
)

class Container(Model):
    class Meta:
        table_name = 'Container'

    name = UnicodeAttribute(hash_key = True)
    my_map = MapAttribute()
    my_list = ListAttribute()

print(Container.my_map['foo'].exists() | Container.my_list[0].contains('bar'))

Conditions can be composited using & (AND) and | (OR) operators. For the & (AND) operator, the left-hand side operand can be None to allow easier chaining of filter conditions:

condition = None

if query.name:
  condition &= Person.name == query.name

if query.age:
  condition &= Person.age == query.age

results = Person.query(..., filter_condition=condition)

Conditional Model.save

This example saves a Thread item, only if the item exists.

thread_item = Thread('Existing Forum', 'Example Subject')

# DynamoDB will only save the item if forum_name exists
print(thread_item.save(Thread.forum_name.exists())

# You can specify multiple conditions
print(thread_item.save(Thread.forum_name.exists() & Thread.subject.contains('foobar')))

Conditional Model.update

This example will update a Thread item, if the views attribute is less than 5 OR greater than 10:

thread_item.update(condition=(Thread.views < 5) | (Thread.views > 10))

Conditional Model.delete

This example will delete the item, only if its views attribute is equal to 0.

print(thread_item.delete(Thread.views == 0))

Conditional Operation Failures

You can check for conditional operation failures by inspecting the cause of the raised exception:

try:
    thread_item.save(Thread.forum_name.exists())
except PutError as e:
    if isinstance(e.cause, ClientError):
        code = e.cause.response['Error'].get('Code')
        print(code == "ConditionalCheckFailedException")