我需要生成一个相当大的GeoJSON数据集。将queryset序列化为geojson是可行的,但是速度非常慢。对我来说大约30秒。使用PostGIS ST_AsGeoJSON({geometry_field})::json
,然后从该查询集创建数据结构需要几秒钟,从而产生完全相同的结果。你知道吗
因此,要在代码中使用这个方法,我有一个函数geojson_queryset(queryset, geom_field, pk_field, other_fields)
(下面引用全文)。我最初写道:
features_queryset = queryset.extra(
select={'geojson_queryset_result': f'ST_AsGeoJSON({geometry_field})::json'})\
.values(*all_fields)
但在读取QuerySet API doc for extra()时,该方法已被弃用,应该编写为:
features_queryset = queryset.annotate(
geojson_queryset_result=RawSQL(f'ST_AsGeoJSON({geometry_field})::json', [])
).values(*all_fields)
这里我不关心SQL注入,因为这些字段完全不受用户输入的影响,我们只有一个geom
、一个simplified_geom
或location
。你知道吗
但问题是,当queryset执行连接时,名称“geom”可能变得模棱两可。Area.objects.filter(foo=1)
很好,但是Area.objects.filter(zone__foo=1)
如果分区也有geom字段,则会失败。你知道吗
在RawSQL中使用参数是行不通的,因为它们是用于值的,而不是用于列名,所以它们被引用了。你知道吗
所以我的问题是如何将geom
转换成正确的sql列表达式,如a0.geom
?你知道吗
完整代码: sql\注入\几何\正则表达式=重新编译(r“[^a-zA-Z0-9]”)
def geojson_queryset(queryset, geometry_field, pk_field='id', fields=[]):
"""
This method is fast way to serialize to GeoJSON a queryset. The regular serializer is extremely slow and will need
to be parsed from text to return in a Response object. This method is roughly 20x faster.
:param queryset: queryset to return data from
:param geometry_field: the field to be serialized to geojson
:param pk_field: GeoJSON requires a primary key value, defaults to 'id'
:param fields: List of fields to include in the result
:return: a GeoJSON FeatureCollection with the requested data.
"""
all_fields = [pk_field, *fields, 'geojson_queryset_result']
# Try to avoid SQL injection in the geom_field name
if sql_injection_geom_regex.match(geometry_field):
raise ValueError("invalid geom field name")
features_queryset = queryset.annotate(
geojson_queryset_result=RawSQL(f'ST_AsGeoJSON({geometry_field})::json', [])
).values(*all_fields)
# features_queryset = queryset.extra(
# select={'geojson_queryset_result': f'ST_AsGeoJSON({geometry_field})::json'})\
# .values(*all_fields)
features = []
for row in features_queryset:
features.append({
'type': 'Feature',
'id': row['id'],
'geometry': row['geojson_queryset_result'],
'properties': {field: row[field] for field in fields}
})
return {
'type': 'FeatureCollection',
'crs': {
'type': 'name',
'properties': {
'name': 'EPSG:4326'
}
},
'features': features
}
目前没有回答
相关问题 更多 >
编程相关推荐