Install & Compatibility
Where this runs
tested against v6.1.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.589s · 50.1MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 3.2s · import 0.534s · 51MB
48MB installed
● package 48MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
Model
✓ from pynamodb.models import Model
Attribute types
✓ from pynamodb.attributes import UnicodeAttribute, NumberAttribute, MapAttribute, ListAttribute, BooleanAttribute
DoesNotExist
✓ from pynamodb.exceptions import DoesNotExist
✗ if item is None: # for Model.get() pre-6.0.0
As of v6.0.0, Model.get() raises DoesNotExist instead of returning None.
settings
✓ from pynamodb import settings
Used for global configuration, e.g., thread_local_connection.
This quickstart demonstrates defining a basic PynamoDB Model, creating its corresponding DynamoDB table (if it doesn't exist), saving a new item, retrieving an item by its hash key, and updating an item. It highlights common configuration options for AWS region and local DynamoDB setup.
import os
from pynamodb.models import Model
from pynamodb.attributes import UnicodeAttribute, NumberAttribute
from pynamodb.exceptions import DoesNotExist
# Configure AWS credentials and region via environment variables
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION
# For local DynamoDB, set DYNAMODB_HOST, e.g., 'http://localhost:8000'
class Product(Model):
class Meta:
table_name = os.environ.get('PRODUCT_TABLE_NAME', 'dev-products-table')
region = os.environ.get('AWS_REGION', 'us-east-1')
host = os.environ.get('DYNAMODB_HOST', None) # Set for local DynamoDB
# Optional: read_capacity_units and write_capacity_units are needed for new tables
product_id = UnicodeAttribute(hash_key=True)
name = UnicodeAttribute()
price = NumberAttribute(default=0)
description = UnicodeAttribute(null=True)
# Create table if it doesn't exist
if not Product.exists():
print(f"Creating table '{Product.Meta.table_name}'...")
Product.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
print(f"Table '{Product.Meta.table_name}' created.")
# Create an item
product = Product(product_id='P123', name='Laptop', price=1200.50, description='High-performance laptop')
product.save()
print(f"Product saved: {product.product_id}")
# Get an item
try:
retrieved_product = Product.get('P123')
print(f"Retrieved product: {retrieved_product.name}, Price: {retrieved_product.price}")
except DoesNotExist:
print("Product not found.")
# Update an item
retrieved_product.update(actions=[
Product.price.set(1150.00),
Product.description.set('Updated description for the laptop')
])
print(f"Product updated: {retrieved_product.product_id}, New price: {retrieved_product.price}")
# Delete an item
# retrieved_product.delete()
# print(f"Product {retrieved_product.product_id} deleted.")
Debug
Known issues
breaking`Model.get()` now raises `pynamodb.exceptions.DoesNotExist` instead of returning `None` when an item is not found.fixUpdate `Model.get()` calls to wrap them in a `try...except DoesNotExist` block. If `None` return behavior is desired, pass `consistent_read=False` to `get()`.
affects: 6.0.0 and later
breaking`Model.query()` and `Model.scan()` no longer return lists by default, but iterators. The `query_count` and `scan_count` methods have been removed.fixIterate directly over the results of `query()` or `scan()`. If a list is required, cast the iterator to a list (e.g., `list(Model.query(...))`). Implement custom logic for counting if needed.
affects: 6.0.0 and later
gotchaPynamoDB frequently encounters compatibility issues with specific `botocore` versions, often requiring users to pin `botocore` or upgrade PynamoDB.fixEnsure `botocore` is within the range specified by `pynamodb`'s `install_requires`. If issues arise, check PynamoDB's GitHub releases or issues for known `botocore` incompatibilities and suggested version pins.
affects: All versions, historically (e.g., 4.x, 5.x, 6.x)
gotchaWhen using local DynamoDB, the `host` setting in `Model.Meta` or the `DYNAMODB_HOST` environment variable must be explicitly configured (e.g., `'http://localhost:8000'`).fixSet `host` in `Model.Meta` or ensure the `DYNAMODB_HOST` environment variable is correctly set before initializing models.
affects: All versions
deprecatedSeveral internal classes and functions, including `PynamoDBConnection`, `PynamoDBException`, and `PynamoDBVersionError` were removed as part of a cleanup.fixMigrate to `pynamodb.connection.Connection` and catch more specific exceptions like `pynamodb.exceptions.TableDoesNotExist` or general `botocore.exceptions.ClientError`.
affects: 6.0.0 and later
Errors
Common errors & fixes
ValidationException: The provided key element does not match the schema.
This error occurs when a get or query operation is attempted with an incomplete or incorrect primary key (hash key and range key if defined), or when trying to use get_item on a secondary index, which is not supported.
fixEnsure all primary key attributes (hash and range key) are provided for get operations. For secondary indexes, use query instead of get_item, and ensure the query uses the index's defined keys.
ConditionalCheckFailedException
This exception is raised during a save(), update(), or delete() operation when a specified condition on the item is not met, often due to optimistic locking where the item's version has changed concurrently.
fixHandle the ConditionalCheckFailedException by re-fetching the item, applying the desired changes, and retrying the operation. For optimistic locking, this involves re-retrieving the item to get the latest version. If conditional checks are not desired for a specific update, `add_version_condition=False` can be passed to `update` (use with caution).
TypeError: Object of type 'MapAttribute' is not JSON serializable
PynamoDB's MapAttribute objects are not standard Python dictionaries and thus cannot be directly serialized to JSON by default JSON encoders or frameworks like Flask.
fixConvert the MapAttribute instance to a Python dictionary using the `.as_dict()` method before JSON serialization.
AttributeNullError: Raised when an attribute which is not nullable (:code:null=False) is unset during serialization.
This occurs when attempting to save a PynamoDB model with a None value for an attribute that was defined with null=False (the default), as PynamoDB prevents None values from being written to DynamoDB for non-nullable attributes. A related error, `TypeError: 'NoneType' object is not iterable`, can also occur if PynamoDB encounters an unexpected None during key schema processing.
fixEnsure that attributes defined with `null=False` always have a non-None value before saving. If an attribute can legitimately be None, define it explicitly with `null=True` in the model definition.
AttributeError: As of v1.0 PynamoDB Models require a `Meta` class with a table_name property.
A PynamoDB Model subclass is missing the required inner Meta class or the table_name attribute within it, which PynamoDB needs to associate the model with a DynamoDB table.
fixDefine an inner `Meta` class within your model, and specify the `table_name` attribute. For example: `class MyModel(Model): class Meta: table_name = 'my-table-name'`.
Upgrade
Version history
6.1.0latest on PyPI · released Jun 2, 2025
Audit
Dependencies
botocorerequiredCore AWS SDK dependency; frequent compatibility issues across minor versions.