Skip to content

Commit

Permalink
Merge pull request #2 from bitdeli-chef/master
Browse files Browse the repository at this point in the history
Add a Bitdeli Badge to README
  • Loading branch information
jlafon committed Jan 31, 2014
2 parents 8a69938 + 23071ef commit 1310723
Show file tree
Hide file tree
Showing 26 changed files with 1,242 additions and 285 deletions.
4 changes: 4 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PynamoDB is written and maintained by Jharrod LaFon and numerous contributors:

* Craig Bruce
* Adam Chainz
98 changes: 92 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,116 @@
PynamoDB
========

.. image:: https://pypip.in/v/pynamodb/badge.png
:target: https://pypi.python.org/pypi/pynamodb/
:alt: Latest Version
.. image:: https://travis-ci.org/jlafon/PynamoDB.png?branch=devel
:target: https://travis-ci.org/jlafon/PynamoDB
:target: https://travis-ci.org/jlafon/PynamoDB
.. image:: https://coveralls.io/repos/jlafon/PynamoDB/badge.png?branch=devel
:target: https://coveralls.io/r/jlafon/PynamoDB
:target: https://coveralls.io/r/jlafon/PynamoDB
.. image:: https://pypip.in/wheel/pynamodb/badge.png
:target: https://pypi.python.org/pypi/pynamodb/
.. image:: https://pypip.in/license/pynamodb/badge.png
:target: https://pypi.python.org/pypi/pynamodb/

A Pythonic interface for DynamoDB
A Pythonic interface for Amazon's `DynamoDB <http://aws.amazon.com/dynamodb/>`_ that supports
Python 2 and 3.

A rich API that is compatible with Python 2 and Python 3.
DynamoDB is a great NoSQL service provided by Amazon, but the API is verbose.
PynamoDB presents you with a simple, elegant API.

See documentation at http://pynamodb.readthedocs.org/

Basic Usage
^^^^^^^^^^^

Create a model that describes your DynamoDB table.

.. code-block:: python
from pynamodb.models import Model
from pynamodb.attributes import UnicodeAttribute
class UserModel(Model):
"""
A DynamoDB User
"""
table_name = 'dynamodb-user'
email = UnicodeAttribute(null=True)
first_name = UnicodeAttribute(range_key=True)
last_name = UnicodeAttribute(hash_key=True)
Now, search your table for all users with a last name of 'Smith' and whose
first name begins with 'J':

.. code-block:: python
for user in UserModel.query('Smith', first_name__begins_with='J'):
print(user.first_name)
Create a new user:

.. code-block:: python
user = UserModel('John', 'Denver')
user.save()
Advanced Usage
^^^^^^^^^^^^^^

Wan't to use indexes? No problem:

.. code-block:: python
from pynamodb.models import Model
from pynamodb.indexes import GlobalSecondaryIndex, AllProjection
from pynamodb.attributes import NumberAttribute, UnicodeAttribute
class ViewIndex(GlobalSecondaryIndex):
read_capacity_units = 2
write_capacity_units = 1
projection = AllProjection()
view = NumberAttribute(default=0, hash_key=True)
class TestModel(Model):
table_name = 'TestModel'
forum = UnicodeAttribute(hash_key=True)
thread = UnicodeAttribute(range_key=True)
view = NumberAttribute(default=0)
view_index = ViewIndex()
Now query the index for all items with 0 views:

.. code-block:: python
for item in TestModel.view_index.query(0):
print("Item queried from index: {0}".format(item))
It's really that simple.

Installation::

$ pip install pynamodb

or install the development version::

$ pip install git+https://github.com/jlafon/PynamoDB#egg=pynamodb

Features
========

* Python 2 support
* Python 3 support
* Fully tested
* Python 2 support
* An ORM-like interface with query and scan filters
* Includes the entire DynamoDB API
* Supports both unicode and binary DynamoDB attributes
* Support for global secondary indexes, local secondary indexes, and batch operations
* Provides iterators for working with queries, scans, that are automatically paginated
* Automatic pagination for bulk operations
* Complex queries


.. image:: https://d2weczhvl823v0.cloudfront.net/jlafon/pynamodb/trend.png
:alt: Bitdeli badge
:target: https://bitdeli.com/free

162 changes: 146 additions & 16 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ DynamoDB. I quickly realized that my go to library, `dynamodb-mapper <http://dyn
In fact, it won't be supporting them anytime soon because dynamodb-mapper relies on another
library, `boto.dynamodb <http://docs.pythonboto.org/en/latest/migrations/dynamodb_v1_to_v2.html>`__,
which itself won't support them. In fact, boto doesn't support
Python 3 either.
Python 3 either. If you want to know more, `I blogged about it <http://jlafon.io/pynamodb.html>`__.

Installation
^^^^^^^^^^^^
Expand All @@ -30,6 +30,11 @@ Installation

$ pip install pynamodb

.. note::

PynamoDB is still under development. More advanced features are available with the development version
of PynamoDB. You can install it directly from GitHub with pip: `pip install git+https://github.com/jlafon/PynamoDB#egg=pynamodb`

Getting Started
^^^^^^^^^^^^^^^

Expand All @@ -48,7 +53,7 @@ inherit from ``pynamodb.attributes.Attribute``. The most common attributes have

Here is an example, using the same table structure as shown in `Amazon's DynamoDB Thread example <http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleTablesAndData.html>`__.

::
.. code-block:: python
from pynamodb.models import Model
from pynamodb.attributes import (
Expand All @@ -68,32 +73,157 @@ Here is an example, using the same table structure as shown in `Amazon's DynamoD
The ``table_name`` class attribute is required, and tells the model which DynamoDB table to use. The ``forum_name`` attribute
is specified as the hash key for this table with the ``hash_key`` argument. Specifying that an attribute is a range key is done
with the ``range_key`` attribute.
with the ``range_key`` attribute. You can specify a default value for any field, and `default` can even be a function.

PynamoDB comes with several built in attribute types for convenience, which include the following:

* UnicodeAttribute
* UnicodeSetAttribute
* NumberAttribute
* NumberSetAttribute
* BinaryAttribute
* BinarySetAttribute
* UTCDateTimeAttribute
* BooleanAttribute
* JSONAttribute

All of these built in attributes handle serializing and deserializng themselves, in both Python 2 and Python 3.

Creating the table
------------------

If your table doesn't already exist, you will have to create it. This can be done with easily:

>>> Thread.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
.. code-block:: python
>>> if not Thread.exists():
Thread.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
The ``wait`` argument tells PynamoDB to wait until the table is ready for use before returning.

Connection
----------

The `Connection` API provides a Pythonic wrapper over the Amazon DynamoDB API. All operations
are supported, and it provides a primitive starting point for the other two APIs.
Using the Model
^^^^^^^^^^^^^^^

Now that you've defined a model (referring to the example above), you can start interacting with
your DynamoDB table. You can create a new `Thread` item by calling the `Thread` constructor.

Creating Items
--------------
.. code-block:: python
>>> thread_item = Thread('forum_name', 'forum_subject')
The first two arguments are automatically assigned to the item's hash and range keys. You can
specify attributes during construction as well:

.. code-block:: python
>>> thread_item = Thread('forum_name', 'forum_subject', replies=10)
The item won't be added to your DynamoDB table until you call save:

.. code-block:: python
>>> thread_item.save()
If you want to retrieve an item that already exists in your table, you can do that with `get`:

.. code-block:: python
>>> thread_item = Thread.get('forum_name', 'forum_subject')
If the item doesn't exist, `None` will be returned.

Updating Items
--------------

You can update an item with the latest data from your table:

.. code-block:: python
>>> thread_item.refresh()
Updates to table items are supported too, even atomic updates. Here is an example of
atomically updating the view count of an item:

.. code-block:: python
>>> thread_item.update_item('views', 1, action='add')
Batch Operations
^^^^^^^^^^^^^^^^

Batch operations are supported using context managers, and iterators. The DynamoDB API has limits for each batch operation
that it supports, but PynamoDB removes the need implement your own grouping or pagination. Instead, it handles
pagination for you automatically.

Batch Writes
-------------

Here is an example using a context manager for a bulk write operation:

.. code-block:: python
with Thread.batch_write() as batch:
items = [TestModel('forum-{0}'.format(x), 'thread-{0}'.format(x)) for x in range(1000)]
for item in items:
batch.save(item)
Batch Gets
-------------

Here is an example using an iterator for retrieving items in bulk:

.. code-block:: python
item_keys = [('forum-{0}'.format(x), 'thread-{0}'.format(x)) for x in range(1000)]
for item in Thread.batch_get(item_keys):
print(item)
Query Filters
-------------

You can query items from your table using a simple syntax, similar to other Python ORMs:

.. code-block:: python
for item in Thread.query('ForumName', thread__begins_with='mygreatprefix'):
print("Query returned item {0}".format(item))
Query filters are translated from an ORM like syntax to DynamoDB API calls, and use
the following syntax: `attribute__operator=value`, where `attribute` is the name of an attribute
and `operator` can be one of the following:

* eq
* le
* lt
* ge
* gt
* begins_with
* between

Scan Filters
------------

TableConnection
---------------
Scan filters have the same syntax as Query filters, but support different operations (a consequence of the
DynamoDB API - not PynamoDB). The supported operators are:

The `TabelConnection` API is a small convenience layer built on the `Connection` that provides
all of the DynamoDB API for a given table.
* eq
* ne
* le
* lt
* gt
* not_null
* null
* contains
* not_contains
* begins_with
* between

Model
-----
You can even specify multiple filters:

This is where the fun begins, with bulk operations, query filters, context managers, and automatic
attribute binding. The `Model` class provides very high level features for interacting with DynamoDB.
.. code-block:: python
>>> for item in Thread.scan(forum__begins_with='Prefix', views__gt=10):
print(item)
13 changes: 13 additions & 0 deletions docs/awsaccess.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
AWS Access
==========

PynamoDB uses botocore to interact with the DynamoDB API. Thus, similar methods can be used to provide your AWS
credentials. For local development the use of environment variables such as `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
is probably preferable. You can of course use IAM users, as recommended by AWS. In addition
`EC2 roles <http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html>`_ will work as well and
would be recommended when running on EC2.

As for the permissions granted via IAM, many tasks can be carried out by PynamoDB. So you should construct your
policies as required, see the
`DynamoDB <http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/UsingIAMWithDDB.html>`_ docs for more
information.
6 changes: 4 additions & 2 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Contributing
============

Pull requests are welcome, please write tests to accompany your changes or at least run the test suite
with `tox` before submitting. Once on GitHub Travis-ci will run the test suite as well.
Pull requests are welcome, forking from the devel branch. Please write tests to accompany your changes or at least run
the test suite with `tox` before submitting. Once on GitHub Travis-ci will run the test suite as well.

Don't forget to add yourself to `AUTHORS.rst <https://github.com/jlafon/PynamoDB/blob/devel/AUTHORS.rst>`_.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Topics
api
indexes
low_level
awsaccess
contributing

Indices and tables
Expand Down
Loading

0 comments on commit 1310723

Please sign in to comment.