summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Chapple <gregchapple1@gmail.com>2016-01-25 12:30:40 +0000
committerTim Graham <timograham@gmail.com>2016-01-29 09:51:23 -0500
commit8dea9f089dcb8aea2c417c91344c4e680431e972 (patch)
treef147304a6fd6bd762edb4d7646c53790c5214387
parent93897a6a75754c1c17d8a60dee188c86f13de232 (diff)
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.
-rw-r--r--django/contrib/postgres/fields/hstore.py17
-rw-r--r--docs/releases/1.10.txt3
-rw-r--r--tests/postgres_tests/test_hstore.py17
3 files changed, 36 insertions, 1 deletions
diff --git a/django/contrib/postgres/fields/hstore.py b/django/contrib/postgres/fields/hstore.py
index 1fb9138e9a..8322d8170c 100644
--- a/django/contrib/postgres/fields/hstore.py
+++ b/django/contrib/postgres/fields/hstore.py
@@ -5,6 +5,7 @@ from django.contrib.postgres.fields.array import ArrayField
from django.core import exceptions
from django.db.models import Field, TextField, Transform
from django.utils import six
+from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
__all__ = ['HStoreField']
@@ -51,6 +52,22 @@ class HStoreField(Field):
defaults.update(kwargs)
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.ContainedBy)
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index 1f9cc69453..6568d0ff45 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -129,7 +129,8 @@ Minor features
:mod:`django.contrib.postgres`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* ...
+* For convenience, :class:`~django.contrib.postgres.fields.HStoreField` now
+ casts its keys and values to strings.
:mod:`django.contrib.redirects`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py
index 80e46e5021..13c08386e2 100644
--- a/tests/postgres_tests/test_hstore.py
+++ b/tests/postgres_tests/test_hstore.py
@@ -1,3 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
import json
from django.core import exceptions, serializers
@@ -37,6 +40,20 @@ class SimpleTests(PostgreSQLTestCase):
reloaded = HStoreModel.objects.get()
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):