Fixed #26120 -- Made HStoreField cast keys and values to strings.

HStoreField now converts all keys and values to string before they're
saved to the database.
This commit is contained in:
Greg Chapple 2016-01-25 12:30:40 +00:00 committed by Tim Graham
parent 93897a6a75
commit 8dea9f089d
3 changed files with 36 additions and 1 deletions

View File

@ -5,6 +5,7 @@ from django.contrib.postgres.fields.array import ArrayField
from django.core import exceptions from django.core import exceptions
from django.db.models import Field, TextField, Transform from django.db.models import Field, TextField, Transform
from django.utils import six from django.utils import six
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
__all__ = ['HStoreField'] __all__ = ['HStoreField']
@ -51,6 +52,22 @@ class HStoreField(Field):
defaults.update(kwargs) defaults.update(kwargs)
return super(HStoreField, self).formfield(**defaults) return super(HStoreField, self).formfield(**defaults)
def get_prep_value(self, value):
value = super(HStoreField, self).get_prep_value(value)
if isinstance(value, dict):
prep_value = {}
for key, val in value.items():
key = force_text(key)
if val is not None:
val = force_text(val)
prep_value[key] = val
value = prep_value
if isinstance(value, list):
value = [force_text(item) for item in value]
return value
HStoreField.register_lookup(lookups.DataContains) HStoreField.register_lookup(lookups.DataContains)
HStoreField.register_lookup(lookups.ContainedBy) HStoreField.register_lookup(lookups.ContainedBy)

View File

@ -129,7 +129,8 @@ Minor features
:mod:`django.contrib.postgres` :mod:`django.contrib.postgres`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * For convenience, :class:`~django.contrib.postgres.fields.HStoreField` now
casts its keys and values to strings.
:mod:`django.contrib.redirects` :mod:`django.contrib.redirects`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,3 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json import json
from django.core import exceptions, serializers from django.core import exceptions, serializers
@ -37,6 +40,20 @@ class SimpleTests(PostgreSQLTestCase):
reloaded = HStoreModel.objects.get() reloaded = HStoreModel.objects.get()
self.assertEqual(reloaded.field, value) self.assertEqual(reloaded.field, value)
def test_key_val_cast_to_string(self):
value = {'a': 1, 'b': 'B', 2: 'c', 'ï': 'ê', b'x': b'test'}
expected_value = {'a': '1', 'b': 'B', '2': 'c', 'ï': 'ê', 'x': 'test'}
instance = HStoreModel.objects.create(field=value)
instance = HStoreModel.objects.get()
self.assertDictEqual(instance.field, expected_value)
instance = HStoreModel.objects.get(field__a=1)
self.assertDictEqual(instance.field, expected_value)
instance = HStoreModel.objects.get(field__has_keys=[2, 'a', 'ï'])
self.assertDictEqual(instance.field, expected_value)
class TestQuerying(PostgreSQLTestCase): class TestQuerying(PostgreSQLTestCase):