Opened 9 years ago
Last modified 6 days ago
#28341 assigned Bug
GeometryField doesn't create GEOSGeometry objects lazily anymore
| Reported by: | Sergey Fedoseev | Owned by: | Abhimanyu Singh Negi |
|---|---|---|---|
| Component: | GIS | Version: | 1.8 |
| 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 )
Bisected to e9103402c0fa873aea58a6a11dba510cd308cb84 on test project with this script:
import mock
import sys
with mock.patch('django.utils.six.moves.html_parser'):
import django
from django.test import TestCase
from django.contrib.gis.geos import Point
from test_app.models import City
def side_effect(*args, **kwargs):
sys.exit(1)
django.setup()
with mock.patch('django.contrib.gis.db.models.fields.Geometry.__init__', side_effect=side_effect):
City.objects.first()
This laziness is declared in GeoDjango Tutorial.
Change History (10)
comment:1 by , 9 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:2 by , 9 years ago
| Description: | modified (diff) |
|---|
comment:3 by , 9 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:4 by , 9 years ago
| Owner: | changed from to |
|---|
comment:7 by , 9 years ago
comment:9 by , 2 weeks ago
| Owner: | set to |
|---|
Hi, I spent some time digging into this and I think I understand what’s going on.
Right now geometry objects are being created too early. The conversion happens in the database converter layer — BaseSpatialOperations.get_db_converters() adds a geometry converter, and that converter runs in SQLCompiler.apply_converters(). So GEOSGeometry gets created while rows are being fetched, before the values ever reach the model instance. Because of that, SpatialProxy never sees raw values and the lazy-loading path isn’t used.
I traced this through the ORM flow and confirmed that model instances already contain GEOSGeometry objects in instance.dict, which explains why accessing the field later doesn’t trigger any conversion.
One important detail is that values() and values_list() depend on converters returning geometry objects immediately, so converters can’t just be removed. The fix needs to keep eager conversion for those cases but allow raw values when loading model instances so SpatialProxy can do the conversion lazily.
I’m going to try implementing this by adjusting the geometry converter / registration logic so conversion is skipped when loading model instances, then add a regression test and run the GIS test suite to make sure nothing else breaks.
Assigning this issue to myself for implementation.
comment:10 by , 2 weeks ago
| Has patch: | set |
|---|
comment:11 by , 2 weeks ago
I have opened a pr addressing this issue(https://github.com/django/django/pull/20687)
During my investigation I confirmed that GeometryField values were being converted to GEOSGeometry obejcts, and Spatial proxy never receives the values the loading is bypassed
What i tried to do was to try distinguish model instance coming from values( queries ) so that raw WKB can be returned for model feilds, but due to lack of enogh query context they couldnt be distinuished properly
so i tried a diffrent approach, the backend converters return raw db values and the lazy conversion is handeled as intended by Spatial Proxy. So the values(), values_list(), annotations, and aggreagates are explicitly converted at result part, where the query context and output feilds are there.
So this restores the lazy loading while keeping the existing behaviour of the values() and aggregation queries.
Note: setting up and running the GIS tests required installing GDAL/PostGIS locally, and some GIS related jobs are failing in the CI, any guidance on how to fix that would be appriciated
comment:12 by , 6 days ago
| Has patch: | unset |
|---|
Apologies for spam - Are you working on this ? @SergeyFedoseev