2

I'm using vectorformats to display GeoDjango data on my map, following this resource. I have this in my views.py file :

def geojsonFeed(request):
    querySet = WorldBorder.objects.filter()
    djf = Django.Django(geodjango="mpoly", properties=['name', 'iso3'])
    geoj = GeoJSON.GeoJSON()
    s = geoj.encode(djf.decode(querySet))
    return HttpResponse(s)

But the response looks like this

["type", "features", "crs"]

Can anyone help me identify what's wrong with my code?

Update : Added WorldBorder Model

class WorldBorder(models.Model):
    # Regular Django fields corresponding to the attributes in the
    # world borders shapefile.
    name = models.CharField(max_length=50)
    area = models.IntegerField()
    pop2005 = models.IntegerField('Population 2005')
    fips = models.CharField('FIPS Code', max_length=2)
    iso2 = models.CharField('2 Digit ISO', max_length=2)
    iso3 = models.CharField('3 Digit ISO', max_length=3)
    un = models.IntegerField('United Nations Code')
    region = models.IntegerField('Region Code')
    subregion = models.IntegerField('Sub-Region Code')
    lon = models.FloatField()
    lat = models.FloatField()

    # GeoDjango-specific: a geometry field (MultiPolygonField)
    mpoly = models.MultiPolygonField()

    # Returns the string representation of the model.
    def __str__(self):
        return self.name

I'm using Django 2.1.7

Update 2 :

>>> print(querySet)

<QuerySet [<WorldBorder: Antigua and Barbuda>, <WorldBorder: Algeria>, <WorldBorder: Azerbaijan>, <WorldBorder: Albania>, <WorldBorder: Anguilla>, <WorldBorder: Armenia>, <WorldBorder: Angola>, <WorldBorder: American Samoa>, <WorldBorder: Argentina>, <WorldBorder: Australia>, <WorldBorder: Andorra>, <WorldBorder: Gibraltar>, <WorldBorder: Bahrain>, <WorldBorder: Barbados>, <WorldBorder: Bermuda>, <WorldBorder: Bahamas>, <WorldBorder: Bangladesh>, <WorldBorder: Brunei Darussalam>, <WorldBorder: Canada>, <WorldBorder: Cambodia>, '...(remaining elements truncated)...']>
sk001
  • 540
  • 5
  • 25
  • Is there a reason to use a module (`vectorformats`) that seems to be abandoned and very very old (the PyPi page: https://pypi.org/project/vectorformats/ tells us that this package is from 2009 and stuck in version 0.1)? What is the Django version you are using for your project? Also, can you share the `WorldBorder` model in your question? – John Moutafis Apr 11 '19 at 08:21
  • 1
    Thank you @JohnMoutafis. Though vectorformats is abandoned, I've reused [the poject for recent Python 3 versions](https://github.com/koffisani/vectorformats) and used it in my project as a Git submodule. Kindly look at the updated version of the question. – sk001 Apr 11 '19 at 12:18

1 Answers1

1

EDIT After confirmation of non-empty queryset:

I found the issue and it is related to the core code of the vectorformats module.

Specifically, inside GeoJSON.encode on this specific line:

if to_string:
    result = json_dumps(list(result_data))

the list() is causing the problem.

Let's recreate the issue with a minimal example:

>>> import json
>>> test = {'a': 5, 'b': [1, 2, 3], 'c': {'e': 2, 'f': 5}}
>>> list(test)
['a', 'b', 'c']

Here we see the exact same behavior as the one in the question. Let's take it a bit further:

>>> json.dumps(list(test))
'["a", "b", "c"]'

But without the list():

>>> json.dumps(test)
'{"a": 5, "b": [1, 2, 3], "c": {"e": 2, "f": 5}}'

Therefore there are 2 possible solutions around this problem:

  1. Change the vectorformat code removing the list() call.
  2. Call the encode method with to_string=False and "jsonify" the resulting dictionary yourself as follows:

    import json
    
    def geojsonFeed(request):
        queryset = WorldBorder.objects.all()
        djf = Django.Django(geodjango="mpoly", properties=['name', 'iso3'])
        geoj = GeoJSON.GeoJSON()
        s = geoj.encode(djf.decode(queryset), to_string=False)
        return HttpResponse(json.dumps(s))
    

Well from a quick study at your module, it seems to work as intended, so that is not the reason.
Having a look at the GeoJSON.encode() method:

def encode(self, features, to_string=True, **kwargs):
    """
    Encode a list of features to a JSON object or string.
    to_string determines whethr it should convert the result to
    a string or leave it as an object to be encoded later
    """
    results = []
    result_data = None
    for feature in features:
        data = self.encode_feature(feature)
        for key,value in data['properties'].items():
            if value and isinstance(value, str): 
                data['properties'][key] = str(value)
        results.append(data)

   result_data = {
                   'type':'FeatureCollection',
                   'features': results,
                   'crs': self.crs
                  }

   if to_string:
        result = json_dumps(list(result_data))
   else:
        result = result_data
   return result

The result_data has the structure ["type", "features", "crs"] and it is transformed to a json list because you have the to_string argument by default True.

The only reason for your problem I can imagine is that the querySet = WorldBorder.objects.filter() query is empty.

By the way, by using filter() with no arguments, you have a similar result to an all() query.

John Moutafis
  • 18,296
  • 5
  • 55
  • 96
  • 1
    Thank you, @John, for your help. `print(querySet)` returns this : `print(querySet) , , , , , , , , , , '...(remaining elements truncated)...']>`. I updated the question. – sk001 Apr 11 '19 at 22:57
  • 1
    @sk001 I found it :D. I added an edit to my answer that explains and fixes the problem! – John Moutafis Apr 12 '19 at 08:16
  • 1
    Thank you, @John. It's ok now. Thank you. – sk001 Apr 12 '19 at 08:26