#13844: Errors when using character fields for aggregation
-------------------------------------+-------------------------------------
Reporter: zegrep@… | Owner: wogan
Type: Bug | Status: assigned
Milestone: | Component: Database layer
Version: 1.2 | (models, ORM)
Resolution: | Severity: Normal
Triage Stage: Accepted | Keywords:
Needs documentation: 0 | Has patch: 1
Patch needs improvement: 1 | Needs tests: 1
-------------------------------------+-------------------------------------
Changes (by julien):
* needs_better_patch: 0 => 1
* needs_tests: 0 => 1
Old description:
> My intension is joining tables with two different formated columns,
> by using django's double underscore magic to resolve the querysets.
>
> The values in table B are preceded by leading zeros.
>
> table A --> id = "10"
>
> table B --> id = "000010"
>
> {{{
> select distinct b.id from a, b where where a.id = TRIM(leading '0' FROM
> b.id);
> }}}
>
> The resulting code should look like this
> {{{
> qs_a=A.objects.all().values('id')
> qs_b=B.objects.annotate(id_trim=Trim('id', position='leading',
> char='0')).filter(id_trim__in=qs_a)
> }}}
>
> I use the following code to implement the extra functionality.
>
> {{{
> try:
> import psycopg2
> except ImportError, e:
> import psycopg
> else:
> psycopg = psycopg2._psycopg
>
> class Trim(django.db.models.Aggregate):
> name = 'Trim_pg'
> django.db.models.Trim=Trim
>
> class Trim_pg(django.db.models.sql.aggregates.Aggregate):
> '''
> position = [leading, trailing, both]
> char = <character to remove>
> '''
>
> sql_function = 'TRIM'
> sql_template = '''%(function)s(%(position)s %(char)s FROM
> %(field)s)'''
>
> def __init__(self, col, distinct=False, **extra):
> assert extra.has_key('position'), u'no position'
> assert extra['position'] in ('leading', 'trailing', 'both'),
> 'position no in [leading, trailing, both]'
> assert extra.has_key('char'), u'no char'
> assert len(extra['char']) == 1, 'only one character'
> extra['char']=str(psycopg2._psycopg.QuotedString(extra['char']))
> #Quoting
> super(Trim_pg, self).__init__(col, distinct=distinct, **extra)
> django.db.models.sql.aggregates.Trim_pg=Trim_pg
> }}}
>
> The problem is, that "convert_values" makes for a "CharField"
> a cast to float. My solution is to return the value for CharFields
> without the cast.
>
> {{{
> Index: db/backends/__init__.py
> ===================================================================
> --- db/backends/__init__.py (Revision 12595)
> +++ db/backends/__init__.py (Arbeitskopie)
> @@ -438,6 +438,8 @@
> return int(value)
> elif internal_type in ('DateField', 'DateTimeField',
> 'TimeField'):
> return value
> + elif internal_type in ('CharField'):
> + return value
> # No field, or the field isn't known to be a decimal or integer
> # Default to a float
> return float(value)
> }}}
New description:
My intension is joining tables with two different formated columns,
by using django's double underscore magic to resolve the querysets.
The values in table B are preceded by leading zeros.
table A --> id = "10"
table B --> id = "000010"
{{{
select distinct b.id from a, b where where a.id = TRIM(leading '0' FROM
b.id);
}}}
The resulting code should look like this
{{{
qs_a=A.objects.all().values('id')
qs_b=B.objects.annotate(id_trim=Trim('id', position='leading',
char='0')).filter(id_trim__in=qs_a)
}}}
I use the following code to implement the extra functionality.
{{{
try:
import psycopg2
except ImportError, e:
import psycopg
else:
psycopg = psycopg2._psycopg
class Trim(django.db.models.Aggregate):
name = 'Trim_pg'
django.db.models.Trim=Trim
class Trim_pg(django.db.models.sql.aggregates.Aggregate):
'''
position = [leading, trailing, both]
char = <character to remove>
'''
sql_function = 'TRIM'
sql_template = '''%(function)s(%(position)s %(char)s FROM
%(field)s)'''
def __init__(self, col, distinct=False, **extra):
assert extra.has_key('position'), u'no position'
assert extra['position'] in ('leading', 'trailing', 'both'),
'position no in [leading, trailing, both]'
assert extra.has_key('char'), u'no char'
assert len(extra['char']) == 1, 'only one character'
extra['char']=str(psycopg2._psycopg.QuotedString(extra['char']))
#Quoting
super(Trim_pg, self).__init__(col, distinct=distinct, **extra)
django.db.models.sql.aggregates.Trim_pg=Trim_pg
}}}
The problem is, that "convert_values" makes for a "CharField"
a cast to float. My solution is to return the value for CharFields
without the cast.
{{{
Index: db/backends/__init__.py
===================================================================
--- db/backends/__init__.py (Revision 12595)
+++ db/backends/__init__.py (Arbeitskopie)
@@ -438,6 +438,8 @@
return int(value)
elif internal_type in ('DateField', 'DateTimeField',
'TimeField'):
return value
+ elif internal_type in ('CharField'):
+ return value
# No field, or the field isn't known to be a decimal or integer
# Default to a float
return float(value)
}}}
--
Comment:
Patch needs improvement as per chronos' comment. Also needs tests.
--
Ticket URL: <http://code.djangoproject.com/ticket/13844#comment:6>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.