Укажите поля связанной модели в поле сериализатора Django GeoJSON. - PullRequest
2 голосов
/ 13 мая 2019

Я пытаюсь построить точки на карте с помощью geojson serializer . Для этой функции у меня есть две модели с именами Activity и ClusterA.

Действие - это модель, в которой хранятся данные для некоторых действий, определенных в проекте. Это действие содержит поле PointField с именем location. Это моя Activity модель:

class Activity(models.Model):
    name = models.CharField(max_length=200)
    description = models.CharField(max_length=500)
    target_number = models.IntegerField(null=True, blank=True)
    target_unit = models.CharField(max_length=200, null=True, blank=True)
    beneficiary_level = models.BooleanField(default=True)
    weight = models.FloatField(default=0)
    location = PointField(geography=True, srid=4326, blank=True, null=True)

    def __str__(self):
        return self.name

    @property
    def latitude(self):
        if self.location:
            return self.location.y

    @property
    def longitude(self):
        if self.location:
            return self.location.x

Аналогично, деятельность может принадлежать кластеру. Эти данные хранятся в модели ClusterA (Cluster Activity). ClusterA относится к действиям, характерным для кластера.

Модель кластера

class Cluster(models.Model):
    name = models.CharField(max_length=200)
    ward = models.CharField(max_length=200)

    def __str__(self):
        return self.name

Модель ClusterA

class ClusterA(models.Model):
    activity = models.ForeignKey('Activity', related_name='clustera')
    target_number = models.IntegerField(null=True, blank=True, default=0)
    target_unit = models.CharField(max_length=200, null=True, blank=True, default='')
    time_interval = models.ForeignKey(ProjectTimeInterval, related_name='cainterval', null=True, blank=True)
    target_completed = models.IntegerField(null=True, blank=True, default=0)
    interval_updated = models.BooleanField(default=False)
    target_updated = models.BooleanField(default=False)
    location = PointField(geography=True, srid=4326, blank=True, null=True)

    def __str__(self):
        return self.name

    @property
    def latitude(self):
        if self.location:
            return self.location.y

    @property
    def longitude(self):
        if self.location:
            return self.location.x

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if not self.id:
            if not self.activity.beneficiary_level:
                self.target_unit = self.activity.target_unit
            self.time_interval = self.activity.time_interval
        return super(ClusterA, self).save()

Теперь я использую функцию, которая возвращает данные геойсона для действий кластера как:

def get_map_data(request):
    ca = ClusterA.objects.all()
    data = serialize(
        'geojson',
        ca,
        geometry_field='location',
        fields = ('activity', 'location', )
    )
    print(data)
    return HttpResponse(data)

Вывод, который я получаю:

{"type": "FeatureCollection", "crs": {"type": "name", "properties": {"name": "EPSG:4326"}}, "features": [{"geometry": {"type": "Point", "coordinates": [85.336775, 27.542718]}, "type": "Feature", "properties": {"activity": 27}}, {"geometry": null, "type": "Feature", "properties": {"activity": 19}}, {"geometry": {"type": "Point", "coordinates": [85.336776, 27.735227]}, "type": "Feature", "properties": {"activity": 26}}]}

Поле активность дает идентификатор для действие . Но мне требуется имя активности , чтобы я мог отобразить имя активности во всплывающем окне маркера, нанесенного на карту .

Вот как я пытаюсь отобразить название активности во всплывающем окне маркера:

onEachFeature: function (feature, layer) {
   layer.bindPopup(feature.properties.name);
} 

Всплывающее окно отображает другие данные, если я передаю ему поля локальной модели.

Я пытался использовать:

fields = ('activity__name', 'location', )

В функции get_map_data , но она не отображает поле в выводе на печать как:

{
  "type": "FeatureCollection",
  "crs": {
    "type": "name",
    "properties": {
      "name": "EPSG:4326"
    }
  },
  "features": [
    {
      "geometry": {
        "type": "Point",
        "coordinates": [
          85.336775,
          27.542718
        ]
      },
      "type": "Feature",
      "properties": {

      }
    },
    {
      "geometry": null,
      "type": "Feature",
      "properties": {

      }
    },
    {
      "geometry": {
        "type": "Point",
        "coordinates": [
          85.336776,
          27.735227
        ]
      },
      "type": "Feature",
      "properties": {

      }
    }
  ]
}

Как видите, в properties вышеприведенных выходных данных нет полей.

Мне нужна помощь, чтобы иметь возможность получить поле имени модели деятельности, а не идентификатор.

Я использую Django 1.8.

Edit: Выходные данные печати (около dict ) после добавления select_related

{'activity_id': 44, 
'target_unit': u'Check', 
'_state': <django.db.models.base.ModelState object at 0x7f57e19c8150>, 
'target_completed': 0, 
'cag_id': 35, 
'target_updated': False, 
'_activity_cache': <Activity: Test>, 
'location': <Point object at 0x7f57e19391c0>, 
'time_interval_id': 84, 
'target_number': 12, 
'interval_updated': False, 
'id': 72}

Ошибка трассировки для настраиваемого сериализатора

ERROR 2019-06-12 14:40:15,638 base 27641 140154705491712 Internal Server Error: /core/get-map-data/
Traceback (most recent call last):
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/sanip/naxa/mes-core/onadata/apps/core/views.py", line 366, in get_map_data
    data = serializers.serialize(ca, geometry_field='location', fields=('activity__name', 'location',))
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/base.py", line 69, in serialize
    self.end_object(obj)
  File "/home/sanip/naxa/mes-core/onadata/apps/core/serializers.py", line 170, in end_object
    super(CustomSerializer, self).end_object(obj)
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/json.py", line 61, in end_object
    cls=DjangoJSONEncoder, **self.json_kwargs)
  File "/usr/lib/python2.7/json/__init__.py", line 189, in dump
    for chunk in iterable:
  File "/usr/lib/python2.7/json/encoder.py", line 434, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 442, in _iterencode
    o = _default(o)
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/json.py", line 115, in default
    return super(DjangoJSONEncoder, self).default(o)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Point object at 0x7f783f0c92e0> is not JSON serializable
Internal Server Error: /core/get-map-data/
Traceback (most recent call last):
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/sanip/naxa/mes-core/onadata/apps/core/views.py", line 366, in get_map_data
    data = serializers.serialize(ca, geometry_field='location', fields=('activity__name', 'location',))
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/base.py", line 69, in serialize
    self.end_object(obj)
  File "/home/sanip/naxa/mes-core/onadata/apps/core/serializers.py", line 170, in end_object
    super(CustomSerializer, self).end_object(obj)
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/json.py", line 61, in end_object
    cls=DjangoJSONEncoder, **self.json_kwargs)
  File "/usr/lib/python2.7/json/__init__.py", line 189, in dump
    for chunk in iterable:
  File "/usr/lib/python2.7/json/encoder.py", line 434, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 442, in _iterencode
    o = _default(o)
  File "/home/sanip/.virtualenvs/mes/lib/python2.7/site-packages/django/core/serializers/json.py", line 115, in default
    return super(DjangoJSONEncoder, self).default(o)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Point object at 0x7f783f0c92e0> is not JSON serializable

Ответы [ 2 ]

1 голос
/ 12 июня 2019

По умолчанию, django serializer не предоставляет значения ForeignKey.Таким образом, вы можете переопределить поля сериализатора geojson .Например:

from django.contrib.gis.serializers.geojson import Serializer 

class CustomSerializer(Serializer):

    def end_object(self, obj):
        for field in self.selected_fields:
            if field == 'pk':
                continue
            elif field in self._current.keys():
                continue
            else:
                try:
                    if '__' in field:
                        fields = field.split('__')
                        value = obj
                        for f in fields:
                            value = getattr(value, f)
                        if value != obj:
                            self._current[field] = value

                except AttributeError:
                    pass
        super(CustomSerializer, self).end_object(obj)

Использование:

serializers = CustomSerializer()
ca = ClusterA.objects.all()
data = serializers.serialize(ca, geometry_field='location', fields=('activity__name', 'location', ))
0 голосов
/ 07 июня 2019

Я считаю, что все, что вам нужно сделать, это JOIN таблица активности с использованием свойства .select_related():

def get_map_data(request):
    ca = ClusterA.objects.all().select_related()
    data = serialize(
        'geojson',
        ca,
        geometry_field='location',
        fields = ('activity', 'location', )
    )

Дайте мне знать, что произойдет, когда вы попробуете это.

Если это не сработает, попробуйте:

def get_map_data(request):
    ca = ClusterA.objects.all().select_related('activity__name')
    data = serialize(
        'geojson',
        ca,
        geometry_field='location',
        fields = ('activity', 'location', )
    )
...