AWS code-library documentation change
Summary
Restructured Python DynamoDB code examples, added class-based implementations, improved documentation comments, and expanded query examples with projection expressions and dynamic filters
Security assessment
Changes focus on code structure improvements, added query functionality, and documentation clarity. No security vulnerabilities addressed or security features documented. Changes include error handling improvements but these are general best practices rather than security-specific fixes.
Diff
diff --git a/code-library/latest/ug/python_3_dynamodb_code_examples.md b/code-library/latest/ug/python_3_dynamodb_code_examples.md index c8851f869..c249657f1 100644 --- a//code-library/latest/ug/python_3_dynamodb_code_examples.md +++ b//code-library/latest/ug/python_3_dynamodb_code_examples.md @@ -1695 +1695 @@ The following code example shows how to use `Query`. - * Use the begins_with function in a key condition expression. +**SDK for Python (Boto3)** @@ -1697 +1696,0 @@ The following code example shows how to use `Query`. - * Filter items based on a prefix pattern in the sort key. @@ -1698,0 +1698 @@ The following code example shows how to use `Query`. +###### Note @@ -1699,0 +1700 @@ The following code example shows how to use `Query`. +There's more on GitHub. Find the complete example and learn how to set up and run in the [AWS Code Examples Repository](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/dynamodb#code-examples). @@ -1700,0 +1702 @@ The following code example shows how to use `Query`. +Query items by using a key condition expression. @@ -1702 +1703,0 @@ The following code example shows how to use `Query`. -**SDK for Python (Boto3)** @@ -1703,0 +1705,2 @@ The following code example shows how to use `Query`. + class Movies: + """Encapsulates an Amazon DynamoDB table of movie data. @@ -1705 +1708,19 @@ The following code example shows how to use `Query`. -Query a DynamoDB table using a begins_with condition on the sort key with AWS SDK for Python (Boto3). + Example data structure for a movie record in this table: + { + "year": 1999, + "title": "For Love of the Game", + "info": { + "directors": ["Sam Raimi"], + "release_date": "1999-09-15T00:00:00Z", + "rating": 6.3, + "plot": "A washed up pitcher flashes through his career.", + "rank": 4987, + "running_time_secs": 8220, + "actors": [ + "Kevin Costner", + "Kelly Preston", + "John C. Reilly" + ] + } + } + """ @@ -1706,0 +1728,8 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD + def __init__(self, dyn_resource): + """ + :param dyn_resource: A Boto3 DynamoDB resource. + """ + self.dyn_resource = dyn_resource + # The table variable is set during the scenario in the call to + # 'exists' if the table exists. Otherwise, it is set by 'create_table'. + self.table = None @@ -1708,2 +1736,0 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - import boto3 - from boto3.dynamodb.conditions import Key @@ -1710,0 +1738,3 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD + def query_movies(self, year): + """ + Queries for movies that were released in the specified year. @@ -1712,3 +1742,2 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - def query_with_begins_with( - table_name, partition_key_name, partition_key_value, sort_key_name, prefix - ): + :param year: The year to query. + :return: The list of movies that were released in the specified year. @@ -1716 +1745,12 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - Query a DynamoDB table with a begins_with condition on the sort key. + try: + response = self.table.query(KeyConditionExpression=Key("year").eq(year)) + except ClientError as err: + logger.error( + "Couldn't query for movies released in %s. Here's why: %s: %s", + year, + err.response["Error"]["Code"], + err.response["Error"]["Message"], + ) + raise + else: + return response["Items"] @@ -1718,6 +1757,0 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - Args: - table_name (str): The name of the DynamoDB table. - partition_key_name (str): The name of the partition key attribute. - partition_key_value (str): The value of the partition key to query. - sort_key_name (str): The name of the sort key attribute. - prefix (str): The prefix to match at the beginning of the sort key. @@ -1725,6 +1758,0 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - Returns: - dict: The response from DynamoDB containing the query results. - """ - # Initialize the DynamoDB resource - dynamodb = boto3.resource("dynamodb") - table = dynamodb.Table(table_name) @@ -1732,5 +1759,0 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - # Perform the query with a begins_with condition on the sort key - key_condition = Key(partition_key_name).eq(partition_key_value) & Key( - sort_key_name - ).begins_with(prefix) - response = table.query(KeyConditionExpression=key_condition) @@ -1738 +1761,13 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD - return response +Query items and project them to return a subset of data. + + + class UpdateQueryWrapper: + def __init__(self, table): + self.table = table + + + def query_and_project_movies(self, year, title_bounds): + """ + Query for movies that were released in a specified year and that have titles + that start within a range of letters. A projection expression is used + to return a subset of data for each movie. @@ -1739,0 +1775,31 @@ Query a DynamoDB table using a begins_with condition on the sort key with AWS SD + :param year: The release year to query. + :param title_bounds: The range of starting letters to query. + :return: The list of movies. + """ + try: + response = self.table.query( + ProjectionExpression="#yr, title, info.genres, info.actors[0]", + ExpressionAttributeNames={"#yr": "year"}, + KeyConditionExpression=( + Key("year").eq(year) + & Key("title").between( + title_bounds["first"], title_bounds["second"] + ) + ), + ) + except ClientError as err: + if err.response["Error"]["Code"] == "ValidationException": + logger.warning( + "There's a validation error. Here's the message: %s: %s", + err.response["Error"]["Code"], + err.response["Error"]["Message"], + ) + else: + logger.error( + "Couldn't query for movies. Here's why: %s: %s", + err.response["Error"]["Code"], + err.response["Error"]["Message"], + ) + raise + else: + return response["Items"] @@ -3254,0 +3321,134 @@ Query with complex filters using AWS SDK for Python (Boto3). +Query with a dynamically constructed filter expression using AWS SDK for Python (Boto3). + + + import boto3 + from boto3.dynamodb.conditions import Attr, Key + + + def query_with_dynamic_filter( + table_name, partition_key_name, partition_key_value, filter_conditions=None + ): + """ + Query a DynamoDB table with a dynamically constructed filter expression. + + Args: + table_name (str): The name of the DynamoDB table. + partition_key_name (str): The name of the partition key attribute. + partition_key_value (str): The value of the partition key to query. + filter_conditions (dict, optional): A dictionary of filter conditions where + keys are attribute names and values are dictionaries with 'operator' and 'value'. + Example: {'rating': {'operator': '>=', 'value': 4}, 'status': {'operator': '=', 'value': 'active'}} + + Returns: + dict: The response from DynamoDB containing the query results. + """ + # Initialize the DynamoDB resource + dynamodb = boto3.resource("dynamodb") + table = dynamodb.Table(table_name) + + # Start with the key condition expression + key_condition = Key(partition_key_name).eq(partition_key_value) + + # Initialize variables for the filter expression and attribute values + filter_expression = None + expression_attribute_values = {":pk_val": partition_key_value} + + # Dynamically build the filter expression if filter conditions are provided + if filter_conditions: + for attr_name, condition in filter_conditions.items(): + operator = condition.get("operator") + value = condition.get("value") + attr_value_name = f":{attr_name}" + expression_attribute_values[attr_value_name] = value + + # Create the appropriate filter expression based on the operator + current_condition = None + if operator == "=": + current_condition = Attr(attr_name).eq(value) + elif operator == "!=": + current_condition = Attr(attr_name).ne(value) + elif operator == ">": + current_condition = Attr(attr_name).gt(value) + elif operator == ">=": + current_condition = Attr(attr_name).gte(value) + elif operator == "<": + current_condition = Attr(attr_name).lt(value)