Code

Opened 2 years ago

Last modified 13 months ago

#17635 new New feature

Missing ability to cast georaphy to geometry when using GeoDjango and PostgresSQL

Reported by: corentin.chary@… Owned by: nobody
Component: GIS Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by aaugustin)

Looking at http://postgis.refractions.net/docs/ch08.html#PostGIS_TypeFunctionMatrix you will see that a lot of functions only work on geometric fields (ie: geography=False).

That means something like Markers.objects.extent() won't work if the coordinate field of Marker have geography set to True because the underlying function (ST_Extent()) only work with geometric fields.

A workaround (if you don't really care about precision) is to cast geography to geometry:

SELECT ST_Extent(coordinates::geometry) FROM markers;

That will perfectly work. However, you can't really do that with django. The best you can do seems to be:

qs.extra(select={'extent': 'ST_Extent("coordinates"::geometry)'}).values('extent')

But that's really far from perfect.

Here are some propositions:

  • add a way to cast to geometry, that would allow to do: qs.extent(field_name=coordinates__geometry) (the trailing __geometry cast a GeometryField from geography to geometry)
  • another way to cast to geometry would be: qs.geometry('coordinates').extent()
  • automatically cast geography to geometry if a function only support geometry (hum...)

Attachments (0)

Change History (2)

comment:1 Changed 2 years ago by aaugustin

  • Description modified (diff)
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

I've encountered the same problem (with point_on_surface and envelope) and I didn't even manage to resolve it with Django's public APIs.

Here's what I ended up with:

class ZoneManager(gis_models.GeoManager):

    def point_on_surface_and_envelope(self):
        # Use a private API to adapt point_on_surface and envelope for a
        # geographic field. See django.contrib.gis.db.models.query.GeoQuerySet.
        return self.all()._spatial_attribute('point_on_surface', {
            'select_field' : GeomField(),
            'procedure_fmt': '%(geo_col)s::geometry',   # added '::geometry'
        })._spatial_attribute('envelope', {
            'select_field' : GeomField(),
            'procedure_fmt': '%(geo_col)s::geometry',   # added '::geometry'
        })

Maybe I should have started with geometry fields instead of geography fields, but I didn't expect to need these functions...


While I'm interested in a solution to this problem, I'm not convinced we should allow these kind of approximations.

Marking as DDN for now, the GIS maintainer may have a stronger opinion on this matter.

comment:2 Changed 13 months ago by aaugustin

  • Triage Stage changed from Design decision needed to Accepted

Oh well.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as new
The owner will be changed from nobody to anonymous. Next status will be 'assigned'
as The resolution will be set. Next status will be 'closed'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.