Opened 87 minutes ago

Last modified 71 minutes ago

#37322 new Bug

Saving to SpatialField(srid=None) persists NULL instead of raising an error

Reported by: Jacob Walls Owned by:
Component: GIS Version: 6.1
Severity: Release blocker Keywords: srid
Cc: Simon Charette Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

At least one user has tried to use spatial fields with a definition of srid=None, see forum. I'm pretty certain that's invalid usage.

Django can't create a migration to create such a spatial column with srid=None[0], but you can imagine a user trying this with an unmanaged model.

In Django 6.0, trying to save values to such a field raised DatabaseError, because None compiled to the string "None" and crashed.

After 1a8fd5cf75bf855852f6bc2f75c3da9f7b145669 (#36727, Django 6.1) implemented proper parameterization for srid values in spatial queries, None compiled to NULL, which zeroed out the value (because ST_Transform(..., NULL) returns NULL).

Suggesting we throw an error for this case in Python before letting the query persist NULL.

Test case on DryORM:
(You could probably construct a version of this test case using only output_field=GeometryField(srid=None)).)

from django.contrib.gis.db import models
from django.contrib.gis.geos import GEOSGeometry
from django.db.models.expressions import Value

class Person(models.Model):
    # Create this field without srid=None for the sake of creating
    # a working migration.
    home = models.PointField(null=True)


def run():
    # Because Django migrated this model, restore the model field
    # to have srid=None, to simulate an unmanaged model.
    home = Person._meta.get_fields()[1]
    home.srid = None

    me = Person.objects.create()
    me.home = GEOSGeometry("POINT(1 1)", srid=4326)
    me.save()
    me.refresh_from_db()
    assert me.home  # raises

Rerunning that snippet on 6.0 gives a DatabaseError instead. We can raise an error in the ORM layer instead.


[0] At least on PostGIS, because of a %d placeholder. I can check other backends shortly.

Change History (2)

in reply to:  description comment:1 by Jacob Walls, 71 minutes ago

[0] At least on PostGIS, because of a %d placeholder. I can check other backends shortly.

MySQL/MariaDB: a Django migration to create this column works, but transforms aren't supported, so never attempted
Spatialite: can't create the column: "django.db.utils.OperationalError: no such column: None"
Oracle: can't create the column: "django.db.utils.DatabaseError: ORA-00984: column not allowed here

comment:2 by Jacob Walls, 71 minutes ago

Summary: Saving to SpatialField(srid=None) persists NULL instead of raising DatabaseErrorSaving to SpatialField(srid=None) persists NULL instead of raising an error
Note: See TracTickets for help on using tickets.
Back to Top