Using the AWS SDK with DynamoDB
The AWS SDK for Python is well written, well documented, and makes it relatively easy to work with AWS services. Normally, I enjoy working with the library because it makes coding easier but the DynamoDB portion of the SDK feels verbose and unintuitive. As a result, I was looking for something easier to use and found PynamoDB on Github.
PynamoDB as an alternative to the AWS SDK
If you’re looking for a more Pythonic way to write code for interacting with DynamoDB, PynamoDB is certainly a library to try. From creating tables, to populating and querying them, a lot of the verbosity of the SDK has been abstracted and you can focus on what it is you’re trying to accomplish with the service and less time reading the documentation for the library and service.
Creating a table
To start, create a Model
of the table; this is PyanmoDB’s entry point to working with a DynamoDB table. To do this, you extend the Model
class and delineate the attributes of the table. Each of the attributes are concrete instances of the Attribute
class from pynamodb.attributes
. You just need to choose the type(s) that match your table’s attributes. Once the Model
is created, the table can be saved. You’ll see examples of all of this below.
The example table used in this post contains product reviews. The ReviewModel
class below is a representation of that table using PyanmoDB. The inner Meta
class provides table details such as the name (table_name
) and other optional attributes such as the host
URL. This latter feature can be helpful if you’re testing with a local DynamoDB instance.
The attributes are the name
of the product, the url
where the product can be found, a numeric rating
, and the date it was last rated (last_rating
). In this example, name
and url
form a composite key where the name
is the hash portion and url
is the range portion.
{% highlight python %} from pynamodb.attributes import UnicodeAttribute, NumberAttribute, UTCDateTimeAttribute from pynamodb.models import Model
class ReviewModel(Model): class Meta: table_name = ‘product_reviews’ host = ‘http://localhost:8000’
name = UnicodeAttribute(hash_key=True)
url = UnicodeAttribute(range_key=True)
rating = NumberAttribute()
last_rating = UTCDateTimeAttribute()
ReviewModel.create_table(read_capacity_units=1, write_capacity_units=1) {% endhighlight %}
The attributes described above are of types UnicodeAttribute
(name
and url
), NumberAttribute
(rating
), and UTCDateTimeAttribute
(last_rating
). These attribute types are a simple way to declare data types without having to remember or find the character code as you do with the AWS SDK.
Creating a new entry
With the Model
declared, you can use it to instantiate new reviews and write them to the newly created table. A new review for cell phone A
is created below.
{% highlight python %} from datetime import datetime
new_review = ReviewModel(name='cell phone A’, url='https://www.example.com/abc123’, rating=4.5, last_rating=datetime.utcnow())
{% endhighlight %}
Once the review is created, it can be written to the table. Instantiating a new entry does not actually write it to the database table; it must be explicitly saved.
{% highlight python %} import logging from pynamodb.exceptions import PutError
try: new_review.save(ReviewModel.name.does_not_exist()) except PutError as e: logging.error(‘Unable to add new review’) {% endhighlight %}
This particular example illustrates the ability to do even more than simply write to the database because it uses a conditional write ReviewModel.name.does_not_exist()
so that if an entry with this composite key (name
and url
) already exists, it won’t be overwritten. The developer guide discusses conditional expressions so review that for more details.
Querying the table
Maybe even easier than creating the table and adding to it is querying it. Normally, you’d need to consider pagination depending on the size of the query results, but the PynamoDB library uses a more straightforward syntax. If we were to query the table created above for a review with the name
cell phone A
, it would look like the below.
{% highlight python %}
query
ReviewModel.query(‘cell phone A’)
return a list from query using list comprehension
[review for review in ReviewModel.query(‘cell phone A’)] {% endhighlight %}
Summary
PynamoDB is an excellent library to try if you’re looking for an alternative to the AWS SDK when interacting with DynamoDB. It provides a more Pythonic interface to the service by using Python classes and methods in ways that are likely more familiar to a Python developer than those provided by the AWS SDK. It still contains the flexibility and features that the SDK provides and allows you to focus on what you’re doing with the service rather than focusing on the service itself.
If you have questions or comments about this post, please leave them below. If you’d like to know when other posts are available, please follow us on Twitter.