Skip to content

Can't use the discriminator as a primary key in indexes. #1000

Open
@abcydybcy

Description

@abcydybcy

Hi,
I've run into a problem with PynamoDB: I wanted to list all objects of a given type, but avoid using scan. I can't use an index, in which the discriminator is the primary key.

Example output (notice the first line).

BUG:pynamodb.connection.base:Calling Query with arguments {'TableName': 'test-table-1234', 'KeyConditionExpression': '#0 = :0', 'FilterExpression': '#0 IN (:1, :2)', 'IndexName': 'type_index', 'ExpressionAttributeNames': {'#0': 'type'}, 'ExpressionAttributeValues': {':0': {'S': 'user'}, ':1': {'S': 'user'}, ':2': {'S': 'group'}}, 'ReturnConsumedCapacity': 'TOTAL'}
DEBUG:botocore.hooks:Event before-parameter-build.dynamodb.Query: calling handler <function generate_idempotent_uuid at 0x103777a60>
DEBUG:botocore.hooks:Event before-parameter-build.dynamodb.Query: calling handler <function block_endpoint_discovery_required_operations at 0x1036c4d30>
DEBUG:botocore.auth:Calculating signature using v4 auth.
DEBUG:botocore.auth:CanonicalRequest:
POST
/

content-type:application/x-amz-json-1.0
host:dynamodb.eu-west-1.amazonaws.com
x-amz-date:20211129T163717Z
x-amz-security-token: ---

content-type;host;x-amz-date;x-amz-security-token;x-amz-target
a59ab9b0c3b122603f12e5cfe46020899ce8049b56f790b4f57624d06dbd4874
DEBUG:botocore.auth:StringToSign:
AWS4-HMAC-SHA256
20211129T163717Z
20211129/eu-west-1/dynamodb/aws4_request
b0edb2380f43edb04697e68de7150e6743491d52b379e6df5512eee3ab1f704b
DEBUG:botocore.auth:Signature:
df460887d908a2db232bcb69042424b37f6b227eb53a77dad760069a711c9be2
DEBUG:botocore.httpsession:Certificate path: /Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/botocore/cacert.pem
DEBUG:urllib3.connectionpool:https://dynamodb.eu-west-1.amazonaws.com:443 "POST / HTTP/1.1" 400 161
DEBUG:pynamodb.connection.base:Calling DeleteTable with arguments {'TableName': 'test-table-1234'}
DEBUG:botocore.hooks:Event before-parameter-build.dynamodb.DeleteTable: calling handler <function generate_idempotent_uuid at 0x103777a60>
DEBUG:botocore.hooks:Event before-parameter-build.dynamodb.DeleteTable: calling handler <function block_endpoint_discovery_required_operations at 0x1036c4d30>
DEBUG:botocore.auth:Calculating signature using v4 auth.
DEBUG:botocore.auth:CanonicalRequest:
POST
/

content-type:application/x-amz-json-1.0
host:dynamodb.eu-west-1.amazonaws.com
x-amz-date:20211129T163717Z
x-amz-security-token: ---
x-amz-target:DynamoDB_20120810.DeleteTable

content-type;host;x-amz-date;x-amz-security-token;x-amz-target
06d198ac62ba8fda04ad1ea0035c6f0d13afa201e775f979a968d05da3334522
DEBUG:botocore.auth:StringToSign:
AWS4-HMAC-SHA256
20211129T163717Z
20211129/eu-west-1/dynamodb/aws4_request
364ed68b24bcc49e0afbc665c3a01e40374cd0691b5ecd7b2cb7722a44dcd778
DEBUG:botocore.auth:Signature:
94262ec8d585ab0cd4bfad5d9e5dcc3c429af853f0d74f566253d835d026d133
DEBUG:botocore.httpsession:Certificate path: /Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/botocore/cacert.pem
DEBUG:urllib3.connectionpool:https://dynamodb.eu-west-1.amazonaws.com:443 "POST / HTTP/1.1" 200 332
Traceback (most recent call last):
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/connection/base.py", line 1333, in query
    return self.dispatch(QUERY, operation_kwargs, settings)
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/connection/base.py", line 329, in dispatch
    data = self._make_api_call(operation_name, operation_kwargs, settings)
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/connection/base.py", line 440, in _make_api_call
    raise VerboseClientError(botocore_expected_format, operation_name, verbose_properties)
pynamodb.exceptions.VerboseClientError: An error occurred (ValidationException) on request (V50EJSD64U1GCHQ6B499PCNVEFVV4KQNSO5AEMVJF66Q9ASUAAJG) on table (test-table-1234) when calling the Query operation: Filter Expression can only contain non-primary key attributes: Primary key attribute: type

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "bug.py", line 49, in <module>
    print([user for user in User.type_index.query("user")])
  File "bug.py", line 49, in <listcomp>
    print([user for user in User.type_index.query("user")])
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/pagination.py", line 194, in __next__
    self._get_next_page()
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/pagination.py", line 179, in _get_next_page
    page = next(self.page_iter)
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/pagination.py", line 115, in __next__
    page = self._operation(*self._args, settings=self._settings, **self._kwargs)
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/connection/table.py", line 270, in query
    return self.connection.query(
  File "/Users/f0ff/Code/tameshi/framework/venv/lib/python3.8/site-packages/pynamodb/connection/base.py", line 1335, in query
    raise QueryError("Failed to query items: {}".format(e), e)
pynamodb.exceptions.QueryError: Failed to query items: An error occurred (ValidationException) on request (V50EJSD64U1GCHQ6B499PCNVEFVV4KQNSO5AEMVJF66Q9ASUAAJG) on table (test-table-1234) when calling the Query operation: Filter Expression can only contain non-primary key attributes: Primary key attribute: type

Code to recreate:

import logging
from pynamodb.models import Model
from pynamodb.attributes import UnicodeAttribute, DiscriminatorAttribute
from pynamodb.indexes import GlobalSecondaryIndex, IncludeProjection


class TypeIndex(GlobalSecondaryIndex):
    class Meta:
        index_name = "type_index"
        read_capacity_units = 1
        write_capacity_units = 1
        region = "eu-west-1"
        projection = IncludeProjection(["type", "path"])

    type = UnicodeAttribute(hash_key=True)


class CoreModel(Model):
    class Meta:
        table_name = "test-table-1234"
        read_capacity_units = 2
        write_capacity_units = 1
        region = "eu-west-1"

    path = UnicodeAttribute(hash_key=True)
    type = DiscriminatorAttribute()

    type_index = TypeIndex()


class User(CoreModel, discriminator="user"):
    pass


class Group(CoreModel, discriminator="group"):
    pass


if __name__ == "__main__":
    CoreModel.create_table(wait=True)

    # Load some test data
    user1 = User("user.user1")
    user1.save()

    logging.basicConfig(level=logging.DEBUG)

    try:
        print([user for user in User.type_index.query("user")])
    finally:
        CoreModel.delete_table()

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions