From 74fe4428e51030cbed768083489f0497f4453c17 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Sat, 30 May 2015 21:22:36 +0100 Subject: [PATCH] Add HasAnyKeys lookup for HStoreField. --- django/contrib/postgres/fields/hstore.py | 15 +++------------ django/contrib/postgres/lookups.py | 15 +++++++++++++++ docs/ref/contrib/postgres/fields.txt | 17 +++++++++++++++++ tests/postgres_tests/test_hstore.py | 6 ++++++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/django/contrib/postgres/fields/hstore.py b/django/contrib/postgres/fields/hstore.py index b8e47edf17..c87eef3bef 100644 --- a/django/contrib/postgres/fields/hstore.py +++ b/django/contrib/postgres/fields/hstore.py @@ -55,18 +55,9 @@ class HStoreField(Field): HStoreField.register_lookup(lookups.DataContains) HStoreField.register_lookup(lookups.ContainedBy) - - -@HStoreField.register_lookup -class HasKeyLookup(lookups.PostgresSimpleLookup): - lookup_name = 'has_key' - operator = '?' - - -@HStoreField.register_lookup -class HasKeysLookup(lookups.PostgresSimpleLookup): - lookup_name = 'has_keys' - operator = '?&' +HStoreField.register_lookup(lookups.HasKey) +HStoreField.register_lookup(lookups.HasKeys) +HStoreField.register_lookup(lookups.HasAnyKeys) class KeyTransform(Transform): diff --git a/django/contrib/postgres/lookups.py b/django/contrib/postgres/lookups.py index eb7cfd8359..887337861a 100644 --- a/django/contrib/postgres/lookups.py +++ b/django/contrib/postgres/lookups.py @@ -30,6 +30,21 @@ class Overlap(PostgresSimpleLookup): operator = '&&' +class HasKey(PostgresSimpleLookup): + lookup_name = 'has_key' + operator = '?' + + +class HasKeys(PostgresSimpleLookup): + lookup_name = 'has_keys' + operator = '?&' + + +class HasAnyKeys(PostgresSimpleLookup): + lookup_name = 'has_any_keys' + operator = '?|' + + class Unaccent(FunctionTransform): bilateral = True lookup_name = 'unaccent' diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt index 235dbc9079..5313ac4092 100644 --- a/docs/ref/contrib/postgres/fields.txt +++ b/docs/ref/contrib/postgres/fields.txt @@ -385,6 +385,23 @@ Returns objects where the given key is in the data. Uses the SQL operator >>> Dog.objects.filter(data__has_key='owner') [] +.. fieldlookup:: hstorefield.has_any_keys + +has_any_keys +~~~~~~~~~~~~ + +.. versionadded:: 1.9 + +Returns objects where any of the given keys are in the data. Uses the SQL +operator ``?|``. For example:: + + >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'}) + >>> Dog.objects.create(name='Meg', data={'owner': 'Bob'}) + >>> Dog.objects.create(name='Fred', data={}) + + >>> Dog.objects.filter(data__has_any_keys=['owner', 'breed']) + [, ] + .. fieldlookup:: hstorefield.has_keys has_keys diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py index 470ede9d22..50a4702716 100644 --- a/tests/postgres_tests/test_hstore.py +++ b/tests/postgres_tests/test_hstore.py @@ -79,6 +79,12 @@ class TestQuerying(PostgresSQLTestCase): self.objs[1:2] ) + def test_has_any_keys(self): + self.assertSequenceEqual( + HStoreModel.objects.filter(field__has_any_keys=['a', 'c']), + self.objs[:3] + ) + def test_key_transform(self): self.assertSequenceEqual( HStoreModel.objects.filter(field__a='b'),