diff options
| author | Simon Charette <charette.s@gmail.com> | 2012-05-07 20:08:20 +0300 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2012-05-07 20:08:20 +0300 |
| commit | 5cbfb48b92cb26a335f9c8c0f79d3390290103e2 (patch) | |
| tree | 197836116e12332cc43b62dce75af54878cb70cb /django | |
| parent | 1aae1cba99b0f8232527742d64b120e4d902c68d (diff) | |
Made model fields comparable to other objects
Fixed #17851 -- Added __lt__ and @total_ordering to models.Field,
made sure these work correctly on other objects than Field, too.
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/models/fields/__init__.py | 15 | ||||
| -rw-r--r-- | django/utils/functional.py | 32 |
2 files changed, 44 insertions, 3 deletions
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 79fb373ce1..f694958692 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -12,7 +12,7 @@ from django import forms from django.core import exceptions, validators from django.utils.datastructures import DictWrapper from django.utils.dateparse import parse_date, parse_datetime, parse_time -from django.utils.functional import curry +from django.utils.functional import curry, total_ordering from django.utils.text import capfirst from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -45,6 +45,7 @@ class FieldDoesNotExist(Exception): # # getattr(obj, opts.pk.attname) +@total_ordering class Field(object): """Base class for all field types""" @@ -118,9 +119,17 @@ class Field(object): messages.update(error_messages or {}) self.error_messages = messages - def __cmp__(self, other): + def __eq__(self, other): + # Needed for @total_ordering + if isinstance(other, Field): + return self.creation_counter == other.creation_counter + return NotImplemented + + def __lt__(self, other): # This is needed because bisect does not take a comparison function. - return cmp(self.creation_counter, other.creation_counter) + if isinstance(other, Field): + return self.creation_counter < other.creation_counter + return NotImplemented def __deepcopy__(self, memodict): # We don't have to deepcopy very much here, since most things are not diff --git a/django/utils/functional.py b/django/utils/functional.py index befe3e9dad..86bbed7a7b 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -310,3 +310,35 @@ def partition(predicate, values): for item in values: results[predicate(item)].append(item) return results + +try: + from functools import total_ordering +except ImportError: + # For Python < 2.7 + # Code borrowed from python 2.7.3 stdlib + def total_ordering(cls): + """Class decorator that fills in missing ordering methods""" + convert = { + '__lt__': [('__gt__', lambda self, other: not (self < other or self == other)), + ('__le__', lambda self, other: self < other or self == other), + ('__ge__', lambda self, other: not self < other)], + '__le__': [('__ge__', lambda self, other: not self <= other or self == other), + ('__lt__', lambda self, other: self <= other and not self == other), + ('__gt__', lambda self, other: not self <= other)], + '__gt__': [('__lt__', lambda self, other: not (self > other or self == other)), + ('__ge__', lambda self, other: self > other or self == other), + ('__le__', lambda self, other: not self > other)], + '__ge__': [('__le__', lambda self, other: (not self >= other) or self == other), + ('__gt__', lambda self, other: self >= other and not self == other), + ('__lt__', lambda self, other: not self >= other)] + } + roots = set(dir(cls)) & set(convert) + if not roots: + raise ValueError('must define at least one ordering operation: < > <= >=') + root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__ + for opname, opfunc in convert[root]: + if opname not in roots: + opfunc.__name__ = opname + opfunc.__doc__ = getattr(int, opname).__doc__ + setattr(cls, opname, opfunc) + return cls |
