Opened 4 years ago

Last modified 4 years ago

#31910 closed Bug

Django geo model aggregate union fails with distinct — at Version 1

Reported by: Eran Keydar Owned by: nobody
Component: GIS Version: 3.1
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Eran Keydar)

The following code works ok on django 2.7, and fails on django 3 and 3.1
(without the distinct if works ok)

Database is postgis

class PolyModel(models.Model):
    name = models.CharField(max_length=50)
    geom = models.PolygonField()


def run_example():
    PolyModel.objects.all().delete()
    for x in range(1, 10):
        PolyModel.objects.create(
            name="poly_{}".format(x),
            geom=Point(34+x, 34+x).buffer(0.01)
        )
    print(PolyModel.objects.distinct().aggregate(u=Union('geom')))

Output:

<ipython-input-5-c368ff40e50b> in <module>
----> 1 PolyModel.objects.distinct().aggregate(u=Union('geom'))

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/db/models/query.py in aggregate(self, *args, **kwargs)
    396             if not query.annotations[alias].contains_aggregate:
    397                 raise TypeError("%s is not an aggregate expression" % alias)
--> 398         return query.get_aggregation(self.db, kwargs)
    399 
    400     def count(self):

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/db/models/sql/query.py in get_aggregation(self, using, added_aggregate_names)
    503 
    504         converters = compiler.get_converters(outer_query.annotation_select.values())
--> 505         result = next(compiler.apply_converters((result,), converters))
    506 
    507         return dict(zip(outer_query.annotation_select, result))

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/db/models/sql/compiler.py in apply_converters(self, rows, converters)
   1096                 value = row[pos]
   1097                 for converter in convs:
-> 1098                     value = converter(value, expression, connection)
   1099                 row[pos] = value
   1100             yield row

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/contrib/gis/db/backends/postgis/operations.py in converter(value, expression, connection)
    385 
    386         def converter(value, expression, connection):
--> 387             return None if value is None else GEOSGeometryBase(read(value), geom_class)
    388         return converter
    389 

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/contrib/gis/geos/prototypes/io.py in read(self, wkb)
    151             return wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
    152         elif isinstance(wkb, (bytes, str)):
--> 153             return wkb_reader_read_hex(self.ptr, wkb, len(wkb))
    154         else:
    155             raise TypeError

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/contrib/gis/geos/libgeos.py in __call__(self, *args)
    150 
    151     def __call__(self, *args):
--> 152         return self.func(*args)
    153 
    154     @cached_property

~/.virtualenvs/bug1/lib/python3.6/site-packages/django/contrib/gis/geos/prototypes/threadsafe.py in __call__(self, *args)
     45         # Call the threaded GEOS routine with the pointer of the context handle
     46         # as the first argument.
---> 47         return self.cfunc(self.thread_context.handle.ptr, *args)
     48 
     49     def __str__(self):

ArgumentError: argument 3: <class 'TypeError'>: wrong type


Looking at the generated query, gives this:

{'sql': 'SELECT ST_Union("__col1") FROM (SELECT DISTINCT "core_polymodel"."id" AS Col1, "core_polymodel"."name" AS Col2, "core_polymodel"."geom" AS Col3, "core_polymodel"."geom" AS "__col1" FROM "core_polymodel") subquery',
 'time': '0.001'}

So it seems that the union is done on the wrong column.

Thanks

Change History (1)

comment:1 by Eran Keydar, 4 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top