How to write to Django FileField from a tempfile?
I am processing an image within a Django app. I used rasterio to process the geospatial image. I want to save the output directly to a FileField in a Model. I used a tempfile to write the output from rasterio, and used the method Model.FileField.save
to hopefully write it with a reference to my Model instance.
I have a simple model:
class MaskedLayer(models.Model):
name = models.CharField(max_length=250, blank=True)
file = models.FileField(
upload_to='masked',
null=True,
max_length=500)
In my tasks, however this is an example:
from celery import shared_task
import rasterio
import tempfile
from app.models import MaskedLayer
@shared_task
def process_image():
mask_layer_name = 'processed_image.tif'
masked_layer = MaskedLayer.objects.create()
with rasterio.open('example.tif') as dataset: # only example of reading/processing of image
out_image = dataset.read()
with tempfile.NamedTemporaryFile() as tmpfile:
tmpfile.write(out_image)
with rasterio.open(tmpfile.name) as dataset:
masked_layer.file.save(mask_layer_name, File(dataset))
pass
I get this response. I am not sure of the error. Feel free to use the example file.
Fatal Python error: Segmentation fault
Current thread 0x00007f453b463740 (most recent call first): File "/usr/local/lib/python3.11/site-packages/django/views/debug.py", line 232 in get_traceback_frame_variables File "/usr/local/lib/python3.11/site-packages/django/views/debug.py", line 544 in get_exception_traceback_frames File "/usr/local/lib/python3.11/site-packages/django/views/debug.py", line 490 in get_traceback_frames File "/usr/local/lib/python3.11/site-packages/django/views/debug.py", line 320 in get_traceback_data File "/usr/local/lib/python3.11/site-packages/django/views/debug.py", line 403 in get_traceback_text File "/usr/local/lib/python3.11/site-packages/django/utils/log.py", line 125 in emit File "/usr/local/lib/python3.11/logging/init.py", line 978 in handle File "/usr/local/lib/python3.11/logging/init.py", line 1706 in callHandlers File "/usr/local/lib/python3.11/logging/init.py", line 1644 in handle File "/usr/local/lib/python3.11/logging/init.py", line 1634 in _log
File "/usr/local/lib/python3.11/logging/init.py", line 1518 in error File "/usr/local/lib/python3.11/site-packages/django/utils/log.py", line 241 in log_response File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 143 in response_for_exception File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 57 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/utils/deprecation.py", line 136 in call File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55 in inner File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 140 in get_response File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 258 in get_response File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 153 in call File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 805 in request File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 238 in request File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 286 in request File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 541 in generic File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 234 in generic File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 210 in post File "/usr/local/lib/python3.11/site-packages/rest_framework/test.py", line 296 in post File "/usr/src/app/data_management/tests/test_data_management.py", line 18 in test_solar_pot File "/usr/local/lib/python3.11/unittest/case.py", line 579 in _callTestMethod File "/usr/local/lib/python3.11/unittest/case.py", line 623 in run File "/usr/local/lib/python3.11/unittest/case.py", line 678 in call
File "/usr/local/lib/python3.11/site-packages/django/test/testcases.py", line 416 in _setup_and_call File "/usr/local/lib/python3.11/site-packages/django/test/testcases.py", line 381 in call File "/usr/local/lib/python3.11/unittest/suite.py", line 122 in run File "/usr/local/lib/python3.11/unittest/suite.py", line 84 in call
File "/usr/local/lib/python3.11/unittest/runner.py", line 217 in run
File "/usr/local/lib/python3.11/site-packages/django/test/runner.py", line 980 in run_suite File "/usr/local/lib/python3.11/site-packages/django/test/runner.py", line 1058 in run_tests File "/usr/local/lib/python3.11/site-packages/django/core/management/commands/test.py", line 68 in handle File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 448 in execute File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 402 in run_from_argv File "/usr/local/lib/python3.11/site-packages/django/core/management/commands/test.py", line 24 in run_from_argv File "/usr/local/lib/python3.11/site-packages/django/core/management/init.py", line 440 in execute File "/usr/local/lib/python3.11/site-packages/django/core/management/init.py", line 446 in execute_from_command_line File "/usr/src/app/manage.py", line 18 in main File "/usr/src/app/manage.py", line 22 inExtension modules: psycopg2._psycopg, numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator, rasterio._version, rasterio._err, rasterio._filepath, rasterio._env, rasterio._transform, rasterio._base, rasterio.crs, rasterio._features, rasterio._warp, rasterio._io, fiona._err, fiona._geometry, fiona._shim, fiona._env, fiona.schema, fiona.ogrext, fiona._crs (total: 31)
I am by far not familiar with rasterio
and celery
but let me show you my working implementation as guidance:
import io
from django.core.files.images import ImageFile
def _upload_location(instance, filename):
return f'/some/path/{filename}'
class MyModel(models.Model):
model_image_field = models.ImageField(null=True, blank=True, upload_to=_upload_location, editable=False)
def save_structure_img(self):
tmp_img = io.BytesIO() # create buffer
structure_img = self.create_structure_img() # create img
structure_img.save(tmp_img, 'PNG') # utilize save method of your image to save it to the buffer
name = "your_wanted_filename" # create a name
self.model_image_field.save(f'{name}.png', ImageFile(tmp_img)) # save buffer to model_image field
I know, I edited out the creation of structure_img
but that should not matter, because it is specific to my project.
Let me try to translate this to your usecase:
import io
from django.core.files.images import ImageFile
@shared_task
def process_image():
mask_layer_name = 'processed_image.tif'
masked_layer = MaskedLayer.objects.create()
with rasterio.open('example.tif') as dataset: # only example of reading/processing of image
out_image = dataset.read()
tmp_img = io.BytesIO() # create buffer
out_image.save(tmp_img, 'PNG')
# i hope this is the right place where out_image has a `.save` method.
name = "your_wanted_filename"
masked_layer.field.save(f'{name}.png', ImageFile(tmp_img))
pass
Also I admit that I have no clue what your proposed error is trying to tell me. But I feel like the database is complaining about what you are trying to insert. If you so search for an answer how to fix exactly that error, my answer is not what you are looking for. It is more of an alternative approach to the same solution.