Django:如何从相关模型中检索所有属性以进行 GeoJSON 序列化?

Django: How to retrieve all attributes from related models for GeoJSON serialization?

我有两个模型 SiteCell,每个站点都有多个 Cell。

from django.db import models
from django.contrib.gis.db.models import PointField

class SiteManager(models.Model):
    def get_by_natural_key(self, name, state_code, location):
         return self.get(name=name, state_code=state_code, location=location)

class Site(models.Model):
    name = models.CharField(max_length=10)
    state_code = models.PositiveSmallIntegerField()
    location = PointField()

    objects = SiteManager()

    class Meta:
         unique_together = [['name', 'state_code', 'location']]

    def natural_key(self):
         return (self.name, self.state_code, self.location)

class Cell(models.Model):
    tech = models.CharField(max_length=5)
    azimuth = models.IntegerField()
    sector_id = models.CharField(max_length=10)
    frequency_band = models.CharField(max_length=15)
    power = models.DecimalField(decimal_places=2, max_digits=4)
    site = models.ForeignKey(Site, on_delete=models.CASCADE)

    def natural_key(self):
         return (self.tech, self.azimuth,) + self.site.natural_key()
    natural_key.dependencies = ['astmaps.site']

我想检索完整的 Cell 属性以及 Site 模型中的相关属性,对我来说 Serialize 结果 Cell 的,进入 GeoJson 数据,我可以轻松地 Serialize Site 模型,例如:

from django.core.serializers import serialize # GeoJSON Serializer

sites = Site.objects.all()
sitesData = serialize('geojson', sites, geometry_field='location',
    fields=('name', 'state_code'))

这给了我一个 GeoJson featureCollection object 像:

{
            "type":"FeatureCollection",
            "crs":{
            "type":"name",
            "properties":{
                "name":"EPSG:4326"
             }
        },
        "features":[
        {
            "type":"Feature",
            "properties": {
                "name":"02101",
                "state_code":2
             },
             "geometry":{
                "type":"Point",
                "coordinates":[
                   1.34944,
                   36.1586
                ]
             }
          }
       ]
    }

但是当涉及到Cell模型时,我总是无法从相关模型中成功获取几何字段null。 由于 Cell 模型有 Site 模型作为相关模型,我使用函数 select_related() 来获取相关属性:

cells = Cell.objects.select_related('site').all()
cellsData = serialize('geojson', cells, geometry_field='site_location', 
    fields=('azimuth', ...))

但是 GeoJson Serialize 函数无法从 cells QuerySet:

中识别 Site 模型属性
{
   "type":"FeatureCollection",
   "crs":{
      "type":"name",
      "properties":{
         "name":"EPSG:4326"
      }
   },
   "features":[
      {
         "type":"Feature",
         "properties":{
            "azimuth":340
         },
         "geometry":null
      },
      {
         "type":"Feature",
         "properties":{
            "azimuth":340
         },
         "geometry":null
      },
      {
         "type":"Feature",
         "properties":{
            "azimuth":240
         },
         "geometry":null
      }
   ]
}

我已经在数据库上直接测试了 Django ORM 等效返回的查询:

    cells = Cell.objects.select_related('site').all()
    >>> print(cells.query)
SELECT "app_cell"."id", "app_cell"."tech", "app_cell"."azimuth", "app_cell"."sector_id", "app_cell"."frequency_band", "app_cell"."power", "app_cell"."site_id", "app_cell"."id", "app_site"."name", "app_site"."state_code", "app_site"."location"::bytea FROM "app_cell" INNER JOIN "app_site" ON ("app_cell"."site_id" = "app_site"."id")

这给了我正确的结果(两个模型的所有属性或列):

我还使用了Natural Keys,这是外键和其他关系的序列化策略(正如我在文档中阅读并相应地更改了模型):

cellsData = serialize('geojson', cells, geometry_field='site_location', 
    fields=('azimuth', ...), use_natural_foreign_keys=True)

但同样的结果,Serialize 方法无法识别 Site 模型属性。

如何使用 GeoJSON Serializer 获取多个相关模型的所有属性以进行序列化?

我设法通过使用原始 sql 查询加上 PostGIS 扩展的 json_build_objectST_AsGeoJSON 得到了我想要的:

from django.db import connection
def sites_list(request):

cursor = connection.cursor()
cursor.execute("""select json_build_object(
    'type', 'FeatureCollection',
    'features', json_agg(ST_AsGeoJSON(t.*)::json)
    )
    from ( SELECT "app_cell"."id", "app_cell"."tech", "app_cell"."azimuth", "app_cell"."sector_id", 
                        "app_cell"."frequency_band", "app_cell"."power", "app_cell"."site_id", "app_site"."name" 
                        AS "site_name", "app_site"."state_code", "app_cell"."location"::bytea::geometry AS "site_location" 
                        FROM "app_cell" INNER JOIN "app_site" ON ("app_cell"."site_id" = "app_site"."id")
        ) as t(id, tech, azimuth, sector_id, frequency_band, power, site_id, site_name, state_code, geom);""")
geojson = cursor.fetchone()

return JsonResponse(geojson[0], safe=False)

我在 JavaScript 方面遇到了一些问题,使用时:

cursor.fetchall()
return JsonResponse(geojson, safe=False)

returned GeoJSON 对象被 [[]] 双括号包围,因为 cursor.fetchall() return a tuple, 所以,我'我们使用 cursor.fetchone() 获取仅由单个括号 [] 包围的 geoJSON 对象,并使用结果元组的索引 0 获取唯一的元组内容作为字符串,最后 JsonResponse函数将 return 结果作为 JSON 对象。