From 92a17eaae081a213171b044858d6fc29df2df733 Mon Sep 17 00:00:00 2001 From: Marc Tamlyn Date: Thu, 9 Oct 2014 17:04:50 +0100 Subject: [PATCH] Fixed #23627 -- Allowed register_lookup to work as a decorator. --- django/contrib/postgres/fields/array.py | 16 ++++------------ django/db/models/lookups.py | 1 + docs/howto/custom-lookups.txt | 12 ++++++++++++ docs/releases/1.8.txt | 3 +++ tests/custom_lookups/tests.py | 4 ++-- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py index dea9c0440d..1a969d7c0e 100644 --- a/django/contrib/postgres/fields/array.py +++ b/django/contrib/postgres/fields/array.py @@ -160,6 +160,7 @@ class ArrayField(Field): return super(ArrayField, self).formfield(**defaults) +@ArrayField.register_lookup class ArrayContainsLookup(Lookup): lookup_name = 'contains' @@ -171,9 +172,7 @@ class ArrayContainsLookup(Lookup): return '%s @> %s::%s' % (lhs, rhs, type_cast), params -ArrayField.register_lookup(ArrayContainsLookup) - - +@ArrayField.register_lookup class ArrayContainedByLookup(Lookup): lookup_name = 'contained_by' @@ -184,9 +183,7 @@ class ArrayContainedByLookup(Lookup): return '%s <@ %s' % (lhs, rhs), params -ArrayField.register_lookup(ArrayContainedByLookup) - - +@ArrayField.register_lookup class ArrayOverlapLookup(Lookup): lookup_name = 'overlap' @@ -197,9 +194,7 @@ class ArrayOverlapLookup(Lookup): return '%s && %s' % (lhs, rhs), params -ArrayField.register_lookup(ArrayOverlapLookup) - - +@ArrayField.register_lookup class ArrayLenTransform(Transform): lookup_name = 'len' @@ -212,9 +207,6 @@ class ArrayLenTransform(Transform): return 'array_length(%s, 1)' % lhs, params -ArrayField.register_lookup(ArrayLenTransform) - - class IndexTransform(Transform): def __init__(self, index, base_field, *args, **kwargs): diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index 8242602e82..66bdde54b4 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -45,6 +45,7 @@ class RegisterLookupMixin(object): if 'class_lookups' not in cls.__dict__: cls.class_lookups = {} cls.class_lookups[lookup.lookup_name] = lookup + return lookup @classmethod def _unregister_lookup(cls, lookup): diff --git a/docs/howto/custom-lookups.txt b/docs/howto/custom-lookups.txt index c02b896071..820a2ef574 100644 --- a/docs/howto/custom-lookups.txt +++ b/docs/howto/custom-lookups.txt @@ -46,6 +46,18 @@ it with ``Field`` directly:: from django.db.models.fields import Field Field.register_lookup(NotEqual) +Lookup registration can also be done using a decorator pattern:: + + from django.db.models.fields import Field + + @Field.registerLookup + class NotEqualLookup(Lookup): + # ... + +.. versionchanged:: 1.8 + + The ability to use the decorator pattern was added. + We can now use ``foo__ne`` for any field ``foo``. You will need to ensure that this registration happens before you try to create any querysets using it. You could place the implementation in a ``models.py`` file, or register the lookup diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index 0e42f1f12f..631b0bd2f0 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -299,6 +299,9 @@ Models * ``extra(select={...})`` now allows you to escape a literal ``%s`` sequence using ``%%s``. +* :doc:`Custom Lookups` can now be registered using + a decorator pattern. + Signals ^^^^^^^ diff --git a/tests/custom_lookups/tests.py b/tests/custom_lookups/tests.py index c89b268f6e..a965e5a4e8 100644 --- a/tests/custom_lookups/tests.py +++ b/tests/custom_lookups/tests.py @@ -50,6 +50,7 @@ class YearTransform(models.Transform): return models.IntegerField() +@YearTransform.register_lookup class YearExact(models.lookups.Lookup): lookup_name = 'exact' @@ -66,9 +67,9 @@ class YearExact(models.lookups.Lookup): return ("%(lhs)s >= (%(rhs)s || '-01-01')::date " "AND %(lhs)s <= (%(rhs)s || '-12-31')::date" % {'lhs': lhs_sql, 'rhs': rhs_sql}, params) -YearTransform.register_lookup(YearExact) +@YearTransform.register_lookup class YearLte(models.lookups.LessThanOrEqual): """ The purpose of this lookup is to efficiently compare the year of the field. @@ -86,7 +87,6 @@ class YearLte(models.lookups.LessThanOrEqual): # WHERE somecol <= '2013-12-31') # but also make it work if the rhs_sql is field reference. return "%s <= (%s || '-12-31')::date" % (lhs_sql, rhs_sql), params -YearTransform.register_lookup(YearLte) class SQLFunc(models.Lookup):