Search code examples
pythondjangogeodjango

'PosixPath' object is not subscriptable[GeoDjango BUG]


Using ogrinfo -so I've found the structure of the shapefile and based on this structure I've created a model:

from django.contrib.gis.db import models

class Villages(models.Model):
.
.
.

After that I've created the load.py as mentioned here inside the same directory of models.py:

enter image description here

from pathlib import Path
from django.contrib.gis.utils import LayerMapping
from .models import Villages

villages_mapping = {
.
.
.
}

villages = Path(__file__).resolve().parent / 'gis' / 'villages.shp'

def run(verbose=True):
    lm = LayerMapping(Villages, villages, villages_mapping, transform=False)
    lm.save(strict=True, verbose=verbose)

Then, I try to use load.py:

python3 manage.py shell > from geodata import load > load.run()

But I see this strange error:

Traceback (most recent call last):   File "<console>", line 1, in
<module>   File
"/home/maxdragonheart/DEV_FOLDER/Django/Enographiae/enographiae_dev/enographiae/geodata/load.py", line 32, in run
    lm = LayerMapping(Villages, villages, villages_mapping, transform=False)   File
"/home/maxdragonheart/DEV_FOLDER/Django/Enographiae/enographiae_dev/devenv/lib/python3.7/site-packages/django/contrib/gis/utils/layermapping.py", line 99, in __init__
    self.layer = self.ds[layer] TypeError: 'PosixPath' object is not subscriptable

EDIT:

Maybe the problem is inside layermapping.py. I've replicated the tutorial using the original code and datas and I see this:

  File "<console>", line 1, in <module>
  File "/home/maxdragonheart/DEV_FOLDER/Django/Singole APP/GeoDjango/webgis/tutorialgeodjango/load.py", line 23, in run
    lm = LayerMapping(WorldBorder, world_shp, world_mapping, transform=False)
  File "/home/maxdragonheart/DEV_FOLDER/Django/Singole APP/GeoDjango/devenv/lib/python3.7/site-packages/django/contrib/gis/utils/layermapping.py", line 100, in __init__
    self.layer = self.ds[layer]
TypeError: 'PosixPath' object is not subscriptable

EDIT 2:

Using the code from Django 2.2 I've no problem to upload datas. How I can report this bug?

EDIT 3:

The problem is also in Django 3.1.3


Solution

  • Django documentation for LayerMapping API is not 100 % clear on a data type for path, but if you check the source code, you'll see it expects either a string or DataSource instance.

    Below is the relevant code from the source code.

    def __init__(self, model, data, mapping, layer=0,
                 source_srs=None, encoding='utf-8',
                 transaction_mode='commit_on_success',
                 transform=True, unique=None, using=None):
        """
        A LayerMapping object is initialized using the given Model (not an instance),
        a DataSource (or string path to an OGR-supported data file), and a mapping
        dictionary.  See the module level docstring for more details and keyword
        argument usage.
        """
        # Getting the DataSource and the associated Layer.
        if isinstance(data, str):
            self.ds = DataSource(data, encoding=encoding)
        else:
            self.ds = data
        self.layer = self.ds[layer]
    

    The comment mentions string path and later in code there is a check if data argument is a string (path in this case) in initializes DataSource instance with it.

    Simply changing Path to str will fix your problem.

    lm = LayerMapping(Villages, str(villages), villages_mapping, transform=False)