Opened 5 years ago

Last modified 4 years ago

#30489 closed Bug

Django RasterField deserialization bug with pixeltype flags — at Version 1

Reported by: Ivor Bosloper Owned by: nobody
Component: GIS Version: dev
Severity: Normal Keywords: RasterField
Cc: Hasan Ramezani 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 Ivor Bosloper)

After inserting some raster data with raster2pgsql into a Django model table with a RasterField column, I get a list index out of range when querying the table with a Django Queryset.

...
File "django/contrib/gis/db/models/fields.py" in from_db_value
  360.         return connection.ops.parse_raster(value)
File "django/contrib/gis/db/backends/postgis/operations.py" in parse_raster
  369.         return from_pgraster(value)
File "django/contrib/gis/db/backends/postgis/pgraster.py" in from_pgraster
  57.         pixeltype = POSTGIS_TO_GDAL[pixeltype]

It turns out the pixeltype value used is 39 while the POSTGIS_TO_GDAL list is only 16 elements long. The database field contains valid data but can not be deserialized with Django.

Steps for reproduction:

# Django model
class RasterModel(models.Model):
    rast = models.RasterField(srid=4326)

# raw sql, single pixel raster with nodata bit set
insert into app_rastermodel values(1, REPLACE('01 0000 0100 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 E6100000 0100 0100 6 2 03 03', ' ', '')::raster);

# query generating Exception
RasterModel.objects.get(pk=1)

Analysis: if we look at the Raster specification, the pixeltype is a byte of which the 4 highest bits are flags and the lowest 4 bits are the real pixeltype, but the Django deserialization code only considers one bit-flag:

# django/contrib/gis/db/backends/postgis/pgraster.py
def from_pgraster(data):
        ...
        # Subtract nodata byte from band nodata value if it exists
        has_nodata = pixeltype >= 64
        if has_nodata:
            pixeltype -= 64
       ...

The erroneous pixeltype 39 in my example actually had the BANDTYPE_FLAG_ISNODATA (32) bit set which indicates all rastervalues are nodata.

I have created (my first django) patch and hope somebody can assist me in getting it correct and merged.

Change History (1)

comment:1 by Ivor Bosloper, 5 years ago

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