Opened 4 months ago

Last modified 3 months ago

#31450 assigned Bug

Querying on ArrayField(PointField) returns string instead of list

Reported by: Nitin Sangwan Owned by: Hasan Ramezani
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 months ago.
Reproduce test case for #31450

Download all attachments as: .zip

Change History (6)

Changed 4 months ago by Carlton Gibson

Attachment: postgis_tests.zip added

Reproduce test case for #31450

comment:1 Changed 4 months ago by Carlton Gibson

Triage Stage: UnreviewedAccepted

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

comment:2 Changed 4 months ago by felixxm

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

comment:3 Changed 4 months ago by Hasan Ramezani

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 Changed 4 months ago by Simon Charette

Cc: Simon Charette added

comment:5 Changed 3 months ago by Simon Charette

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.

Note: See TracTickets for help on using tickets.
Back to Top