diff -r b758351d191f -r cc9b7e14412b web/lib/django/db/models/fields/subclassing.py --- a/web/lib/django/db/models/fields/subclassing.py Wed May 19 17:43:59 2010 +0200 +++ b/web/lib/django/db/models/fields/subclassing.py Tue May 25 02:43:45 2010 +0200 @@ -1,11 +1,77 @@ """ -Convenience routines for creating non-trivial Field subclasses. +Convenience routines for creating non-trivial Field subclasses, as well as +backwards compatibility utilities. Add SubfieldBase as the __metaclass__ for your Field subclass, implement to_python() and the other necessary methods and everything will work seamlessly. """ -class SubfieldBase(type): +from inspect import getargspec +from warnings import warn + +def call_with_connection(func): + arg_names, varargs, varkwargs, defaults = getargspec(func) + updated = ('connection' in arg_names or varkwargs) + if not updated: + warn("A Field class whose %s method hasn't been updated to take a " + "`connection` argument." % func.__name__, + PendingDeprecationWarning, stacklevel=2) + + def inner(*args, **kwargs): + if 'connection' not in kwargs: + from django.db import connection + kwargs['connection'] = connection + warn("%s has been called without providing a connection argument. " % + func.__name__, PendingDeprecationWarning, + stacklevel=1) + if updated: + return func(*args, **kwargs) + if 'connection' in kwargs: + del kwargs['connection'] + return func(*args, **kwargs) + return inner + +def call_with_connection_and_prepared(func): + arg_names, varargs, varkwargs, defaults = getargspec(func) + updated = ( + ('connection' in arg_names or varkwargs) and + ('prepared' in arg_names or varkwargs) + ) + if not updated: + warn("A Field class whose %s method hasn't been updated to take " + "`connection` and `prepared` arguments." % func.__name__, + PendingDeprecationWarning, stacklevel=2) + + def inner(*args, **kwargs): + if 'connection' not in kwargs: + from django.db import connection + kwargs['connection'] = connection + warn("%s has been called without providing a connection argument. " % + func.__name__, PendingDeprecationWarning, + stacklevel=1) + if updated: + return func(*args, **kwargs) + if 'connection' in kwargs: + del kwargs['connection'] + if 'prepared' in kwargs: + del kwargs['prepared'] + return func(*args, **kwargs) + return inner + +class LegacyConnection(type): + """ + A metaclass to normalize arguments give to the get_db_prep_* and db_type + methods on fields. + """ + def __new__(cls, names, bases, attrs): + new_cls = super(LegacyConnection, cls).__new__(cls, names, bases, attrs) + for attr in ('db_type', 'get_db_prep_save'): + setattr(new_cls, attr, call_with_connection(getattr(new_cls, attr))) + for attr in ('get_db_prep_lookup', 'get_db_prep_value'): + setattr(new_cls, attr, call_with_connection_and_prepared(getattr(new_cls, attr))) + return new_cls + +class SubfieldBase(LegacyConnection): """ A metaclass for custom Field subclasses. This ensures the model's attribute has the descriptor protocol attached to it. @@ -26,7 +92,7 @@ def __get__(self, obj, type=None): if obj is None: raise AttributeError('Can only be accessed via an instance.') - return obj.__dict__[self.field.name] + return obj.__dict__[self.field.name] def __set__(self, obj, value): obj.__dict__[self.field.name] = self.field.to_python(value)