0

My Django app generates a file. It takes img1.png and watermark.png and past them together and saves it again in the folder.

Everything works as expected.

This is the function:

def generate():
    img1 = Image.open(f'{current_path}/media/pdf/img1.png')
    img2 = Image.open(f'{current_path}/media/watermark.png')
    img1.paste(img2, (150, 250), img2)
    img1.save(f'{current_path}/media/pdf/generatedfile.png')

When working locally on my computer everything is good with specifying the path. However, in production it does not work anymore. I need to save the generatedfile.png directly on AWS S3.

For this reason I have create a simple model:

class pngUploadModel(models.Model):
     auto_increment_id = models.AutoField(primary_key=True, default=True)
     image = models.ImageField(null=True, blank=True, upload_to="png/")

I am able to upload images to this model using the admin interface. Everything still works as expected.

Now to my struggle. I need to generate the image, and saving it "directly" to the model. Without saving it first to the path (because this will not work in production).

Approach:

   def generate():
        img1 = Image.open(f'{current_path}/media/pdf/img1.png')
        img2 = Image.open(f'{current_path}/media/watermark.png')
        img1.paste(img2, (150, 250), img2)
        img1.save(f'{current_path}/media/pdf/generatedfile.png')

        try:
             filename = pngUploadModel.objects.create()
             filename.image = img2
             print('worked!')
        except Exception as e:
             print(f'this is the error message: {e}')

Output: It creates an object in my model which I can see on my admin panel, but the model is empty, there is no image.

How can I save the generated image to my model, without having to save it first to my local directory. I was thinking to use something like a tempfile but I do not know if it is the right way.

GCMeccariello
  • 339
  • 2
  • 13

1 Answers1

1

If I'm correct, you want to get the generated file from the file path (f'{current_path}/media/pdf/generatedfile.png') and save it to your pngUploadModel.

An approach that I remember taking recently was to use the same prefix of the generated filename, setting that to be where the model instance image field points. For example:

def generate():
    img1 = Image.open(f'{current_path}/media/pdf/img1.png')
    img2 = Image.open(f'{current_path}/media/watermark.png')
    img1.paste(img2, (150, 250), img2)
    img1.save(f'{current_path}/media/pdf/generatedfile.png') 
    # the prefix string of the generated file -> f'{current_path}/media/pdf/generatedfile.png'

    try:
         genFile = pngUploadModel()
         # Using the path/prefix of the generated file to be set to the image field
         genFile.image = f'{current_path}/media/pdf/generatedfile.png'
         genFile.save()
         print('worked!')
    except Exception as e:
         print(f'this is the error message: {e}')

I used this answer as my guide then and it worked perfectly.

Another way is to save the generated file to the image field by passing a few arguments to the save() on the image/file field. Example:

from django.core.files.base import ContentFile  # ensure you import

def generate():
    prefix = f'{current_path}/media/pdf/generatedfile.png'

    img1 = Image.open(f'{current_path}/media/pdf/img1.png')
    img2 = Image.open(f'{current_path}/media/watermark.png')
    img1.paste(img2, (150, 250), img2)
    img1.save(prefix) 
    # the prefix string of the generated file -> f'{current_path}/media/pdf/generatedfile.png'

    # with open('/path/to/already/existing/file', 'rb') as f:
    with open(prefix, 'rb') as f:
        data = f.read()

        genFile = pngUploadModel()

        genFile.image.save('generatedfile.png', ContentFile(data))
        genFile.save()

Ideally, that should work. You can also view other answers to this question as they might be helpful or can be used for future reference.

Damoiskii
  • 1,328
  • 1
  • 5
  • 20
  • Thanks a lot for this elaborated answer. The first approach did not seem to work. The second works for a specific file which already is on the server. The main problem is, when the file is generated it will be saved first locally and then it will be uploaded to S3. However, on the server it can not be saved somewhere before uploading it. I don't know if a tempfile would solve the problem. `def generate()` -> `tempfile` -> `pngUploadModel()` – GCMeccariello Aug 17 '22 at 06:22