How do I read a request.FILES into DataSource in Geodjango

620 Views Asked by At

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.

3

There are 3 best solutions below

3
schillingt On

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.

1
kiro On

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

0
Miquel Strippoli On

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.