# Where is the image file?

**URL:** <https://forum.djangoproject.com/t/where-is-the-image-file/22978>\
**Category:** Using the ORM\
**Created:** [August 11, 2023, 11:51am UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978 "2023-08-11T11:51:01Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 11, 2023, 11:51am UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/1 "2023-08-11T11:51:01Z")

</div>

Hi all,

I have this model:

```auto
class Product(VASTObject_NameUserGroupUnique):
    image = models.ImageField(upload_to='product_images/', default=None, null=True, blank=True)
    image_resource_id = models.IntegerField(default=None, null=True, blank=True)
    image_uriref = models.URLField(max_length=512, null=True, blank=True)

    def save(self, *args, **kwargs):
        logger.info(f"Product: save():", *args, **kwargs)
        if self.image:
            path = self.image.path
            url = self.image.url
            logger.info(f"Product: save(): Image url: {url} (exists: {os.path.exists(path)})")
            logger.info(f"Product: save(): Image path: {path} (exists: {os.path.exists(path)})")
            if not os.path.exists(path):
                # Image not found at this path. Look into product_images...
                head_tail = os.path.split(path)
                path = os.path.join(head_tail[0], 'product_images', head_tail[1])
                logger.info(f"Product: save(): Trying new Image path: {path} (exists: {os.path.exists(path)})")
                if os.path.exists(path):
                    head_tail = os.path.split(url)
                    url = os.path.join(head_tail[0], 'product_images', head_tail[1])
                    logger.info(f"Product: save(): Trying new Image url: {url} (exists: {os.path.exists(path)})")
        super().save(*args, **kwargs)

```

When I create a new product, it seems to work. But when changing the image on an existing object, I get this output:

```auto
Product: save():
Product: save(): Image url: /media/20230520_174836.jpg (exists: False)
Product: save(): Image path: /backend/media/20230520_174836.jpg (exists: False)
Product: save(): Trying new Image path: /backend/media/product_images/20230520_174836.jpg (exists: False)

```

The fields in image seem correct, but the actual file is not in the media folder.  
Where is my image file?  
(I need o upload it into a digital assets management system).

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 11, 2023, 12:14pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/2 "2023-08-11T12:14:39Z")

</div>

There are a couple of points to keep in mind when working with uploaded files:

- Files are stored in a physical path based on `MEDIA_ROOT`, but accessed through the logical path based on `MEDIA_URL`. The two do _not_ need to have any relationship to each other.

- Files may have their name changed when being saved. Django will not overwrite one uploaded file with another. It’s up to you to keep track of either the `pk` of the entity referencing that file or saving the original name used for the upload.

Also, the file is committed to the storage during the `pre_save` step of the model being saved. Since you’re trying to do this in the models `save` method, you’re (possibly) looking for the file before it has been written to `MEDIA_ROOT`.

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 11, 2023, 12:27pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/3 "2023-08-11T12:27:01Z")

</div>

And how can I add code to the pre\_save step? It seems it is a signal?

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 11, 2023, 12:34pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/4 "2023-08-11T12:34:56Z")

</div>

If I save the image myself, upload the image into the DAM, and then delete the image, before calling super().save(), seems to work.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 11, 2023, 12:36pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/5 "2023-08-11T12:36:04Z")

</div>

No, from what I can see in the code (I’m _not_ sure of this), the “pre\_save” step in the save process is just the name given to functions that are called for each field while doing the save. It’s not tied to the signals processes.

You can call your logging code _after_ the call to `super().save(...)` - the data should be there.

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 14, 2023, 7:45am UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/6 "2023-08-14T07:45:25Z")

</div>

Well, because I need the image before save(), what I did is to save a temporary image, and remove it:

```auto
    def create_image_resource(self):
        if self.image:
            path = self.image.path
            url = self.image.url
            logger.info(f"{self. __class__. __name__ }: create_image_resource(): Image url: {url} (exists: {os.path.exists(path)})")
            logger.info(f"{self. __class__. __name__ }: create_image_resource(): Image path: {path} (exists: {os.path.exists(path)})")
            delete_tmp_image = False
            if not os.path.exists(path):
                ## Try to save the image in a temporary file...
                path = self.image.path
                logger.info(f"{self. __class__. __name__ }: create_image_resource(): Saving Temp Image: {path}")
                # Open the image using PIL
                img = Image.open(self.image)
                img.save(path)
                delete_tmp_image = True
            if os.path.exists(path):
                dam = DAMStoreVAST()
                logger.info(f"{self. __class__. __name__ }: create_image_resource(): Creating Image resource...")
                self.image_resource_id = dam.create_resource(self.image.url, {
                    'description': f'{type(self). __name__ }: {self.name}',
                })
                logger.info(f"{self. __class__. __name__ }: create_image_resource(): Image Resource: {self.image_resource_id}")
                json_data = dam.get_resource(self.image_resource_id)
                self.image_uriref = dam.get_size(json_data)['url']
                logger.info(f"{self. __class__. __name__ }: create_image_resource(): Image url: {self.image_uriref}")
                del dam
                if delete_tmp_image:
                    logger.info(f"{self. __class__. __name__ }: create_image_resource(): Deleting Temp Image: {path}")
                    os.remove(path)
            else:
                self.image_resource_id = None
                self.image_uriref = None

```

Using this temporary image I can push it to an external DAM, get the URL in the DAM, and save it in the model.

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 22, 2023, 6:49pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/7 "2023-08-22T18:49:03Z")

</div>

Ok, it seems images were easy, saving temporarily the files is more complicated.

```auto
document = models.FileField(upload_to='stimulus_documents/', default=None, null=True, blank=True)

    def create_document_resource(self):
        if self.document:
            path = self.document.path
            url = self.document.url
            logger.info(f"{self. __class__. __name__ }: create_document_resource(): Document url: {url} (exists: {os.path.exists(path)})")
            logger.info(f"{self. __class__. __name__ }: create_document_resource(): Document path: {path} (exists: {os.path.exists(path)})")
            delete_tmp_document = False
            if not os.path.exists(path):
                ## Try to save the document in a temporary file...
                path = self.document.path
                logger.info(f"{self. __class__. __name__ }: create_document_resource(): Saving Temp Document: {path}")
                # Save the file on disk...
                with open(path, 'wb') as fd:
                    with self.document.open('rb') as file:
                        fd.write(file.read())
                delete_tmp_document = True

```

The file is saved, I can upload it to the digital assets management, but django cannot save any more the instance to the database:

```auto
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1695, in pre_save_val
    return field.pre_save(obj, add=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/files.py", line 317, in pre_save
    file.save(file.name, file.file, save=False)
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/files.py", line 93, in save
    self.name = self.storage.save(name, content, max_length=self.field.max_length)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/files/storage/base.py", line 38, in save
    name = self._save(name, content)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/files/storage/filesystem.py", line 101, in _save
    file_move_safe(content.temporary_file_path(), full_path)
  File "/usr/local/lib/python3.11/site-packages/django/core/files/move.py", line 61, in file_move_safe
    with open(old_file_name, "rb") as old_file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmp9kkwzab5.upload.pdf'

```

So, the question is, how can I save a temporary copy of a FileField, before save() is called?

---

<div class="post-metadata">

**Author:** ![dennisvd](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/dennisvd/32/1441_2.png) [@dennisvd](https://forum.djangoproject.com/u/dennisvd)\
**Post date:** [August 22, 2023, 9:16pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/8 "2023-08-22T21:16:27Z")

</div>

It is not entirely clear to me as to why you need the file pre-save. From what I read I deduce that you want to save the file in a DAM instead of the media folder of your Django app.

Options:

- don’t use an image field in the model but a url field for example and handle the upload of the image to the DAM yourself
- perhaps the DAM can be used as the Django media location. For example you can have an AWS S3 bucket as your media files location
- you can also extend the middleware layer in Django to handle the upload to your DAM perhaps by creating your own custom field type

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 23, 2023, 9:09am UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/9 "2023-08-23T09:09:09Z")

</div>

I want to save the image in an external DAM (ResourceSpace), and update the instance with the DAM resource id & URL in the DAM. ResourceSpace allows only import of resources from an online url, so I need the image to be accessible in django through a url.

I will keep images in both django & DAM.

the problem is that the file is uploaded by the user in a form. The file is nowhere to be found though, until I save the model instance. But then I need to modify instance, and save again?

Right now, the best approach I have found that seems to work, is to save the FileField (from inside the model) before saving the instance, like this:

```auto
self.document.save(self.document.name, self.document.file, save=False)
--- save in DAM & update other model fields ---
super().save

```

---

<div class="post-metadata">

**Author:** ![dennisvd](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/dennisvd/32/1441_2.png) [@dennisvd](https://forum.djangoproject.com/u/dennisvd)\
**Post date:** [August 23, 2023, 6:48pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/10 "2023-08-23T18:48:20Z")

</div>

Why not upload the file to the DAM after save. You can still make it a single transaction and rollback the save should the upload fail and update the record with the DAM uri.

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 24, 2023, 10:53pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/11 "2023-08-24T22:53:32Z")

</div>

Because I need to save info from the DAM to the database (its id in DAM and its url).  
So as to display it, and delete the DAM entry if the django db object gets deleted.

---

<div class="post-metadata">

**Author:** ![dennisvd](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/dennisvd/32/1441_2.png) [@dennisvd](https://forum.djangoproject.com/u/dennisvd)\
**Post date:** [August 25, 2023, 2:39pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/12 "2023-08-25T14:39:04Z")

</div>

You could explore option 3 from my previous reply.

---

<div class="post-metadata">

**Author:** ![petasis](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/petasis/32/6393_2.png) [@petasis](https://forum.djangoproject.com/u/petasis)\
**Post date:** [August 29, 2023, 7:50am UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/13 "2023-08-29T07:50:55Z")

</div>

Its a very complex option. It should have been much easier in django in my opinion.  
Right now, the solution I am using (saving the field with save=False) its much easier.  
Its not documented, but…

---

<div class="post-metadata">

**Author:** ![dennisvd](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/dennisvd/32/1441_2.png) [@dennisvd](https://forum.djangoproject.com/u/dennisvd)\
**Post date:** [August 29, 2023, 2:37pm UTC](https://forum.djangoproject.com/t/where-is-the-image-file/22978/14 "2023-08-29T14:37:37Z")

</div>

It is documented [Creating forms from models | Django documentation | Django](https://docs.djangoproject.com/en/4.0/topics/forms/modelforms/#the-save-method)

You can look for the commit=False

> This `save()` method accepts an optional `commit` keyword argument, which accepts either `True` or `False` . If you call `save()` with `commit=False` , then it will return an object that hasn’t yet been saved to the database. In this case, it’s up to you to call `save()` on the resulting model instance. This is useful if you want to do custom processing on the object before saving it, or if you want to use one of the specialized[model saving options](https://docs.djangoproject.com/en/4.0/ref/models/instances/#ref-models-force-insert). `commit` is `True` by default.

However I don’t know how it effects the file saving but I suspect the file will be stored in the media folder despite that there is no commit. Probably a good idea to use atomic to treat all your operations as 1 transaction so that you don’t get any inconsistencies like having files in the media folder that do not have a corresponding record.
