我有两种模型:一种用于维护点网格,第二种用于保存地理空间数据
from django.contrib.gis.db import models as geomodels
from django.db import models
class Grid(geomodels.Model):
geom = geomodels.PointField(srid=4326, unique=True)
elevation = geomodels.FloatField(blank=True, null=True)
class SpData(models.Model):
mtime = models.DateTimeField()
grid = models.ForeignKey(Grid)
measure = models.DecimalField(
max_digits=6,
decimal_places=1,
blank=True,
null=True,
)
使用django rest框架,很容易获得模型的geojson文件 有一个几何字段作为我的网格模型,下面的视图提供了一个 精美的geojson,其中geom作为几何字段,属性中具有“高程”。
from django.http import HttpResponse
from django.core.serializers import serialize
from rest_framework.views import APIView
from .models import Grid
class GridView(APIView):
def get(self, request):
result = serialize(
"geojson",
Grid.objects.all(),
geometry_field="geom",
srid=4326,
fields=(
"elevation",
),
)
return HttpResponse(result)
现在,我想使用相同的网格来显示链接到的SpData记录 我的网格模型显示“度量”值,但我没有成功指出 到我要使用Grid表的几何图形的序列化程序。我想 这样优雅的代码可以工作:
class SpDataView(APIView):
def get(self, request):
geodata = SpData.objects.filter(mtime=today())
fields = ("measure", "grid",)
result = serialize(
"geojson",
geodata,
geometry_field="grid.geom",
srid=4326,
fields=fields,
use_natural_foreign_keys=True,
)
return HttpResponse(result)
但事实并非如此。因此,我尝试将属性字段添加到我的SpData模型中,但是它也不起作用:
class SpData(models.Model):
mtime = models.DateTimeField()
grid = models.ForeignKey(Grid)
measure = models.DecimalField(
max_digits=6,
decimal_places=1,
blank=True,
null=True,
)
@property
def geom(self):
return self.grid.geom
class SpDataView(APIView):
def get(self, request):
geodata = SpData.objects.filter(mtime=today())
fields = ("measure", "geom",)
result = serialize(
"geojson",
geodata,
geometry_field="geom",
srid=4326,
fields=fields,
)
return HttpResponse(result)
我尝试使用原始SQL查询,但是序列化程序仅考虑 完成原始sql的模型。
strsql ='SELECT sp.pk, sp.measure, g.geom '
strsql += ' FROM SpData AS sp'
strsql += ' INNER JOIN Grid AS g'
strsql += ' ON sp.grid = g.pk'
strsql += ' WHERE sp.mtime = today()'
geodata = SpData.objects.raw(strsql)
fields = ("measure", "geom",)
result = serialize(
"geojson",
geodata,
geometry_field="geom",
srid=4326,
fields=fields,
)
return HttpResponse(result)
但是我生成的geojson中的几何等于null。所以还原SQL将 提供几何图形,但不会将字段“度量”添加到属性中:
strsql ='SELECT g.pk, sp.measure, g.geom '
strsql += ' FROM Grid AS g'
strsql += ' INNER JOIN SpData AS sp'
strsql += ' ON sp.grid = g.pk'
strsql += ' WHERE sp.mtime = today()'
geodata = Grid.objects.raw(strsql)
我想念什么?这是否超出了当前的geodjango序列化程序的范围?
答案 0 :(得分:0)
感谢相关列中显示的新链接,我了解了 我的假设有误,最后我找到了2个解决方案: 第一个创建专用的序列化器, 第二个使用sqlview作为模型。
A)创建一个专用的序列化程序,重新定义get_properties方法 为他们提供所需的措施:
from rest_framework_gis.serializers import GeoFeatureModelSerializer
from django.db import connection
def dictfetchall(cursor):
"""
When using a django.db.connection for raw sql,
returns all rows from a cursor as a dict
"""
columns = [col[0] for col in cursor.description]
return [
dict(zip(columns, row))
for row in cursor.fetchall()
]
class SpDataSerializer(GeoFeatureModelSerializer):
"""
Geojson Serializer for SpData
"""
def get_properties(self, instance, fields):
"""
Retrieve the measures linked to each grid point
"""
strsql ='SELECT sp.measure '
strsql += ' FROM SpData AS sp'
strsql += ' WHERE sp.grid_id = %s'
strsql += ' AND sp.mtime = today()'
with connection.cursor() as cursor:
cursor.execute(strsql, [instance.id])
properties = dictfetchall(cursor)
return properties[0]
class Meta:
model = Grid
geo_field = "geom"
fields = ("id", "elevation")
然后使用它来生成geojson的视图:
from rest_framework.generics import ListAPIView
class SpDataView(ListAPIView):
serializer_class = SpatialWalSerializer
def get_queryset(self):
# get the grid
queryset = Grid.objects.all()
return queryset
此优雅解决方案的局限性在于完成的查询数量 (对于在Grid模型中选择的每个几何图形一个),因此要花费时间。
B)为了获得更高的性能,我已经实现了GridView解决方案 (请参阅我的第一个问题),但将其应用于基于数据库VIEW的模型 被https://blog.rescale.com/using-database-views-in-django-orm/感染:
BEGIN
;
DROP VIEW IF EXISTS app_viewspdata
;
CREATE OR REPLACE VIEW app_viewspdata AS
SELECT sp.id
, g.geom
, g.elevation
, sp.mtime
, sp.measure
FROM app_spdata AS sp
INNER JOIN app_grid AS g
ON g.id = sp.grid_id
;
COMMIT
;
然后我创建了一个新模型:
class ViewSpData(geomodels.Model):
geom = geomodels.PointField(srid=4326, unique=True)
elevation = geomodels.FloatField(blank=True, null=True)
mtime = models.DateTimeField()
measure = models.DecimalField(
max_digits=6,
decimal_places=1,
blank=True,
null=True,
)
class Meta:
managed = False
db_table = 'app_viewspdata'
此模型可用于生成像这样的geojson:
from django.http import HttpResponse
from django.core.serializers import serialize
from rest_framework.views import APIView
from .models import ViewSpData
class ViewSpDataView(APIView):
def get(self, request):
result = serialize(
"geojson",
ViewSpData.objects.filter(mtime=today()),
geometry_field="geom",
srid=4326,
fields=(
"measure",
"elevation",
),
)
return HttpResponse(result)
就是这样。