0

So, the goal is to create a webpage to load a .shp file into and get a summary of some calculations as a JsonResponse. I have prepared the calculations and everything and it works nicely when I add a manual path to the file in question. However, the goal is for someone else to be able to upload the data and get back the response so I can't hardcode my path.

The overall approach:

  • Read in a through forms.FileField() and request.FILES['file_name']. After this, I need to transfer this request.FILES object to DataSource in order to read it in. I would rather not upload the file on pc if possible but work directly from the memory.

forms.py

from django import forms
from django.core.files.storage import FileSystemStorage


class UploadFileForm(forms.Form):
    # title = forms.CharField(max_length=50)
    file = forms.FileField()

views.py

import json
import os

from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render

from django.template import loader
from django.contrib import messages
from django.views.generic import TemplateView
from django.http import JsonResponse

from django.conf import settings
from .forms import UploadFileForm
from . import models
from django.shortcuts import redirect
from gisapp.functions.functions import handle_uploaded_file, handle_uploaded_file_two
from django.contrib.gis.gdal import DataSource
from django.core.files.uploadedfile import UploadedFile, TemporaryUploadedFile
import geopandas as gpd
import fiona


def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            f = request.FILES['file']
            # geo2 = gpd.read_file(f)
            # print(geo2)
            # f_path = os.path.abspath(os.path.join(os.path.dirname(f), f))

            # f_path = TemporaryUploadedFile.temporary_file_path(UploadedFile(f))
            # print(f_path)
            # f_path = f.temporary_file_path()
            # new_path =  request.FILES['file'].temporary_file_path
            # print(f'This is file path: {f_path}')
            # print(f'This is file path: {new_path}')
            # data = DataSource(f'gisapp/data/{f}') -- given an absolute path it works great
            data = DataSource(f) -- constantly failing
            # data = DataSource(new_path)
            # print(f'This is file path: {f_path}')
            layer = data[0]
            if layer.geom_type.name == "Polygon" or layer.geom_type.name == "LineString":
                handle_uploaded_file(request.FILES['file'])
            elif layer.geom_type.name == "Point":
                handle_uploaded_file_two(request.FILES['file'])

            return JsonResponse({"Count": f"{handle_uploaded_file_two(request.FILES['file'])[0]}", "Bounding Box": f"{handle_uploaded_file_two(request.FILES['file'])[1]}"})
            
            # return JsonResponse({"Count": f"{handle_uploaded_file(request.FILES['file'])[0]}", "Minimum": f"{handle_uploaded_file(request.FILES['file'])[1]}", "Maximum": f"{handle_uploaded_file(request.FILES['file'])[1]}"})
            # instance = models.GeometryUpload(file_field=request.FILES['file'])
            # instance.save()
            # # return HttpResponseRedirect('/success/')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

Error I get:

django.contrib.gis.gdal.error.GDALException: Invalid data source input type: <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>

Now as you can see from the upload_file() in views.py, I tried a multitude of operations and when I add an absolute path, it works, but besides that I can't seem to upload the file to DataSource so that I can use it in my later analysis.

mkw
  • 123
  • 2
  • 10

3 Answers3

0

Looking at how Django handles this, it doesn't appear possible to work off of an in memory file. The path to the file is passed to the C API for OGR which then handles opening the file and reading it in.

schillingt
  • 13,493
  • 2
  • 32
  • 34
  • Thanks @schillingt, that was what I was afraid of. But there must be a way to do this. Any idea? Another issue with shapefiles is that they consist of minimum 3 separate files. – mkw Jun 30 '21 at 19:56
  • Could you have the user upload all three files, then process them as GDAL expects? – schillingt Jun 30 '21 at 20:01
  • No, that is not an option. But still, even in that case, I still have an issue from above as I also get an error when I try importing GeoJSON. – mkw Jun 30 '21 at 20:10
0

A possible solution that I am trying myself is to have the user zip their shape files (.shp,.shx.,dbf etc.) beforehand. The zip file is then uploaded and unzipped. The shp files can then be read. Hope this helps

kiro
  • 1
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 14 '22 at 09:09
0

I face the same problem and my workaround was to save the file upload by the user in a temporary folder, then pass the absolute path of the temporary file to my DataSource. After finish all my process with the temporary file, I deleted.

The downside of this method is the execution time, is slow.