Refs -- Simplified introspection of geography columns on PostGIS.
@@ -3,9 +3,7 @@ from django.db.backends.postgresql.introspection import DatabaseIntrospection
class PostGISIntrospection(DatabaseIntrospection):
- # Reverse dictionary for PostGIS geometry types not populated until
- # introspection is actually performed.
- postgis_types_reverse = {}
+ postgis_oid_lookup = {} # Populated when introspection is performed.
ignored_tables = DatabaseIntrospection.ignored_tables + [
'geography_columns',
@@ -15,42 +13,17 @@ class PostGISIntrospection(DatabaseIntrospection):
'raster_overviews',
]
- def get_postgis_types(self):
- """
- Return a dictionary with keys that are the PostgreSQL object
- identification integers for the PostGIS geometry and/or
- geography types (if supported).
- """
- field_types = [
- ('geometry', 'GeometryField'),
- # The value for the geography type is actually a tuple
- # to pass in the `geography=True` keyword to the field
- # definition.
- ('geography', ('GeometryField', {'geography': True})),
- ]
- postgis_types = {}
-
- # The OID integers associated with the geometry type may
- # be different across versions; hence, this is why we have
- # to query the PostgreSQL pg_type table corresponding to the
- # PostGIS custom data types.
- oid_sql = 'SELECT "oid" FROM "pg_type" WHERE "typname" = %s'
- with self.connection.cursor() as cursor:
- for field_type in field_types:
- cursor.execute(oid_sql, (field_type[0],))
- for result in cursor.fetchall():
- postgis_types[result[0]] = field_type[1]
- return postgis_types
-
def get_field_type(self, data_type, description):
- if not self.postgis_types_reverse:
- # If the PostGIS types reverse dictionary is not populated, do so
- # now. In order to prevent unnecessary requests upon connection
- # initialization, the `data_types_reverse` dictionary is not updated
- # with the PostGIS custom types until introspection is actually
- # performed -- in other words, when this function is called.
- self.postgis_types_reverse = self.get_postgis_types()
- self.data_types_reverse.update(self.postgis_types_reverse)
+ if not self.postgis_oid_lookup:
+ # Query PostgreSQL's pg_type table to determine the OID integers
+ # for the PostGIS data types used in reverse lookup (the integers
+ # may be different across versions). To prevent unnecessary
+ # requests upon connection initialization, the `data_types_reverse`
+ # dictionary isn't updated until introspection is performed here.
+ with self.connection.cursor() as cursor:
+ cursor.execute("SELECT oid, typname FROM pg_type WHERE typname IN ('geometry', 'geography')")
+ self.postgis_oid_lookup = dict(cursor.fetchall())
+ self.data_types_reverse.update((oid, 'GeometryField') for oid in self.postgis_oid_lookup)
return super().get_field_type(data_type, description)
def get_geometry_type(self, table_name, description):
@@ -78,6 +51,8 @@ class PostGISIntrospection(DatabaseIntrospection):
field_type = OGRGeomType(field_type).django
# Getting any GeometryField keyword arguments that are not the default.
field_params = {}
+ if self.postgis_oid_lookup.get(description.type_code) == 'geography':
+ field_params['geography'] = True
if srid != 4326:
field_params['srid'] = srid
if dim != 2:
