Python 用于RawSql的queryset字段的Django sql名称
我需要生成一个相当大的GeoJSON数据集。将queryset序列化为geojson是可行的,但速度非常慢。就我而言,大约30秒。使用PostGISPython 用于RawSql的queryset字段的Django sql名称,python,django,Python,Django,我需要生成一个相当大的GeoJSON数据集。将queryset序列化为geojson是可行的,但速度非常慢。就我而言,大约30秒。使用PostGISST_AsGeoJSON({geometry\u field})::json然后从该查询集创建数据结构需要几秒钟,产生完全相同的结果 因此,为了在我的代码中使用这个方法,我有一个函数geojson\u queryset(queryset,geom\u字段,pk\u字段,其他字段)(在下面完整引用)。我最初写道: features_queryset
ST_AsGeoJSON({geometry\u field})::json
然后从该查询集创建数据结构需要几秒钟,产生完全相同的结果
因此,为了在我的代码中使用这个方法,我有一个函数geojson\u queryset(queryset,geom\u字段,pk\u字段,其他字段)
(在下面完整引用)。我最初写道:
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\u geom
或location
但问题是,当queryset执行连接时,“geom”的名称可能会变得模棱两可<代码>区域.objects.filter(foo=1)很好,但是如果区域也有geom字段,则区域.objects.filter(zone\uu foo=1)
将失败
在RawSQL中使用参数不起作用,因为它们用于值,而不是列名,所以它们被引用
因此,我的问题是如何将geom
转换为正确的sql列表达式,如a0.geom
完整代码:
sql\u injection\u geom\u regex=re.compile(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
}