2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
<html xmlns="http://www.w3.org/1999/xhtml">
8
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
10
<title>An Introduction to boto’s DynamoDB v2 interface — boto v2.16.0</title>
12
<link rel="stylesheet" href="_static/boto.css" type="text/css" />
13
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
15
<script type="text/javascript">
16
var DOCUMENTATION_OPTIONS = {
19
COLLAPSE_INDEX: false,
24
<script type="text/javascript" src="_static/jquery.js"></script>
25
<script type="text/javascript" src="_static/underscore.js"></script>
26
<script type="text/javascript" src="_static/doctools.js"></script>
27
<link rel="top" title="boto v2.16.0" href="index.html" />
28
<link rel="next" title="Migrating from DynamoDB v1 to DynamoDB v2" href="migrations/dynamodb_v1_to_v2.html" />
29
<link rel="prev" title="An Introduction to boto’s Support interface" href="support_tut.html" />
35
<li class="right" style="margin-right: 10px">
36
<a href="genindex.html" title="General Index"
37
accesskey="I">index</a></li>
39
<a href="py-modindex.html" title="Python Module Index"
42
<a href="migrations/dynamodb_v1_to_v2.html" title="Migrating from DynamoDB v1 to DynamoDB v2"
43
accesskey="N">next</a> |</li>
45
<a href="support_tut.html" title="An Introduction to boto’s Support interface"
46
accesskey="P">previous</a> |</li>
47
<li><a href="index.html">boto v2.16.0</a> »</li>
51
<div class="document">
52
<div class="documentwrapper">
53
<div class="bodywrapper">
56
<div class="section" id="an-introduction-to-boto-s-dynamodb-v2-interface">
57
<span id="dynamodb2-tut"></span><h1>An Introduction to boto’s DynamoDB v2 interface<a class="headerlink" href="#an-introduction-to-boto-s-dynamodb-v2-interface" title="Permalink to this headline">¶</a></h1>
58
<p>This tutorial focuses on the boto interface to AWS’ <a class="reference external" href="http://aws.amazon.com/dynamodb/">DynamoDB</a> v2. This tutorial
59
assumes that you have boto already downloaded and installed.</p>
60
<div class="admonition warning">
61
<p class="first admonition-title">Warning</p>
62
<p class="last">This tutorial covers the <strong>SECOND</strong> major release of DynamoDB (including
63
local secondary index support). The documentation for the original
64
version of DynamoDB (& boto’s support for it) is at
65
<a class="reference internal" href="dynamodb_tut.html"><em>DynamoDB v1</em></a>.</p>
67
<p>The v2 DynamoDB API has both a high-level & low-level component. The low-level
68
API (contained primarily within <tt class="docutils literal"><span class="pre">boto.dynamodb2.layer1</span></tt>) provides an
69
interface that rough matches exactly what is provided by the API. It supports
70
all options available to the service.</p>
71
<p>The high-level API attempts to make interacting with the service more natural
72
from Python. It supports most of the featureset.</p>
73
<div class="section" id="the-high-level-api">
74
<h2>The High-Level API<a class="headerlink" href="#the-high-level-api" title="Permalink to this headline">¶</a></h2>
75
<p>Most of the interaction centers around a single object, the <tt class="docutils literal"><span class="pre">Table</span></tt>. Tables
76
act as a way to effectively namespace your records. If you’re familiar with
77
database tables from an RDBMS, tables will feel somewhat familiar.</p>
78
<div class="section" id="creating-a-new-table">
79
<h3>Creating a New Table<a class="headerlink" href="#creating-a-new-table" title="Permalink to this headline">¶</a></h3>
80
<p>To create a new table, you need to call <tt class="docutils literal"><span class="pre">Table.create</span></tt> & specify (at a
81
minimum) both the table’s name as well as the key schema for the table.</p>
82
<p>Since both the key schema and local secondary indexes can not be
83
modified after the table is created, you’ll need to plan ahead of time how you
84
think the table will be used. Both the keys & indexes are also used for
85
querying, so you’ll want to represent the data you’ll need when querying
87
<p>For the schema, you can either have a single <tt class="docutils literal"><span class="pre">HashKey</span></tt> or a combined
88
<tt class="docutils literal"><span class="pre">HashKey+RangeKey</span></tt>. The <tt class="docutils literal"><span class="pre">HashKey</span></tt> by itself should be thought of as a
89
unique identifier (for instance, like a username or UUID). It is typically
90
looked up as an exact value.
91
A <tt class="docutils literal"><span class="pre">HashKey+RangeKey</span></tt> combination is slightly different, in that the
92
<tt class="docutils literal"><span class="pre">HashKey</span></tt> acts like a namespace/prefix & the <tt class="docutils literal"><span class="pre">RangeKey</span></tt> acts as a value
93
that can be referred to by a sorted range of values.</p>
94
<p>For the local secondary indexes, you can choose from an <tt class="docutils literal"><span class="pre">AllIndex</span></tt>, a
95
<tt class="docutils literal"><span class="pre">KeysOnlyIndex</span></tt> or a <tt class="docutils literal"><span class="pre">IncludeIndex</span></tt> field. Each builds an index of values
96
that can be queried on. The <tt class="docutils literal"><span class="pre">AllIndex</span></tt> duplicates all values onto the index
97
(to prevent additional reads to fetch the data). The <tt class="docutils literal"><span class="pre">KeysOnlyIndex</span></tt>
98
duplicates only the keys from the schema onto the index. The <tt class="docutils literal"><span class="pre">IncludeIndex</span></tt>
99
lets you specify a list of fieldnames to duplicate over.</p>
100
<p>Simple example:</p>
101
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.fields</span> <span class="kn">import</span> <span class="n">HashKey</span>
102
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
104
<span class="go"># Uses your ``aws_access_key_id`` & ``aws_secret_access_key`` from either a</span>
105
<span class="go"># config file or environment variable & the default region.</span>
106
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="p">[</span>
107
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'username'</span><span class="p">),</span>
108
<span class="gp">... </span><span class="p">])</span>
111
<p>A full example:</p>
112
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">boto.dynamodb2</span>
113
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.fields</span> <span class="kn">import</span> <span class="n">HashKey</span><span class="p">,</span> <span class="n">RangeKey</span><span class="p">,</span> <span class="n">KeysOnlyIndex</span><span class="p">,</span> <span class="n">AllIndex</span>
114
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
115
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.types</span> <span class="kn">import</span> <span class="n">NUMBER</span>
117
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="p">[</span>
118
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">,</span> <span class="n">data_type</span><span class="o">=</span><span class="n">NUMBER</span><span class="p">),</span>
119
<span class="gp">... </span> <span class="n">RangeKey</span><span class="p">(</span><span class="s">'last_name'</span><span class="p">),</span>
120
<span class="gp">... </span><span class="p">],</span> <span class="n">throughput</span><span class="o">=</span><span class="p">{</span>
121
<span class="gp">... </span> <span class="s">'read'</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
122
<span class="gp">... </span> <span class="s">'write'</span><span class="p">:</span> <span class="mi">15</span><span class="p">,</span>
123
<span class="gp">... </span><span class="p">},</span> <span class="n">indexes</span><span class="o">=</span><span class="p">[</span>
124
<span class="gp">... </span> <span class="n">AllIndex</span><span class="p">(</span><span class="s">'EverythingIndex'</span><span class="p">,</span> <span class="n">parts</span><span class="o">=</span><span class="p">[</span>
125
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">,</span> <span class="n">data_type</span><span class="o">=</span><span class="n">NUMBER</span><span class="p">),</span>
126
<span class="gp">... </span> <span class="p">])</span>
127
<span class="gp">... </span><span class="p">],</span>
128
<span class="gp">... </span><span class="c"># If you need to specify custom parameters like keys or region info...</span>
129
<span class="gp">... </span><span class="n">connection</span><span class="o">=</span> <span class="n">boto</span><span class="o">.</span><span class="n">dynamodb2</span><span class="o">.</span><span class="n">connect_to_region</span><span class="p">(</span><span class="s">'us-east-1'</span><span class="p">))</span>
133
<div class="section" id="using-an-existing-table">
134
<h3>Using an Existing Table<a class="headerlink" href="#using-an-existing-table" title="Permalink to this headline">¶</a></h3>
135
<p>Once a table has been created, using it is relatively simple. You can either
136
specify just the <tt class="docutils literal"><span class="pre">table_name</span></tt> (allowing the object to lazily do an additional
137
call to get details about itself if needed) or provide the <tt class="docutils literal"><span class="pre">schema/indexes</span></tt>
138
again (same as what was used with <tt class="docutils literal"><span class="pre">Table.create</span></tt>) to avoid extra overhead.</p>
140
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
141
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
144
<p>Efficient example:</p>
145
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.fields</span> <span class="kn">import</span> <span class="n">HashKey</span><span class="p">,</span> <span class="n">RangeKey</span><span class="p">,</span> <span class="n">AllIndex</span>
146
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
147
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.types</span> <span class="kn">import</span> <span class="n">NUMBER</span>
148
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="p">[</span>
149
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">,</span> <span class="n">data_type</span><span class="o">=</span><span class="n">NUMBER</span><span class="p">),</span>
150
<span class="gp">... </span> <span class="n">RangeKey</span><span class="p">(</span><span class="s">'last_name'</span><span class="p">),</span>
151
<span class="gp">... </span><span class="p">],</span> <span class="n">indexes</span><span class="o">=</span><span class="p">[</span>
152
<span class="gp">... </span> <span class="n">AllIndex</span><span class="p">(</span><span class="s">'EverythingIndex'</span><span class="p">,</span> <span class="n">parts</span><span class="o">=</span><span class="p">[</span>
153
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">,</span> <span class="n">data_type</span><span class="o">=</span><span class="n">NUMBER</span><span class="p">),</span>
154
<span class="gp">... </span> <span class="p">])</span>
155
<span class="gp">... </span><span class="p">])</span>
159
<div class="section" id="creating-a-new-item">
160
<h3>Creating a New Item<a class="headerlink" href="#creating-a-new-item" title="Permalink to this headline">¶</a></h3>
161
<p>Once you have a <tt class="docutils literal"><span class="pre">Table</span></tt> instance, you can add new items to the table. There
162
are two ways to do this.</p>
163
<p>The first is to use the <tt class="docutils literal"><span class="pre">Table.put_item</span></tt> method. Simply hand it a dictionary
164
of data & it will create the item on the server side. This dictionary should
165
be relatively flat (as you can nest in other dictionaries) & <strong>must</strong> contain
166
the keys used in the <tt class="docutils literal"><span class="pre">schema</span></tt>.</p>
168
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
169
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
171
<span class="go"># Create the new user.</span>
172
<span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="p">{</span>
173
<span class="gp">... </span> <span class="s">'username'</span><span class="p">:</span> <span class="s">'johndoe'</span><span class="p">,</span>
174
<span class="gp">... </span> <span class="s">'first_name'</span><span class="p">:</span> <span class="s">'John'</span><span class="p">,</span>
175
<span class="gp">... </span> <span class="s">'last_name'</span><span class="p">:</span> <span class="s">'Doe'</span><span class="p">,</span>
176
<span class="gp">... </span><span class="p">})</span>
177
<span class="go">True</span>
180
<p>The alternative is to manually construct an <tt class="docutils literal"><span class="pre">Item</span></tt> instance & tell it to
181
<tt class="docutils literal"><span class="pre">save</span></tt> itself. This is useful if the object will be around for awhile & you
182
don’t want to re-fetch it.</p>
184
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.items</span> <span class="kn">import</span> <span class="n">Item</span>
185
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
186
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
188
<span class="go"># WARNING - This doens't save it yet!</span>
189
<span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">Item</span><span class="p">(</span><span class="n">users</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span>
190
<span class="gp">... </span> <span class="s">'username'</span><span class="p">:</span> <span class="s">'johndoe'</span><span class="p">,</span>
191
<span class="gp">... </span> <span class="s">'first_name'</span><span class="p">:</span> <span class="s">'John'</span><span class="p">,</span>
192
<span class="gp">... </span> <span class="s">'last_name'</span><span class="p">:</span> <span class="s">'Doe'</span><span class="p">,</span>
193
<span class="gp">... </span><span class="p">})</span>
194
<span class="go"># The data now gets persisted to the server.</span>
195
<span class="gp">>>> </span><span class="n">johndoe</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
196
<span class="go">True</span>
200
<div class="section" id="getting-an-item-accessing-data">
201
<h3>Getting an Item & Accessing Data<a class="headerlink" href="#getting-an-item-accessing-data" title="Permalink to this headline">¶</a></h3>
202
<p>With data now in DynamoDB, if you know the key of the item, you can fetch it
203
back out. Specify the key value(s) as kwargs to <tt class="docutils literal"><span class="pre">Table.get_item</span></tt>.</p>
205
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
206
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
208
<span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
211
<p>Once you have an <tt class="docutils literal"><span class="pre">Item</span></tt> instance, it presents a dictionary-like interface to
213
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
215
<span class="go"># Read a field out.</span>
216
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span>
217
<span class="go">'John'</span>
219
<span class="go"># Change a field (DOESN'T SAVE YET!).</span>
220
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'Johann'</span>
222
<span class="go"># Delete data from it (DOESN'T SAVE YET!).</span>
223
<span class="gp">>>> </span><span class="k">del</span> <span class="n">johndoe</span><span class="p">[</span><span class="s">'last_name'</span><span class="p">]</span>
227
<div class="section" id="updating-an-item">
228
<h3>Updating an Item<a class="headerlink" href="#updating-an-item" title="Permalink to this headline">¶</a></h3>
229
<p>Just creating new items or changing only the in-memory version of the <tt class="docutils literal"><span class="pre">Item</span></tt>
230
isn’t particularly effective. To persist the changes to DynamoDB, you have
232
<p>The first is sending all the data with the expectation nothing has changed
233
since you read the data. DynamoDB will verify the data is in the original state
234
and, if so, will all of the item’s data. If that expectation fails, the call
236
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
237
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'Johann'</span>
238
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'whatever'</span><span class="p">]</span> <span class="o">=</span> <span class="s">"man, that's just like your opinion"</span>
239
<span class="gp">>>> </span><span class="k">del</span> <span class="n">johndoe</span><span class="p">[</span><span class="s">'last_name'</span><span class="p">]</span>
241
<span class="go"># Affects all fields, even the ones not changed locally.</span>
242
<span class="gp">>>> </span><span class="n">johndoe</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
243
<span class="go">True</span>
246
<p>The second is a full overwrite. If you can be confident your version of the
247
data is the most correct, you can force an overwrite of the data.:</p>
248
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
249
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'Johann'</span>
250
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'whatever'</span><span class="p">]</span> <span class="o">=</span> <span class="s">"man, that's just like your opinion"</span>
251
<span class="gp">>>> </span><span class="k">del</span> <span class="n">johndoe</span><span class="p">[</span><span class="s">'last_name'</span><span class="p">]</span>
253
<span class="go"># Specify ``overwrite=True`` to fully replace the data.</span>
254
<span class="gp">>>> </span><span class="n">johndoe</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">overwrite</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
255
<span class="go">True</span>
258
<p>The last is a partial update. If you’ve only modified certain fields, you
259
can send a partial update that only writes those fields, allowing other
260
(potentially changed) fields to go untouched.:</p>
261
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">johndoe</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">get_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
262
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'Johann'</span>
263
<span class="gp">>>> </span><span class="n">johndoe</span><span class="p">[</span><span class="s">'whatever'</span><span class="p">]</span> <span class="o">=</span> <span class="s">"man, that's just like your opinion"</span>
264
<span class="gp">>>> </span><span class="k">del</span> <span class="n">johndoe</span><span class="p">[</span><span class="s">'last_name'</span><span class="p">]</span>
266
<span class="go"># Partial update, only sending/affecting the</span>
267
<span class="go"># ``first_name/whatever/last_name`` fields.</span>
268
<span class="gp">>>> </span><span class="n">johndoe</span><span class="o">.</span><span class="n">partial_save</span><span class="p">()</span>
269
<span class="go">True</span>
273
<div class="section" id="deleting-an-item">
274
<h3>Deleting an Item<a class="headerlink" href="#deleting-an-item" title="Permalink to this headline">¶</a></h3>
275
<p>You can also delete items from the table. You have two choices, depending on
276
what data you have present.</p>
277
<p>If you already have an <tt class="docutils literal"><span class="pre">Item</span></tt> instance, the easiest approach is just to call
278
<tt class="docutils literal"><span class="pre">Item.delete</span></tt>.:</p>
279
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">johndoe</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
280
<span class="go">True</span>
283
<p>If you don’t have an <tt class="docutils literal"><span class="pre">Item</span></tt> instance & you don’t want to incur the
284
<tt class="docutils literal"><span class="pre">Table.get_item</span></tt> call to get it, you can call <tt class="docutils literal"><span class="pre">Table.delete_item</span></tt> method.:</p>
285
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
286
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
288
<span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">delete_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s">'johndoe'</span><span class="p">)</span>
289
<span class="go">True</span>
293
<div class="section" id="batch-writing">
294
<h3>Batch Writing<a class="headerlink" href="#batch-writing" title="Permalink to this headline">¶</a></h3>
295
<p>If you’re loading a lot of data at a time, making use of batch writing can
296
both speed up the process & reduce the number of write requests made to the
298
<p>Batch writing involves wrapping the calls you want batched in a context manager.
299
The context manager immitates the <tt class="docutils literal"><span class="pre">Table.put_item</span></tt> & <tt class="docutils literal"><span class="pre">Table.delete_item</span></tt>
300
APIs. Getting & using the context manager looks like:</p>
301
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
302
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
304
<span class="gp">>>> </span><span class="k">with</span> <span class="n">users</span><span class="o">.</span><span class="n">batch_write</span><span class="p">()</span> <span class="k">as</span> <span class="n">batch</span><span class="p">:</span>
305
<span class="gp">... </span> <span class="n">batch</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="p">{</span>
306
<span class="gp">... </span> <span class="s">'username'</span><span class="p">:</span> <span class="s">'anotherdoe'</span><span class="p">,</span>
307
<span class="gp">... </span> <span class="s">'first_name'</span><span class="p">:</span> <span class="s">'Another'</span><span class="p">,</span>
308
<span class="gp">... </span> <span class="s">'last_name'</span><span class="p">:</span> <span class="s">'Doe'</span><span class="p">,</span>
309
<span class="gp">... </span> <span class="s">'date_joined'</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()),</span>
310
<span class="gp">... </span> <span class="p">})</span>
311
<span class="gp">... </span> <span class="n">batch</span><span class="o">.</span><span class="n">put_item</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="p">{</span>
312
<span class="gp">... </span> <span class="s">'username'</span><span class="p">:</span> <span class="s">'alice'</span><span class="p">,</span>
313
<span class="gp">... </span> <span class="s">'first_name'</span><span class="p">:</span> <span class="s">'Alice'</span><span class="p">,</span>
314
<span class="gp">... </span> <span class="s">'date_joined'</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()),</span>
315
<span class="gp">... </span> <span class="p">})</span>
316
<span class="gp">... </span> <span class="n">batch</span><span class="o">.</span><span class="n">delete_item</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">jane</span><span class="s">')</span>
319
<p>However, there are some limitations on what you can do within the context
322
<li>It can’t read data at all or do batch any other operations.</li>
323
<li>You can’t put & delete the same data within a batch request.</li>
325
<div class="admonition note">
326
<p class="first admonition-title">Note</p>
327
<p class="last">Additionally, the context manager can only batch 25 items at a time for a
328
request (this is a DynamoDB limitation). It is handled for you so you can
329
keep writing additional items, but you should be aware that 100 <tt class="docutils literal"><span class="pre">put_item</span></tt>
330
calls is 4 batch requests, not 1.</p>
333
<div class="section" id="querying">
334
<h3>Querying<a class="headerlink" href="#querying" title="Permalink to this headline">¶</a></h3>
335
<p>Manually fetching out each item by itself isn’t tenable for large datasets.
336
To cope with fetching many records, you can either perform a standard query,
337
query via a local secondary index or scan the entire table.</p>
338
<p>A standard query typically gets run against a hash+range key combination.
339
Filter parameters are passed as kwargs & use a <tt class="docutils literal"><span class="pre">__</span></tt> to separate the fieldname
340
from the operator being used to filter the value.</p>
341
<p>In terms of querying, our original schema is less than optimal. For the
342
following examples, we’ll be using the following table setup:</p>
343
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="p">[</span>
344
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">),</span>
345
<span class="gp">... </span> <span class="n">RangeKey</span><span class="p">(</span><span class="s">'last_name'</span><span class="p">),</span>
346
<span class="gp">... </span><span class="p">],</span> <span class="n">indexes</span><span class="o">=</span><span class="p">[</span>
347
<span class="gp">... </span> <span class="n">AllIndex</span><span class="p">(</span><span class="s">'DateJoinedIndex'</span><span class="p">,</span> <span class="n">parts</span><span class="o">=</span><span class="p">[</span>
348
<span class="gp">... </span> <span class="n">HashKey</span><span class="p">(</span><span class="s">'account_type'</span><span class="p">),</span>
349
<span class="gp">... </span> <span class="n">RangeKey</span><span class="p">(</span><span class="s">'date_joined'</span><span class="p">,</span> <span class="n">data_type</span><span class="o">=</span><span class="n">NUMBER</span><span class="p">),</span>
350
<span class="gp">... </span> <span class="p">]),</span>
351
<span class="gp">... </span><span class="p">])</span>
354
<p>When executing the query, you get an iterable back that contains your results.
355
These results may be spread over multiple requests as DynamoDB paginates them.
356
This is done transparently, but you should be aware it may take more than one
358
<p>To run a query for last names starting with the letter “D”:</p>
359
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">names_with_d</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
360
<span class="gp">... </span> <span class="n">account_type__eq</span><span class="o">=</span><span class="s">'standard_user'</span><span class="p">,</span>
361
<span class="gp">... </span> <span class="n">last_name__beginswith</span><span class="o">=</span><span class="s">'D'</span>
362
<span class="gp">... </span><span class="p">)</span>
364
<span class="gp">>>> </span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">names_with_d</span><span class="p">:</span>
365
<span class="gp">... </span> <span class="k">print</span> <span class="n">user</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span>
366
<span class="go">'Bob'</span>
367
<span class="go">'Jane'</span>
368
<span class="go">'John'</span>
371
<p>You can also reverse results (<tt class="docutils literal"><span class="pre">reverse=True</span></tt>) as well as limiting them
372
(<tt class="docutils literal"><span class="pre">limit=2</span></tt>):</p>
373
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">rev_with_d</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
374
<span class="gp">... </span> <span class="n">account_type__eq</span><span class="o">=</span><span class="s">'standard_user'</span><span class="p">,</span>
375
<span class="gp">... </span> <span class="n">last_name__beginswith</span><span class="o">=</span><span class="s">'D'</span><span class="p">,</span>
376
<span class="gp">... </span> <span class="n">reverse</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
377
<span class="gp">... </span> <span class="n">limit</span><span class="o">=</span><span class="mi">2</span>
378
<span class="gp">... </span><span class="p">)</span>
380
<span class="gp">>>> </span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">rev_with_d</span><span class="p">:</span>
381
<span class="gp">... </span> <span class="k">print</span> <span class="n">user</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span>
382
<span class="go">'John'</span>
383
<span class="go">'Jane'</span>
386
<p>You can also run queries against the local secondary indexes. Simply provide
387
the index name (<tt class="docutils literal"><span class="pre">index='FirstNameIndex'</span></tt>) & filter parameters against its
389
<div class="highlight-python"><pre># Users within the last hour.
390
>>> recent = users.query(
391
... account_type__eq='standard_user',
392
... date_joined__gte=time.time() - (60 * 60),
393
... index='DateJoinedIndex'
396
>>> for user in recent:
397
... print user['first_name']
401
<p>Finally, if you need to query on data that’s not in either a key or in an
402
index, you can run a <tt class="docutils literal"><span class="pre">Table.scan</span></tt> across the whole table, which accepts a
403
similar but expanded set of filters. If you’re familiar with the Map/Reduce
404
concept, this is akin to what DynamoDB does.</p>
405
<div class="admonition warning">
406
<p class="first admonition-title">Warning</p>
407
<p class="last">Scans are consistent & run over the entire table, so relatively speaking,
408
they’re more expensive than plain queries or queries against an LSI.</p>
410
<p>An example scan of all records in the table looks like:</p>
411
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">all_users</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
414
<p>Filtering a scan looks like:</p>
415
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">owners_with_emails</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span>
416
<span class="gp">... </span> <span class="n">is_owner__eq</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
417
<span class="gp">... </span> <span class="n">email__null</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
418
<span class="gp">... </span><span class="p">)</span>
420
<span class="gp">>>> </span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">recent</span><span class="p">:</span>
421
<span class="gp">... </span> <span class="k">print</span> <span class="n">user</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span>
422
<span class="go">'George'</span>
423
<span class="go">'John'</span>
427
<div class="section" id="parallel-scan">
428
<h3>Parallel Scan<a class="headerlink" href="#parallel-scan" title="Permalink to this headline">¶</a></h3>
429
<p>DynamoDB also includes a feature called “Parallel Scan”, which allows you
430
to make use of <strong>extra</strong> read capacity to divide up your result set & scan
431
an entire table faster.</p>
432
<p>This does require extra code on the user’s part & you should ensure that
433
you need the speed boost, have enough data to justify it and have the extra
434
capacity to read it without impacting other queries/scans.</p>
435
<p>To run it, you should pick the <tt class="docutils literal"><span class="pre">total_segments</span></tt> to use, which is an integer
436
representing the number of temporary partitions you’d divide your table into.
437
You then need to spin up a thread/process for each one, giving each
438
thread/process a <tt class="docutils literal"><span class="pre">segment</span></tt>, which is a zero-based integer of the segment
439
you’d like to scan.</p>
440
<p>An example of using parallel scan to send out email to all users might look
442
<div class="highlight-python"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
443
<span class="kn">import</span> <span class="nn">threading</span>
445
<span class="kn">import</span> <span class="nn">boto.ses</span>
446
<span class="kn">import</span> <span class="nn">boto.dynamodb2</span>
447
<span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
450
<span class="n">AWS_ACCESS_KEY_ID</span> <span class="o">=</span> <span class="s">'<YOUR_AWS_KEY_ID>'</span>
451
<span class="n">AWS_SECRET_ACCESS_KEY</span> <span class="o">=</span> <span class="s">'<YOUR_AWS_SECRET_KEY>'</span>
452
<span class="n">APPROVED_EMAIL</span> <span class="o">=</span> <span class="s">'some@address.com'</span>
455
<span class="k">def</span> <span class="nf">send_email</span><span class="p">(</span><span class="n">email</span><span class="p">):</span>
456
<span class="c"># Using Amazon's Simple Email Service, send an email to a given</span>
457
<span class="c"># email address. You must already have an email you've verified with</span>
458
<span class="c"># AWS before this will work.</span>
459
<span class="n">conn</span> <span class="o">=</span> <span class="n">boto</span><span class="o">.</span><span class="n">ses</span><span class="o">.</span><span class="n">connect_to_region</span><span class="p">(</span>
460
<span class="s">'us-east-1'</span><span class="p">,</span>
461
<span class="n">aws_access_key_id</span><span class="o">=</span><span class="n">AWS_ACCESS_KEY_ID</span><span class="p">,</span>
462
<span class="n">aws_secret_access_key</span><span class="o">=</span><span class="n">AWS_SECRET_ACCESS_KEY</span>
463
<span class="p">)</span>
464
<span class="n">conn</span><span class="o">.</span><span class="n">send_email</span><span class="p">(</span>
465
<span class="n">APPROVED_EMAIL</span><span class="p">,</span>
466
<span class="s">"[OurSite] New feature alert!"</span><span class="p">,</span>
467
<span class="s">"We've got some exciting news! We added a new feature to..."</span><span class="p">,</span>
468
<span class="p">[</span><span class="n">email</span><span class="p">]</span>
469
<span class="p">)</span>
472
<span class="k">def</span> <span class="nf">process_segment</span><span class="p">(</span><span class="n">segment</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">total_segments</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span>
473
<span class="c"># This method/function is executed in each thread, each getting its</span>
474
<span class="c"># own segment to process through.</span>
475
<span class="n">conn</span> <span class="o">=</span> <span class="n">boto</span><span class="o">.</span><span class="n">dynamodb2</span><span class="o">.</span><span class="n">connect_to_region</span><span class="p">(</span>
476
<span class="s">'us-east-1'</span><span class="p">,</span>
477
<span class="n">aws_access_key_id</span><span class="o">=</span><span class="n">AWS_ACCESS_KEY_ID</span><span class="p">,</span>
478
<span class="n">aws_secret_access_key</span><span class="o">=</span><span class="n">AWS_SECRET_ACCESS_KEY</span>
479
<span class="p">)</span>
480
<span class="n">table</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">connection</span><span class="o">=</span><span class="n">conn</span><span class="p">)</span>
482
<span class="c"># We pass in the segment & total_segments to scan here.</span>
483
<span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">table</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span><span class="n">segment</span><span class="o">=</span><span class="n">segment</span><span class="p">,</span> <span class="n">total_segments</span><span class="o">=</span><span class="n">total_segments</span><span class="p">):</span>
484
<span class="n">send_email</span><span class="p">(</span><span class="n">user</span><span class="p">[</span><span class="s">'email'</span><span class="p">])</span>
487
<span class="k">def</span> <span class="nf">send_all_emails</span><span class="p">():</span>
488
<span class="n">pool</span> <span class="o">=</span> <span class="p">[]</span>
489
<span class="c"># We're choosing to divide the table in 3, then...</span>
490
<span class="n">pool_size</span> <span class="o">=</span> <span class="mi">3</span>
492
<span class="c"># ...spinning up a thread for each segment.</span>
493
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">pool_size</span><span class="p">):</span>
494
<span class="n">worker</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span>
495
<span class="n">target</span><span class="o">=</span><span class="n">process_segment</span><span class="p">,</span>
496
<span class="n">kwargs</span><span class="o">=</span><span class="p">{</span>
497
<span class="s">'segment'</span><span class="p">:</span> <span class="n">i</span><span class="p">,</span>
498
<span class="s">'total_segments'</span><span class="p">:</span> <span class="n">pool_size</span><span class="p">,</span>
499
<span class="p">}</span>
500
<span class="p">)</span>
501
<span class="n">pool</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">worker</span><span class="p">)</span>
502
<span class="c"># We start them to let them start scanning & consuming their</span>
503
<span class="c"># assigned segment.</span>
504
<span class="n">worker</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
506
<span class="c"># Finally, we wait for each to finish.</span>
507
<span class="k">for</span> <span class="n">thread</span> <span class="ow">in</span> <span class="n">pool</span><span class="p">:</span>
508
<span class="n">thread</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
511
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
512
<span class="n">send_all_emails</span><span class="p">()</span>
516
<div class="section" id="batch-reading">
517
<h3>Batch Reading<a class="headerlink" href="#batch-reading" title="Permalink to this headline">¶</a></h3>
518
<p>Similar to batch writing, batch reading can also help reduce the number of
519
API requests necessary to access a large number of items. The
520
<tt class="docutils literal"><span class="pre">Table.batch_get</span></tt> method takes a list (or any sliceable collection) of keys
521
& fetches all of them, presented as an iterator interface.</p>
522
<p>This is done lazily, so if you never iterate over the results, no requests are
523
executed. Additionally, if you only iterate over part of the set, the minumum
524
number of calls are made to fetch those results (typically max 100 per
527
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">boto.dynamodb2.table</span> <span class="kn">import</span> <span class="n">Table</span>
528
<span class="gp">>>> </span><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">)</span>
530
<span class="go"># No request yet.</span>
531
<span class="gp">>>> </span><span class="n">many_users</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">batch_get</span><span class="p">(</span><span class="n">keys</span><span class="o">=</span><span class="p">[</span>
532
<span class="go"> {'username': 'alice'},</span>
533
<span class="go"> {'username': 'bob'},</span>
534
<span class="go"> {'username': 'fred'},</span>
535
<span class="go"> {'username': 'jane'},</span>
536
<span class="go"> {'username': 'johndoe'},</span>
537
<span class="go">])</span>
539
<span class="go"># Now the request is performed, requesting all five in one request.</span>
540
<span class="gp">>>> </span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">many_users</span><span class="p">:</span>
541
<span class="gp">... </span> <span class="k">print</span> <span class="n">user</span><span class="p">[</span><span class="s">'first_name'</span><span class="p">]</span>
542
<span class="go">'Alice'</span>
543
<span class="go">'Bobby'</span>
544
<span class="go">'Fred'</span>
545
<span class="go">'Jane'</span>
546
<span class="go">'John'</span>
550
<div class="section" id="deleting-a-table">
551
<h3>Deleting a Table<a class="headerlink" href="#deleting-a-table" title="Permalink to this headline">¶</a></h3>
552
<p>Deleting a table is a simple exercise. When you no longer need a table, simply
554
<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
558
<div class="section" id="dynamodb-local">
559
<h3>DynamoDB Local<a class="headerlink" href="#dynamodb-local" title="Permalink to this headline">¶</a></h3>
560
<p><a class="reference external" href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.html">Amazon DynamoDB Local</a> is a utility which can be used to mock DynamoDB
561
during development. Connecting to a running DynamoDB Local server is easy:</p>
562
<div class="highlight-python"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
563
<span class="kn">from</span> <span class="nn">boto.dynamodb2.layer1</span> <span class="kn">import</span> <span class="n">DynamoDBConnection</span>
566
<span class="c"># Connect to DynamoDB Local</span>
567
<span class="n">conn</span> <span class="o">=</span> <span class="n">DynamoDBConnection</span><span class="p">(</span>
568
<span class="n">host</span><span class="o">=</span><span class="s">'localhost'</span><span class="p">,</span>
569
<span class="n">port</span><span class="o">=</span><span class="mi">8000</span><span class="p">,</span>
570
<span class="n">aws_secret_access_key</span><span class="o">=</span><span class="s">'anything'</span><span class="p">,</span>
571
<span class="n">is_secure</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
573
<span class="c"># List all local tables</span>
574
<span class="n">tables</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">list_tables</span><span class="p">()</span>
578
<div class="section" id="next-steps">
579
<h3>Next Steps<a class="headerlink" href="#next-steps" title="Permalink to this headline">¶</a></h3>
580
<p>You can find additional information about other calls & parameter options
581
in the <a class="reference internal" href="ref/dynamodb2.html"><em>API docs</em></a>.</p>
590
<div class="sphinxsidebar">
591
<div class="sphinxsidebarwrapper">
592
<h3><a href="index.html">Table Of Contents</a></h3>
594
<li><a class="reference internal" href="#">An Introduction to boto’s DynamoDB v2 interface</a><ul>
595
<li><a class="reference internal" href="#the-high-level-api">The High-Level API</a><ul>
596
<li><a class="reference internal" href="#creating-a-new-table">Creating a New Table</a></li>
597
<li><a class="reference internal" href="#using-an-existing-table">Using an Existing Table</a></li>
598
<li><a class="reference internal" href="#creating-a-new-item">Creating a New Item</a></li>
599
<li><a class="reference internal" href="#getting-an-item-accessing-data">Getting an Item & Accessing Data</a></li>
600
<li><a class="reference internal" href="#updating-an-item">Updating an Item</a></li>
601
<li><a class="reference internal" href="#deleting-an-item">Deleting an Item</a></li>
602
<li><a class="reference internal" href="#batch-writing">Batch Writing</a></li>
603
<li><a class="reference internal" href="#querying">Querying</a></li>
604
<li><a class="reference internal" href="#parallel-scan">Parallel Scan</a></li>
605
<li><a class="reference internal" href="#batch-reading">Batch Reading</a></li>
606
<li><a class="reference internal" href="#deleting-a-table">Deleting a Table</a></li>
607
<li><a class="reference internal" href="#dynamodb-local">DynamoDB Local</a></li>
608
<li><a class="reference internal" href="#next-steps">Next Steps</a></li>
615
<h4>Previous topic</h4>
616
<p class="topless"><a href="support_tut.html"
617
title="previous chapter">An Introduction to boto’s Support interface</a></p>
619
<p class="topless"><a href="migrations/dynamodb_v1_to_v2.html"
620
title="next chapter">Migrating from DynamoDB v1 to DynamoDB v2</a></p>
622
<ul class="this-page-menu">
623
<li><a href="_sources/dynamodb2_tut.txt"
624
rel="nofollow">Show Source</a></li>
626
<div id="searchbox" style="display: none">
627
<h3>Quick search</h3>
628
<form class="search" action="search.html" method="get">
629
<input type="text" name="q" />
630
<input type="submit" value="Go" />
631
<input type="hidden" name="check_keywords" value="yes" />
632
<input type="hidden" name="area" value="default" />
634
<p class="searchtip" style="font-size: 90%">
635
Enter search terms or a module, class or function name.
638
<script type="text/javascript">$('#searchbox').show(0);</script><div><a href="boto.pdf">PDF Version</a></div>
641
<div class="clearer"></div>
643
<div class="related">
646
<li class="right" style="margin-right: 10px">
647
<a href="genindex.html" title="General Index"
650
<a href="py-modindex.html" title="Python Module Index"
653
<a href="migrations/dynamodb_v1_to_v2.html" title="Migrating from DynamoDB v1 to DynamoDB v2"
656
<a href="support_tut.html" title="An Introduction to boto’s Support interface"
658
<li><a href="index.html">boto v2.16.0</a> »</li>
662
© Copyright 2009,2010, Mitch Garnaat.
663
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
b'\\ No newline at end of file'