Opened 4 years ago

Last modified 4 years ago

#31450 new Bug

Querying on ArrayField(PointField) returns string instead of list

Reported by: Nitin Sangwan Owned by:
Component: contrib.postgres Version: 3.0
Severity: Normal Keywords: ArrayField, PointField
Cc: Simon Charette Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

The following code

from django.db import models
from django.contrib.postgres.fields import ArrayField
from django.contrib.gis.db.models import PointField


class Foo(models.Model):
    bar = ArrayField(models.TextField)
    baz = ArrayField(PointField())

has this wrong behaviour:

x = Foo.objects.get(id=1)
x.bar #  => ['Foo', 'Bar']
x.baz #  => '{HexRepresentationofPoint1,HexRepresentationofPoint2}'

Attachments (1)

postgis_tests.zip (2.5 KB ) - added by Carlton Gibson 4 years ago.
Reproduce test case for #31450

Download all attachments as: .zip

Change History (7)

by Carlton Gibson, 4 years ago

Attachment: postgis_tests.zip added

Reproduce test case for #31450

comment:1 by Carlton Gibson, 4 years ago

Triage Stage: UnreviewedAccepted

Thanks for the report. Reproduced at 578c03b276e435bcd3ce9eb17b81e85135c2d3f3 with the attached test case.

comment:2 by Mariusz Felisiak, 4 years ago

Has patch: set
Owner: set to Hasan Ramezani
Patch needs improvement: set
Status: newassigned

comment:3 by Hasan Ramezani, 4 years ago

Comment from the PR:

Thanks @Simon for your suggestion.
I've tried to create and register a new array type for geometry based on your suggestion at #8453. here is the code:

def get_geometry_oids(connection_alias):
    with connections[connection_alias].cursor() as cursor:
        cursor.execute("SELECT typarray FROM pg_type WHERE typname = 'geometry'")
        return tuple(row[0] for row in cursor)

...

       geometry_oids = get_geometry_oids(connection.alias)
        new_type = psycopg2.extensions.new_type(geometry_oids, "geometry", caster) # caster is function to cast hex to geometry object
        array_type = psycopg2.extensions.new_array_type(geometry_oids, 'geometry[]', new_type)
        psycopg2.extensions.register_type(array_type, None)

The problem is that in caster function, I get all items in array not one item. something like this:
0101000020E610000000000000000018400000000000003840:0101000020E610000000000000000014400000000000003740
which is represent two points that seprated by :.
I've checed the column value in postgres console. for an array of points I got this:
{0101000020E6100000000000000000F03F0000000000000040:0101000020E6100000000000000000F03F0000000000000040}
While, I got below value for an array of chars:
{foo,bar}

the difference between two cases is for an array of points I got : as a separator, but for an array of chars I got ,.

I also tried to insert data from console to an array of points column by:
insert into test values (ARRAY[st_geomFromText('POINT(1 1)', 4326), st_geomFromText('POINT(1 1)', 4326)]);
the result was the same(: as separator).

Do you have any idea?

comment:4 by Simon Charette, 4 years ago

Cc: Simon Charette added

comment:5 by Simon Charette, 4 years ago

I spent a few hours trying to figure it out but it looks like there might be something wrong with psycopg2. When registering an array type for geometry from the retrieved oid it simply doesn't get invoked for columns of type geometry(POINT, srid)[] behind ArrayField(PointField()).

Hasan your code is registering an array type and a scalar type for the same oid, you want to register a type for the scalar oid and an array type for array oid. Look at how get_hstore_oids and psycopg2.extras.register_hstore do it.

comment:6 by Hasan Ramezani, 4 years ago

Owner: Hasan Ramezani removed
Status: assignednew
Note: See TracTickets for help on using tickets.
Back to Top