mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
[soc2009/multidb] Cleaned up the double processing required by validate() by splitting get_db_prep_* functions into db-specific and non-db-specific parts. Patch from Russell Keith-Magee.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11786 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
5a5e082161
commit
0ca0ed0453
4
TODO
4
TODO
@ -7,10 +7,6 @@ Required for v1.2
|
|||||||
* Finalize the sql.Query internals
|
* Finalize the sql.Query internals
|
||||||
* Clean up the use of db.backend.query_class()
|
* Clean up the use of db.backend.query_class()
|
||||||
* Verify it still works with GeoDjango
|
* Verify it still works with GeoDjango
|
||||||
* Cleanup of new API entry points
|
|
||||||
* validate() on a field
|
|
||||||
* name/purpose clash with Honza?
|
|
||||||
* any overlap with existing methods?
|
|
||||||
|
|
||||||
Optional for v1.2
|
Optional for v1.2
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
@ -180,21 +180,56 @@ class Field(object):
|
|||||||
"Returns field's value just before saving."
|
"Returns field's value just before saving."
|
||||||
return getattr(model_instance, self.attname)
|
return getattr(model_instance, self.attname)
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
|
"Perform preliminary non-db specific value checks and conversions."
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
"""Returns field's value prepared for interacting with the database
|
"""Returns field's value prepared for interacting with the database
|
||||||
backend.
|
backend.
|
||||||
|
|
||||||
Used by the default implementations of ``get_db_prep_save``and
|
Used by the default implementations of ``get_db_prep_save``and
|
||||||
`get_db_prep_lookup```
|
`get_db_prep_lookup```
|
||||||
"""
|
"""
|
||||||
|
if not prepared:
|
||||||
|
value = self.get_prep_value(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_db_prep_save(self, value, connection):
|
def get_db_prep_save(self, value, connection):
|
||||||
"Returns field's value prepared for saving into a database."
|
"Returns field's value prepared for saving into a database."
|
||||||
return self.get_db_prep_value(value, connection=connection)
|
return self.get_db_prep_value(value, connection=connection, prepared=False)
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
|
"Perform preliminary non-db specific lookup checks and conversions"
|
||||||
|
if hasattr(value, 'prepare'):
|
||||||
|
return value.prepare()
|
||||||
|
if hasattr(value, '_prepare'):
|
||||||
|
return value._prepare()
|
||||||
|
|
||||||
|
if lookup_type in (
|
||||||
|
'regex', 'iregex', 'month', 'day', 'week_day', 'search',
|
||||||
|
'contains', 'icontains', 'iexact', 'startswith', 'istartswith',
|
||||||
|
'endswith', 'iendswith', 'isnull'
|
||||||
|
):
|
||||||
|
return value
|
||||||
|
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
|
||||||
|
return self.get_prep_value(value)
|
||||||
|
elif lookup_type in ('range', 'in'):
|
||||||
|
return [self.get_prep_value(v) for v in value]
|
||||||
|
elif lookup_type == 'year':
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("The __year lookup type requires an integer argument")
|
||||||
|
|
||||||
|
raise TypeError("Field has invalid lookup: %s" % lookup_type)
|
||||||
|
|
||||||
|
def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
|
||||||
"Returns field's value prepared for database lookup."
|
"Returns field's value prepared for database lookup."
|
||||||
|
if not prepared:
|
||||||
|
value = self.get_prep_lookup(lookup_type, value)
|
||||||
|
if hasattr(value, 'get_compiler'):
|
||||||
|
value = value.get_compiler(connection=connection)
|
||||||
if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
|
if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
|
||||||
# If the value has a relabel_aliases method, it will need to
|
# If the value has a relabel_aliases method, it will need to
|
||||||
# be invoked before the final SQL is evaluated
|
# be invoked before the final SQL is evaluated
|
||||||
@ -206,13 +241,12 @@ class Field(object):
|
|||||||
sql, params = value._as_sql(connection=connection)
|
sql, params = value._as_sql(connection=connection)
|
||||||
return QueryWrapper(('(%s)' % sql), params)
|
return QueryWrapper(('(%s)' % sql), params)
|
||||||
|
|
||||||
|
|
||||||
if lookup_type in ('regex', 'iregex', 'month', 'day', 'week_day', 'search'):
|
if lookup_type in ('regex', 'iregex', 'month', 'day', 'week_day', 'search'):
|
||||||
return [value]
|
return [value]
|
||||||
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
|
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
|
||||||
return [self.get_db_prep_value(value, connection=connection)]
|
return [self.get_db_prep_value(value, connection=connection, prepared=prepared)]
|
||||||
elif lookup_type in ('range', 'in'):
|
elif lookup_type in ('range', 'in'):
|
||||||
return [self.get_db_prep_value(v, connection=connection) for v in value]
|
return [self.get_db_prep_value(v, connection=connection, prepared=prepared) for v in value]
|
||||||
elif lookup_type in ('contains', 'icontains'):
|
elif lookup_type in ('contains', 'icontains'):
|
||||||
return ["%%%s%%" % connection.ops.prep_for_like_query(value)]
|
return ["%%%s%%" % connection.ops.prep_for_like_query(value)]
|
||||||
elif lookup_type == 'iexact':
|
elif lookup_type == 'iexact':
|
||||||
@ -224,36 +258,11 @@ class Field(object):
|
|||||||
elif lookup_type == 'isnull':
|
elif lookup_type == 'isnull':
|
||||||
return []
|
return []
|
||||||
elif lookup_type == 'year':
|
elif lookup_type == 'year':
|
||||||
try:
|
|
||||||
value = int(value)
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError("The __year lookup type requires an integer argument")
|
|
||||||
|
|
||||||
if self.get_internal_type() == 'DateField':
|
if self.get_internal_type() == 'DateField':
|
||||||
return connection.ops.year_lookup_bounds_for_date_field(value)
|
return connection.ops.year_lookup_bounds_for_date_field(value)
|
||||||
else:
|
else:
|
||||||
return connection.ops.year_lookup_bounds(value)
|
return connection.ops.year_lookup_bounds(value)
|
||||||
|
|
||||||
raise TypeError("Field has invalid lookup: %s" % lookup_type)
|
|
||||||
|
|
||||||
def validate(self, lookup_type, value):
|
|
||||||
"""
|
|
||||||
Validate that the data is valid, as much so as possible without knowing
|
|
||||||
what connection we are using. Returns True if the value was
|
|
||||||
successfully validated and false if the value wasn't validated (this
|
|
||||||
doesn't consider whether the value was actually valid, an exception is
|
|
||||||
raised in those circumstances).
|
|
||||||
"""
|
|
||||||
if hasattr(value, 'validate') or hasattr(value, '_validate'):
|
|
||||||
if hasattr(value, 'validate'):
|
|
||||||
value.validate()
|
|
||||||
else:
|
|
||||||
value._validate()
|
|
||||||
return True
|
|
||||||
if lookup_type == 'isnull':
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def has_default(self):
|
def has_default(self):
|
||||||
"Returns a boolean of whether this field has a default value."
|
"Returns a boolean of whether this field has a default value."
|
||||||
return self.default is not NOT_PROVIDED
|
return self.default is not NOT_PROVIDED
|
||||||
@ -376,22 +385,11 @@ class AutoField(Field):
|
|||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
_("This value must be an integer."))
|
_("This value must be an integer."))
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return int(value)
|
return int(value)
|
||||||
|
|
||||||
def validate(self, lookup_type, value):
|
|
||||||
if super(AutoField, self).validate(lookup_type, value):
|
|
||||||
return
|
|
||||||
if value is None or hasattr(value, 'as_sql'):
|
|
||||||
return
|
|
||||||
if lookup_type in ('range', 'in'):
|
|
||||||
for val in value:
|
|
||||||
int(val)
|
|
||||||
else:
|
|
||||||
int(value)
|
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
def contribute_to_class(self, cls, name):
|
||||||
assert not cls._meta.has_auto_field, "A model can't have more than one AutoField."
|
assert not cls._meta.has_auto_field, "A model can't have more than one AutoField."
|
||||||
super(AutoField, self).contribute_to_class(cls, name)
|
super(AutoField, self).contribute_to_class(cls, name)
|
||||||
@ -419,24 +417,16 @@ class BooleanField(Field):
|
|||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
_("This value must be either True or False."))
|
_("This value must be either True or False."))
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
# Special-case handling for filters coming from a web request (e.g. the
|
# Special-case handling for filters coming from a web request (e.g. the
|
||||||
# admin interface). Only works for scalar values (not lists). If you're
|
# admin interface). Only works for scalar values (not lists). If you're
|
||||||
# passing in a list, you might as well make things the right type when
|
# passing in a list, you might as well make things the right type when
|
||||||
# constructing the list.
|
# constructing the list.
|
||||||
if value in ('1', '0'):
|
if value in ('1', '0'):
|
||||||
value = bool(int(value))
|
value = bool(int(value))
|
||||||
return super(BooleanField, self).get_db_prep_lookup(lookup_type, value,
|
return super(BooleanField, self).get_prep_lookup(lookup_type, value)
|
||||||
connection=connection)
|
|
||||||
|
|
||||||
def validate(self, lookup_type, value):
|
def get_prep_value(self, value):
|
||||||
if super(BooleanField, self).validate(lookup_type, value):
|
|
||||||
return
|
|
||||||
if value in ('1', '0'):
|
|
||||||
value = int(value)
|
|
||||||
bool(value)
|
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return bool(value)
|
return bool(value)
|
||||||
@ -539,31 +529,21 @@ class DateField(Field):
|
|||||||
setattr(cls, 'get_previous_by_%s' % self.name,
|
setattr(cls, 'get_previous_by_%s' % self.name,
|
||||||
curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
|
curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
# For "__month", "__day", and "__week_day" lookups, convert the value
|
# For "__month", "__day", and "__week_day" lookups, convert the value
|
||||||
# to an int so the database backend always sees a consistent type.
|
# to an int so the database backend always sees a consistent type.
|
||||||
if lookup_type in ('month', 'day', 'week_day'):
|
if lookup_type in ('month', 'day', 'week_day'):
|
||||||
return [int(value)]
|
return int(value)
|
||||||
return super(DateField, self).get_db_prep_lookup(lookup_type, value,
|
return super(DateField, self).get_prep_lookup(lookup_type, value)
|
||||||
connection=connection)
|
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
|
return self.to_python(value)
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
# Casts dates into the format expected by the backend
|
# Casts dates into the format expected by the backend
|
||||||
return connection.ops.value_to_db_date(self.to_python(value))
|
if not prepared:
|
||||||
|
value = self.get_prep_value(value)
|
||||||
def validate(self, lookup_type, value):
|
return connection.ops.value_to_db_date(value)
|
||||||
if super(DateField, self).validate(lookup_type, value):
|
|
||||||
return
|
|
||||||
if value is None:
|
|
||||||
return
|
|
||||||
if lookup_type in ('month', 'day', 'year', 'week_day'):
|
|
||||||
int(value)
|
|
||||||
return
|
|
||||||
if lookup_type in ('in', 'range'):
|
|
||||||
for val in value:
|
|
||||||
self.to_python(val)
|
|
||||||
return
|
|
||||||
self.to_python(value)
|
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
def value_to_string(self, obj):
|
||||||
val = self._get_val_from_obj(obj)
|
val = self._get_val_from_obj(obj)
|
||||||
@ -619,9 +599,14 @@ class DateTimeField(DateField):
|
|||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
_('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.'))
|
_('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.'))
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
|
return self.to_python(value)
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
# Casts dates into the format expected by the backend
|
# Casts dates into the format expected by the backend
|
||||||
return connection.ops.value_to_db_datetime(self.to_python(value))
|
if not prepared:
|
||||||
|
value = self.get_prep_value(value)
|
||||||
|
return connection.ops.value_to_db_datetime(value)
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
def value_to_string(self, obj):
|
||||||
val = self._get_val_from_obj(obj)
|
val = self._get_val_from_obj(obj)
|
||||||
@ -679,7 +664,7 @@ class DecimalField(Field):
|
|||||||
return connection.ops.value_to_db_decimal(self.to_python(value),
|
return connection.ops.value_to_db_decimal(self.to_python(value),
|
||||||
self.max_digits, self.decimal_places)
|
self.max_digits, self.decimal_places)
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
return self.to_python(value)
|
return self.to_python(value)
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
@ -723,7 +708,7 @@ class FilePathField(Field):
|
|||||||
class FloatField(Field):
|
class FloatField(Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return float(value)
|
return float(value)
|
||||||
@ -747,7 +732,7 @@ class FloatField(Field):
|
|||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return int(value)
|
return int(value)
|
||||||
@ -800,22 +785,16 @@ class NullBooleanField(Field):
|
|||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
_("This value must be either None, True or False."))
|
_("This value must be either None, True or False."))
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
# Special-case handling for filters coming from a web request (e.g. the
|
# Special-case handling for filters coming from a web request (e.g. the
|
||||||
# admin interface). Only works for scalar values (not lists). If you're
|
# admin interface). Only works for scalar values (not lists). If you're
|
||||||
# passing in a list, you might as well make things the right type when
|
# passing in a list, you might as well make things the right type when
|
||||||
# constructing the list.
|
# constructing the list.
|
||||||
if value in ('1', '0'):
|
if value in ('1', '0'):
|
||||||
value = bool(int(value))
|
value = bool(int(value))
|
||||||
return super(NullBooleanField, self).get_db_prep_lookup(lookup_type,
|
return super(NullBooleanField, self).get_prep_lookup(lookup_type, value)
|
||||||
value, connection=connection)
|
|
||||||
|
|
||||||
def validate(self, lookup_type, value):
|
def get_prep_value(self, value):
|
||||||
if value in ('1', '0'):
|
|
||||||
value = int(value)
|
|
||||||
bool(value)
|
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
return bool(value)
|
return bool(value)
|
||||||
@ -931,9 +910,14 @@ class TimeField(Field):
|
|||||||
else:
|
else:
|
||||||
return super(TimeField, self).pre_save(model_instance, add)
|
return super(TimeField, self).pre_save(model_instance, add)
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
|
return self.to_python(value)
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
# Casts times into the format expected by the backend
|
# Casts times into the format expected by the backend
|
||||||
return connection.ops.value_to_db_time(self.to_python(value))
|
if not prepared:
|
||||||
|
value = self.get_prep_value(value)
|
||||||
|
return connection.ops.value_to_db_time(value)
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
def value_to_string(self, obj):
|
||||||
val = self._get_val_from_obj(obj)
|
val = self._get_val_from_obj(obj)
|
||||||
|
@ -232,13 +232,12 @@ class FileField(Field):
|
|||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "FileField"
|
return "FileField"
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
if hasattr(value, 'name'):
|
if hasattr(value, 'name'):
|
||||||
value = value.name
|
value = value.name
|
||||||
return super(FileField, self).get_db_prep_lookup(lookup_type, value,
|
return super(FileField, self).get_prep_lookup(lookup_type, value)
|
||||||
connection=connection)
|
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
"Returns field's value prepared for saving into a database."
|
"Returns field's value prepared for saving into a database."
|
||||||
# Need to convert File objects provided via a form to unicode for database insertion
|
# Need to convert File objects provided via a form to unicode for database insertion
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -120,7 +120,7 @@ class RelatedField(object):
|
|||||||
if not cls._meta.abstract:
|
if not cls._meta.abstract:
|
||||||
self.contribute_to_related_class(other, self.related)
|
self.contribute_to_related_class(other, self.related)
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
|
||||||
# If we are doing a lookup on a Related Field, we must be
|
# If we are doing a lookup on a Related Field, we must be
|
||||||
# comparing object instances. The value should be the PK of value,
|
# comparing object instances. The value should be the PK of value,
|
||||||
# not value itself.
|
# not value itself.
|
||||||
@ -140,14 +140,16 @@ class RelatedField(object):
|
|||||||
if field:
|
if field:
|
||||||
if lookup_type in ('range', 'in'):
|
if lookup_type in ('range', 'in'):
|
||||||
v = [v]
|
v = [v]
|
||||||
v = field.get_db_prep_lookup(lookup_type, v, connection=connection)
|
v = field.get_db_prep_lookup(lookup_type, v,
|
||||||
|
connection=connection, prepared=prepared)
|
||||||
if isinstance(v, list):
|
if isinstance(v, list):
|
||||||
v = v[0]
|
v = v[0]
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
if not prepared:
|
||||||
|
value = self.get_prep_lookup(lookup_type, value)
|
||||||
if hasattr(value, 'get_compiler'):
|
if hasattr(value, 'get_compiler'):
|
||||||
value = value.get_compiler(connection=connection)
|
value = value.get_compiler(connection=connection)
|
||||||
|
|
||||||
if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
|
if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
|
||||||
# If the value has a relabel_aliases method, it will need to
|
# If the value has a relabel_aliases method, it will need to
|
||||||
# be invoked before the final SQL is evaluated
|
# be invoked before the final SQL is evaluated
|
||||||
|
@ -11,25 +11,53 @@ from warnings import warn
|
|||||||
|
|
||||||
def call_with_connection(func):
|
def call_with_connection(func):
|
||||||
arg_names, varargs, varkwargs, defaults = getargspec(func)
|
arg_names, varargs, varkwargs, defaults = getargspec(func)
|
||||||
takes_connection = 'connection' in arg_names or varkwargs
|
updated = ('connection' in arg_names or varkwargs)
|
||||||
if not takes_connection:
|
if not updated:
|
||||||
warn("A Field class whose %s method doesn't take connection has been "
|
warn("A Field class whose %s method hasn't been updated to take a "
|
||||||
"defined. Please add a connection argument" % func.__name__,
|
"`connection` argument." % func.__name__,
|
||||||
PendingDeprecationWarning, stacklevel=2)
|
PendingDeprecationWarning, stacklevel=2)
|
||||||
|
|
||||||
def inner(*args, **kwargs):
|
def inner(*args, **kwargs):
|
||||||
if 'connection' not in kwargs:
|
if 'connection' not in kwargs:
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
kwargs['connection'] = connection
|
kwargs['connection'] = connection
|
||||||
warn("%s has been called without providing a connection argument. "
|
warn("%s has been called without providing a connection argument. " %
|
||||||
"Please provide one" % func.__name__, PendingDeprecationWarning,
|
func.__name__, PendingDeprecationWarning,
|
||||||
stacklevel=1)
|
stacklevel=1)
|
||||||
if takes_connection:
|
if updated:
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
if 'connection' in kwargs:
|
if 'connection' in kwargs:
|
||||||
del kwargs['connection']
|
del kwargs['connection']
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
return inner
|
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):
|
class LegacyConnection(type):
|
||||||
"""
|
"""
|
||||||
A metaclass to normalize arguments give to the get_db_prep_* and db_type
|
A metaclass to normalize arguments give to the get_db_prep_* and db_type
|
||||||
@ -37,9 +65,10 @@ class LegacyConnection(type):
|
|||||||
"""
|
"""
|
||||||
def __new__(cls, names, bases, attrs):
|
def __new__(cls, names, bases, attrs):
|
||||||
new_cls = super(LegacyConnection, cls).__new__(cls, names, bases, attrs)
|
new_cls = super(LegacyConnection, cls).__new__(cls, names, bases, attrs)
|
||||||
for attr in ('db_type', 'get_db_prep_save', 'get_db_prep_lookup',
|
for attr in ('db_type', 'get_db_prep_save'):
|
||||||
'get_db_prep_value'):
|
|
||||||
setattr(new_cls, attr, call_with_connection(getattr(new_cls, attr)))
|
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
|
return new_cls
|
||||||
|
|
||||||
class SubfieldBase(LegacyConnection):
|
class SubfieldBase(LegacyConnection):
|
||||||
|
@ -739,6 +739,9 @@ class QuerySet(object):
|
|||||||
self.query.add_fields(field_names, False)
|
self.query.add_fields(field_names, False)
|
||||||
self.query.set_group_by()
|
self.query.set_group_by()
|
||||||
|
|
||||||
|
def _prepare(self):
|
||||||
|
return self
|
||||||
|
|
||||||
def _as_sql(self, connection):
|
def _as_sql(self, connection):
|
||||||
"""
|
"""
|
||||||
Returns the internal query's SQL and parameters (as a tuple).
|
Returns the internal query's SQL and parameters (as a tuple).
|
||||||
@ -748,13 +751,6 @@ class QuerySet(object):
|
|||||||
return obj.query.get_compiler(connection=connection).as_nested_sql()
|
return obj.query.get_compiler(connection=connection).as_nested_sql()
|
||||||
raise ValueError("Can't do subqueries with queries on different DBs.")
|
raise ValueError("Can't do subqueries with queries on different DBs.")
|
||||||
|
|
||||||
def _validate(self):
|
|
||||||
"""
|
|
||||||
A normal QuerySet is always valid when used as the RHS of a filter,
|
|
||||||
since it automatically gets filtered down to 1 field.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
# When used as part of a nested query, a queryset will never be an "always
|
# When used as part of a nested query, a queryset will never be an "always
|
||||||
# empty" result.
|
# empty" result.
|
||||||
value_annotation = True
|
value_annotation = True
|
||||||
@ -877,7 +873,7 @@ class ValuesQuerySet(QuerySet):
|
|||||||
return obj.query.get_compiler(connection=connection).as_nested_sql()
|
return obj.query.get_compiler(connection=connection).as_nested_sql()
|
||||||
raise ValueError("Can't do subqueries with queries on different DBs.")
|
raise ValueError("Can't do subqueries with queries on different DBs.")
|
||||||
|
|
||||||
def _validate(self):
|
def _prepare(self):
|
||||||
"""
|
"""
|
||||||
Validates that we aren't trying to do a query like
|
Validates that we aren't trying to do a query like
|
||||||
value__in=qs.values('value1', 'value2'), which isn't valid.
|
value__in=qs.values('value1', 'value2'), which isn't valid.
|
||||||
@ -886,7 +882,7 @@ class ValuesQuerySet(QuerySet):
|
|||||||
(not self._fields and len(self.model._meta.fields) > 1)):
|
(not self._fields and len(self.model._meta.fields) > 1)):
|
||||||
raise TypeError('Cannot use a multi-field %s as a filter value.'
|
raise TypeError('Cannot use a multi-field %s as a filter value.'
|
||||||
% self.__class__.__name__)
|
% self.__class__.__name__)
|
||||||
|
return self
|
||||||
|
|
||||||
class ValuesListQuerySet(ValuesQuerySet):
|
class ValuesListQuerySet(ValuesQuerySet):
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
|
@ -18,9 +18,10 @@ class RelatedObject(object):
|
|||||||
self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name)
|
self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name)
|
||||||
self.var_name = self.opts.object_name.lower()
|
self.var_name = self.opts.object_name.lower()
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value, connection):
|
def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
|
||||||
# Defer to the actual field definition for db prep
|
# Defer to the actual field definition for db prep
|
||||||
return self.field.get_db_prep_lookup(lookup_type, value)
|
return self.field.get_db_prep_lookup(lookup_type, value,
|
||||||
|
connection=connection, prepared=prepared)
|
||||||
|
|
||||||
def editable_fields(self):
|
def editable_fields(self):
|
||||||
"Get the fields in this class that should be edited inline."
|
"Get the fields in this class that should be edited inline."
|
||||||
|
@ -837,7 +837,7 @@ class SQLUpdateCompiler(SQLCompiler):
|
|||||||
self.query.related_ids = idents
|
self.query.related_ids = idents
|
||||||
else:
|
else:
|
||||||
# The fast path. Filters and updates in one query.
|
# The fast path. Filters and updates in one query.
|
||||||
self.query.add_filter(('pk__in', query.get_compiler(self.using)))
|
self.query.add_filter(('pk__in', query))
|
||||||
for alias in self.query.tables[1:]:
|
for alias in self.query.tables[1:]:
|
||||||
self.query.alias_refcount[alias] = 0
|
self.query.alias_refcount[alias] = 0
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ class SQLEvaluator(object):
|
|||||||
self.contains_aggregate = False
|
self.contains_aggregate = False
|
||||||
self.expression.prepare(self, query, allow_joins)
|
self.expression.prepare(self, query, allow_joins)
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
return self
|
||||||
|
|
||||||
def as_sql(self, qn, connection):
|
def as_sql(self, qn, connection):
|
||||||
return self.expression.evaluate(self, qn, connection)
|
return self.expression.evaluate(self, qn, connection)
|
||||||
|
|
||||||
|
@ -141,6 +141,9 @@ class Query(object):
|
|||||||
|
|
||||||
self.__dict__.update(obj_dict)
|
self.__dict__.update(obj_dict)
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
return self
|
||||||
|
|
||||||
def get_compiler(self, using=None, connection=None):
|
def get_compiler(self, using=None, connection=None):
|
||||||
if using is None and connection is None:
|
if using is None and connection is None:
|
||||||
raise ValueError("Need either using or connection")
|
raise ValueError("Need either using or connection")
|
||||||
|
@ -62,8 +62,8 @@ class WhereNode(tree.Node):
|
|||||||
else:
|
else:
|
||||||
annotation = bool(value)
|
annotation = bool(value)
|
||||||
|
|
||||||
if hasattr(obj, "process"):
|
if hasattr(obj, "prepare"):
|
||||||
obj.validate(lookup_type, value)
|
value = obj.prepare(lookup_type, value)
|
||||||
super(WhereNode, self).add((obj, lookup_type, annotation, value),
|
super(WhereNode, self).add((obj, lookup_type, annotation, value),
|
||||||
connector)
|
connector)
|
||||||
return
|
return
|
||||||
@ -143,7 +143,7 @@ class WhereNode(tree.Node):
|
|||||||
raise EmptyResultSet
|
raise EmptyResultSet
|
||||||
else:
|
else:
|
||||||
params = Field().get_db_prep_lookup(lookup_type, params_or_value,
|
params = Field().get_db_prep_lookup(lookup_type, params_or_value,
|
||||||
connection=connection)
|
connection=connection, prepared=True)
|
||||||
if isinstance(lvalue, tuple):
|
if isinstance(lvalue, tuple):
|
||||||
# A direct database column lookup.
|
# A direct database column lookup.
|
||||||
field_sql = self.sql_for_columns(lvalue, qn, connection)
|
field_sql = self.sql_for_columns(lvalue, qn, connection)
|
||||||
@ -262,6 +262,11 @@ class Constraint(object):
|
|||||||
def __init__(self, alias, col, field):
|
def __init__(self, alias, col, field):
|
||||||
self.alias, self.col, self.field = alias, col, field
|
self.alias, self.col, self.field = alias, col, field
|
||||||
|
|
||||||
|
def prepare(self, lookup_type, value):
|
||||||
|
if self.field:
|
||||||
|
return self.field.get_prep_lookup(lookup_type, value)
|
||||||
|
return value
|
||||||
|
|
||||||
def process(self, lookup_type, value, connection):
|
def process(self, lookup_type, value, connection):
|
||||||
"""
|
"""
|
||||||
Returns a tuple of data suitable for inclusion in a WhereNode
|
Returns a tuple of data suitable for inclusion in a WhereNode
|
||||||
@ -272,14 +277,14 @@ class Constraint(object):
|
|||||||
try:
|
try:
|
||||||
if self.field:
|
if self.field:
|
||||||
params = self.field.get_db_prep_lookup(lookup_type, value,
|
params = self.field.get_db_prep_lookup(lookup_type, value,
|
||||||
connection=connection)
|
connection=connection, prepared=True)
|
||||||
db_type = self.field.db_type(connection=connection)
|
db_type = self.field.db_type(connection=connection)
|
||||||
else:
|
else:
|
||||||
# This branch is used at times when we add a comparison to NULL
|
# This branch is used at times when we add a comparison to NULL
|
||||||
# (we don't really want to waste time looking up the associated
|
# (we don't really want to waste time looking up the associated
|
||||||
# field object at the calling location).
|
# field object at the calling location).
|
||||||
params = Field().get_db_prep_lookup(lookup_type, value,
|
params = Field().get_db_prep_lookup(lookup_type, value,
|
||||||
connection=connection)
|
connection=connection, prepared=True)
|
||||||
db_type = None
|
db_type = None
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise EmptyShortCircuit
|
raise EmptyShortCircuit
|
||||||
@ -289,7 +294,3 @@ class Constraint(object):
|
|||||||
def relabel_aliases(self, change_map):
|
def relabel_aliases(self, change_map):
|
||||||
if self.alias in change_map:
|
if self.alias in change_map:
|
||||||
self.alias = change_map[self.alias]
|
self.alias = change_map[self.alias]
|
||||||
|
|
||||||
def validate(self, lookup_type, value):
|
|
||||||
if hasattr(self.field, 'validate'):
|
|
||||||
self.field.validate(lookup_type, value)
|
|
||||||
|
@ -396,36 +396,58 @@ Python object type we want to store in the model's attribute.
|
|||||||
called when it is created, you should be using `The SubfieldBase metaclass`_
|
called when it is created, you should be using `The SubfieldBase metaclass`_
|
||||||
mentioned earlier. Otherwise :meth:`to_python` won't be called automatically.
|
mentioned earlier. Otherwise :meth:`to_python` won't be called automatically.
|
||||||
|
|
||||||
Converting Python objects to database values
|
Converting Python objects to query values
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. method:: get_db_prep_value(self, value, connection)
|
.. method:: get_prep_value(self, value)
|
||||||
|
|
||||||
This is the reverse of :meth:`to_python` when working with the database backends
|
This is the reverse of :meth:`to_python` when working with the
|
||||||
(as opposed to serialization). The ``value`` parameter is the current value of
|
database backends (as opposed to serialization). The ``value``
|
||||||
the model's attribute (a field has no reference to its containing model, so it
|
parameter is the current value of the model's attribute (a field has
|
||||||
cannot retrieve the value itself), and the method should return data in a format
|
no reference to its containing model, so it cannot retrieve the value
|
||||||
that can be used as a parameter in a query for the database backend. The
|
itself), and the method should return data in a format that has been
|
||||||
specific connection that will be used for the query is passed as the
|
prepared for use as a parameter in a query.
|
||||||
``connection`` parameter, this allows you to generate the value in a backend
|
|
||||||
specific mannner if necessary.
|
This conversion should *not* include any database-specific
|
||||||
|
conversions. If database-specific conversions are required, they
|
||||||
|
should be made in the call to :meth:`get_db_prep_value`.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection):
|
def get_prep_value(self, value):
|
||||||
return ''.join([''.join(l) for l in (value.north,
|
return ''.join([''.join(l) for l in (value.north,
|
||||||
value.east, value.south, value.west)])
|
value.east, value.south, value.west)])
|
||||||
|
|
||||||
|
Converting query values to database values
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. method:: get_db_prep_value(self, value, connection, prepared=False)
|
||||||
|
|
||||||
|
Some data types (for example, dates) need to be in a specific format
|
||||||
|
before they can be used by a database backend.
|
||||||
|
:meth:`get_db_prep_value` is the method where those conversions should
|
||||||
|
be made. The specific connection that will be used for the query is
|
||||||
|
passed as the ``connection`` parameter. This allows you to use
|
||||||
|
backend-specific conversion logic if it is required.
|
||||||
|
|
||||||
|
The ``prepared`` argument describes whether or not the value has
|
||||||
|
already been passed through :meth:`get_prep_value` conversions. When
|
||||||
|
``prepared`` is False, the default implementation of
|
||||||
|
:meth:`get_db_prep_value` will call :meth:`get_prep_value` to do
|
||||||
|
initial data conversions before performing any database-specific
|
||||||
|
processing.
|
||||||
|
|
||||||
.. method:: get_db_prep_save(self, value, connection)
|
.. method:: get_db_prep_save(self, value, connection)
|
||||||
|
|
||||||
Same as the above, but called when the Field value must be *saved* to the
|
Same as the above, but called when the Field value must be *saved* to
|
||||||
database. As the default implementation just calls ``get_db_prep_value``, you
|
the database. As the default implementation just calls
|
||||||
shouldn't need to implement this method unless your custom field needs a
|
``get_db_prep_value``, you shouldn't need to implement this method
|
||||||
special conversion when being saved that is not the same as the conversion used
|
unless your custom field needs a special conversion when being saved
|
||||||
for normal query parameters (which is implemented by ``get_db_prep_value``).
|
that is not the same as the conversion used for normal query
|
||||||
|
parameters (which is implemented by ``get_db_prep_value``).
|
||||||
|
|
||||||
Preprocessing values before saving
|
Preprocessing values before saving
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -453,7 +475,13 @@ correct value.
|
|||||||
Preparing values for use in database lookups
|
Preparing values for use in database lookups
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. method:: get_db_prep_lookup(self, lookup_type, value, connection)
|
As with value conversions, preparing a value for database lookups is a
|
||||||
|
two phase process.
|
||||||
|
|
||||||
|
.. method:: get_prep_lookup(self, lookup_type, value)
|
||||||
|
|
||||||
|
:meth:`get_prep_lookup` performs the first phase of lookup preparation,
|
||||||
|
performing generic data validity checks
|
||||||
|
|
||||||
Prepares the ``value`` for passing to the database when used in a lookup (a
|
Prepares the ``value`` for passing to the database when used in a lookup (a
|
||||||
``WHERE`` constraint in SQL). The ``lookup_type`` will be one of the valid
|
``WHERE`` constraint in SQL). The ``lookup_type`` will be one of the valid
|
||||||
@ -470,34 +498,42 @@ by with handling the lookup types that need special handling for your field
|
|||||||
and pass the rest to the :meth:`get_db_prep_lookup` method of the parent class.
|
and pass the rest to the :meth:`get_db_prep_lookup` method of the parent class.
|
||||||
|
|
||||||
If you needed to implement ``get_db_prep_save()``, you will usually need to
|
If you needed to implement ``get_db_prep_save()``, you will usually need to
|
||||||
implement ``get_db_prep_lookup()``. If you don't, ``get_db_prep_value`` will be
|
implement ``get_prep_lookup()``. If you don't, ``get_prep_value`` will be
|
||||||
called by the default implementation, to manage ``exact``, ``gt``, ``gte``,
|
called by the default implementation, to manage ``exact``, ``gt``, ``gte``,
|
||||||
``lt``, ``lte``, ``in`` and ``range`` lookups.
|
``lt``, ``lte``, ``in`` and ``range`` lookups.
|
||||||
|
|
||||||
You may also want to implement this method to limit the lookup types that could
|
You may also want to implement this method to limit the lookup types that could
|
||||||
be used with your custom field type.
|
be used with your custom field type.
|
||||||
|
|
||||||
Note that, for ``range`` and ``in`` lookups, ``get_db_prep_lookup`` will receive
|
Note that, for ``range`` and ``in`` lookups, ``get_prep_lookup`` will receive
|
||||||
a list of objects (presumably of the right type) and will need to convert them
|
a list of objects (presumably of the right type) and will need to convert them
|
||||||
to a list of things of the right type for passing to the database. Most of the
|
to a list of things of the right type for passing to the database. Most of the
|
||||||
time, you can reuse ``get_db_prep_value()``, or at least factor out some common
|
time, you can reuse ``get_prep_value()``, or at least factor out some common
|
||||||
pieces.
|
pieces.
|
||||||
|
|
||||||
For example, the following code implements ``get_db_prep_lookup`` to limit the
|
For example, the following code implements ``get_prep_lookup`` to limit the
|
||||||
accepted lookup types to ``exact`` and ``in``::
|
accepted lookup types to ``exact`` and ``in``::
|
||||||
|
|
||||||
class HandField(models.Field):
|
class HandField(models.Field):
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
# We only handle 'exact' and 'in'. All others are errors.
|
# We only handle 'exact' and 'in'. All others are errors.
|
||||||
if lookup_type == 'exact':
|
if lookup_type == 'exact':
|
||||||
return [self.get_db_prep_value(value)]
|
return [self.get_prep_value(value)]
|
||||||
elif lookup_type == 'in':
|
elif lookup_type == 'in':
|
||||||
return [self.get_db_prep_value(v) for v in value]
|
return [self.get_prep_value(v) for v in value]
|
||||||
else:
|
else:
|
||||||
raise TypeError('Lookup type %r not supported.' % lookup_type)
|
raise TypeError('Lookup type %r not supported.' % lookup_type)
|
||||||
|
|
||||||
|
.. method:: get_db_prep_lookup(self, lookup_type, value, connection, prepared=False)
|
||||||
|
|
||||||
|
Performs any database-specific data conversions required by a lookup.
|
||||||
|
As with :meth:`get_db_prep_value`, the specific connection that will
|
||||||
|
be used for the query is passed as the ``connection`` parameter.
|
||||||
|
The ``prepared`` argument describes whether the value has already been
|
||||||
|
prepared with :meth:`get_prep_lookup`.
|
||||||
|
|
||||||
Specifying the form field for a model field
|
Specifying the form field for a model field
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -35,6 +35,11 @@ their deprecation, as per the :ref:`Django deprecation policy
|
|||||||
(i.e., ``sqlite3`` instead of ``django.db.backends.sqlite3``) will be
|
(i.e., ``sqlite3`` instead of ``django.db.backends.sqlite3``) will be
|
||||||
removed.
|
removed.
|
||||||
|
|
||||||
|
* The ``get_db_prep_save``, ``get_db_prep_value`` and
|
||||||
|
``get_db_prep_lookup`` methods on Field were modified in 1.2 to support
|
||||||
|
multiple databases. In 1.4, the support functions that allow methods
|
||||||
|
with the old prototype to continue working will be removed.
|
||||||
|
|
||||||
* 2.0
|
* 2.0
|
||||||
* ``django.views.defaults.shortcut()``. This function has been moved
|
* ``django.views.defaults.shortcut()``. This function has been moved
|
||||||
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
|
to ``django.contrib.contenttypes.views.shortcut()`` as part of the
|
||||||
|
@ -141,6 +141,74 @@ appear in ``__dict__`` for a model instance. If your code relies on
|
|||||||
iterating over __dict__ to obtain a list of fields, you must now
|
iterating over __dict__ to obtain a list of fields, you must now
|
||||||
filter out ``_state`` attribute of out ``__dict__``.
|
filter out ``_state`` attribute of out ``__dict__``.
|
||||||
|
|
||||||
|
``get_db_prep_*()`` methods on Field
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Prior to v1.2, a custom field had the option of defining several
|
||||||
|
functions to support conversion of Python values into
|
||||||
|
database-compatible values. A custom field might look something like::
|
||||||
|
|
||||||
|
class CustomModelField(models.Field):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_db_prep_save(self, value):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
In 1.2, these three methods have undergone a change in prototype, and
|
||||||
|
two extra methods have been introduced::
|
||||||
|
|
||||||
|
class CustomModelField(models.Field):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_prep_value(self, value):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_prep_lookup(self, lookup_type, value):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_db_prep_save(self, value, connection):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
def get_prep_lookup(self, lookup_type, value, connection, prepared=False):
|
||||||
|
# ...
|
||||||
|
|
||||||
|
These changes are required to support multiple databases -
|
||||||
|
``get_db_prep_*`` can no longer make any assumptions regarding the
|
||||||
|
database for which it is preparing. The ``connection`` argument now
|
||||||
|
provides the preparation methods with the specific connection for
|
||||||
|
which the value is being prepared.
|
||||||
|
|
||||||
|
The two new methods exist to differentiate general data preparation
|
||||||
|
requirements, and requirements that are database-specific. The
|
||||||
|
``prepared`` argument is used to indicate to the database preparation
|
||||||
|
methods whether generic value preparation has been performed. If
|
||||||
|
an unprepared (i.e., ``prepared=False``) value is provided to the
|
||||||
|
``get_db_prep_*()`` calls, they should invoke the corresponding
|
||||||
|
``get_prep_*()`` calls to perform generic data preparation.
|
||||||
|
|
||||||
|
Conversion functions has been provided which will transparently
|
||||||
|
convert functions adhering to the old prototype into functions
|
||||||
|
compatible with the new prototype. However, this conversion function
|
||||||
|
will be removed in Django 1.4, so you should upgrade your Field
|
||||||
|
definitions to use the new prototype.
|
||||||
|
|
||||||
|
If your ``get_db_prep_*()`` methods made no use of the database
|
||||||
|
connection, you should be able to upgrade by renaming
|
||||||
|
``get_db_prep_value()`` to ``get_prep_value()`` and
|
||||||
|
``get_db_prep_lookup()`` to ``get_prep_lookup()`. If you require
|
||||||
|
database specific conversions, then you will need to provide an
|
||||||
|
implementation ``get_db_prep_*`` that uses the ``connection``
|
||||||
|
argument to resolve database-specific values.
|
||||||
|
|
||||||
.. _deprecated-features-1.2:
|
.. _deprecated-features-1.2:
|
||||||
|
|
||||||
Features deprecated in 1.2
|
Features deprecated in 1.2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user