diff --git a/pynamodb/models.py b/pynamodb/models.py index 3e56c5787..d3bb6d13a 100644 --- a/pynamodb/models.py +++ b/pynamodb/models.py @@ -478,11 +478,16 @@ def from_raw_data(cls, data): hash_keyname = cls.meta().hash_keyname range_keyname = cls.meta().range_keyname hash_key_type = cls.meta().get_attribute_type(hash_keyname) - args = (mutable_data.pop(hash_keyname).get(hash_key_type),) + hash_key = mutable_data.pop(hash_keyname).get(hash_key_type) + hash_key_attr = cls.get_attributes().get(hash_keyname) + hash_key = hash_key_attr.deserialize(hash_key) + args = (hash_key,) kwargs = {} if range_keyname: + range_key_attr = cls.get_attributes().get(range_keyname) range_key_type = cls.meta().get_attribute_type(range_keyname) - kwargs['range_key'] = mutable_data.pop(range_keyname).get(range_key_type) + range_key = mutable_data.pop(range_keyname).get(range_key_type) + kwargs['range_key'] = range_key_attr.deserialize(range_key) for name, value in mutable_data.items(): attr = cls.get_attributes().get(name, None) if attr: diff --git a/pynamodb/tests/data.py b/pynamodb/tests/data.py index a9edb0459..0728ba545 100644 --- a/pynamodb/tests/data.py +++ b/pynamodb/tests/data.py @@ -179,6 +179,20 @@ } } } +COMPLEX_ITEM_DATA = { + "ConsumedCapacity": { + "CapacityUnits": 1, + "TableName": "Thread" + }, + 'Item': { + 'date_created': { + 'S': '2014-02-03T23:58:10.963333+0000' + }, + 'name': { + 'S': 'bar' + } + } +} GET_ITEM_DATA = { "ConsumedCapacity": { @@ -231,3 +245,34 @@ ] } } + +COMPLEX_TABLE_DATA = { + 'Table': { + 'ItemCount': 0, 'TableName': 'ComplexKey', + 'ProvisionedThroughput': { + 'ReadCapacityUnits': 2, + 'WriteCapacityUnits': 2, + 'NumberOfDecreasesToday': 0 + }, + 'CreationDateTime': 1391471876.86, + 'TableStatus': 'ACTIVE', + 'AttributeDefinitions': [ + { + 'AttributeName': 'date_created', 'AttributeType': 'S' + }, + { + 'AttributeName': 'name', 'AttributeType': 'S' + } + ], + 'KeySchema': [ + { + 'AttributeName': 'name', 'KeyType': 'HASH' + }, + { + 'AttributeName': 'date_created', 'KeyType': 'RANGE' + } + ], + 'TableSizeBytes': 0 + } +} + diff --git a/pynamodb/tests/test_model.py b/pynamodb/tests/test_model.py index 54d5d2a30..4627441ab 100644 --- a/pynamodb/tests/test_model.py +++ b/pynamodb/tests/test_model.py @@ -3,6 +3,7 @@ """ import copy import six +from datetime import datetime from pynamodb.throttle import Throttle from pynamodb.connection.util import pythonic from pynamodb.connection.exceptions import TableError @@ -17,13 +18,15 @@ IncludeProjection, KeysOnlyProjection, Index ) from pynamodb.attributes import ( - UnicodeAttribute, NumberAttribute, BinaryAttribute, + UnicodeAttribute, NumberAttribute, BinaryAttribute, UTCDateTimeAttribute, UnicodeSetAttribute, NumberSetAttribute, BinarySetAttribute) from unittest import TestCase from .response import HttpOK, HttpBadRequest from .data import ( MODEL_TABLE_DATA, GET_MODEL_ITEM_DATA, SIMPLE_MODEL_TABLE_DATA, - BATCH_GET_ITEMS, SIMPLE_BATCH_GET_ITEMS) + BATCH_GET_ITEMS, SIMPLE_BATCH_GET_ITEMS, COMPLEX_TABLE_DATA, + COMPLEX_ITEM_DATA +) # Py2/3 if six.PY3: @@ -117,6 +120,15 @@ class UserModel(Model): callable_field = NumberAttribute(default=lambda: 42) +class ComplexKeyModel(Model): + """ + This model has a key that must be serialized/deserialized properly + """ + table_name = 'ComplexKey' + name = UnicodeAttribute(hash_key=True) + date_created = UTCDateTimeAttribute(default=datetime.utcnow) + + class ModelTestCase(TestCase): """ Tests for the models API @@ -235,6 +247,18 @@ def test_refresh(self): item.user_name, GET_MODEL_ITEM_DATA.get(ITEM).get('user_name').get(STRING_SHORT)) + def test_complex_key(self): + """ + Model with complex key + """ + with patch(PATCH_METHOD) as req: + req.return_value = HttpOK(), COMPLEX_TABLE_DATA + item = ComplexKeyModel('test') + + with patch(PATCH_METHOD) as req: + req.return_value = HttpOK(COMPLEX_ITEM_DATA), COMPLEX_ITEM_DATA + item.refresh() + def test_delete(self): """ Model.delete