#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 django-updates@googlegroups.com. To unsubscribe from this group, send email to django-updates+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-updates?hl=en.