1

Here is my problem. To summarize, my application transform one or many images. And I want that the user can download the images transformed with a button "Save new images" for example. When the user clicks the button, the Download window for example pops up and he can download all the images where he wants on his computer. I don't know if it's possible, I wait your answers.
I already did the upload images part, it works.

views.py

def mon_data(request, dataset_id):
    my_data = get_object_or_404(Dataset, pk=dataset_id)
    images_src = Image_Source.objects.filter(dataset = my_data)
    images_seg = []
    for src in images_src:
        images_seg.append(Image_Segmentee.objects.get(origine = src, model = src.model_initial))
    model = images_seg[0].model
    context = {
        "material": model.materiau_type, "model": model, 
        "images_seg": images_seg, "my_data": my_data, "nb_images":len(images_seg)
    }
    return render(request, "interface/my_data.html", context)

models.py

TYPES=[
    ('Metal', 'Metal'),
    ('Composite', 'Composite'),
]

DECISION=[
    ('En attente', 'En attente'),
    ('Valide', 'Valide'),
    ('Rejete', 'Rejete'),
]

class Modele(models.Model):
    name = models.CharField(max_length=100)
    materiau_type = models.CharField(max_length=20, choices=TYPES, null=False, blank=False)


class Dataset(models.Model):
    name = models.CharField(max_length=200, null=False, blank=False)
    date = models.DateField()

class Image_Source(models.Model):
    dataset = models.ForeignKey(Dataset, on_delete=models.CASCADE, null=True)
    materiau_type = models.CharField(max_length=20, choices=TYPES, null=False, blank=False)
    model_initial = models.ForeignKey(Modele, on_delete=models.SET_NULL, null=True)
    illustration = models.ImageField(null=False, blank=False, upload_to="img/")

class Image_Segmentee(models.Model):
    dataset = models.ForeignKey(Dataset, on_delete=models.CASCADE, null=True)
    origine = models.ForeignKey(Image_Source, on_delete=models.CASCADE, null=True)        
    operator_decision = models.CharField(max_length=20, choices=DECISION, default='En attente')
    illustration = models.ImageField(null=False, blank=False, upload_to="img_modif/")
    model = models.ForeignKey(Modele, on_delete=models.SET_NULL, null=True)

interface/my_data.html

<div class="row">
     <div class="col s6">
                <p style="font-size: 200%; font-weight: bold;">Original image</p>
                {% for seg in images_seg %}
                    <a href="{% url 'mon_image' seg.origine.id %}">
                        <p style="color: black;">{{seg.origine}}</p>
                        <img class="img-data" src="{{ seg.origine.illustration.url }}" alt="image_src_echec">   
                    </a>
                {% endfor %}                             
      </div>
       <div class="col s6">
                <p style="font-size: 200%; font-weight: bold;">Segmented image</p>
                {% for seg in images_seg %}
                    <a href="{% url 'mon_image' seg.origine.id %}">
                        <p style="color: black;">{{seg}}</p>
                        <img class="img-data test1" src="{{ seg.illustration.url }}" alt="image_seg_echec">
                   </a>
                {% endfor %}                         
      </div>
</div>

-- Edit --
I created a new view download and I changed my urls.py file. Don't forget the imports

views.py

from wsgiref.util import FileWrapper
from zipfile import ZipFile

def download_user(request, dataset_id):
    my_data = get_object_or_404(Dataset, pk=dataset_id)
    images_seg = Image_Segmentee.objects.filter(dataset = my_data)    
    with ZipFile('export.zip', 'w') as export_zip:
        for my_seg in images_seg:
            img_url =  "." + my_seg.illustration.url
            print(img_url.split("/")[-1])
            export_zip.write(img_url, img_url.split('/')[-1])

    wrapper = FileWrapper(open('export.zip', 'rb'))
    content_type = 'application/zip'
    content_disposition = 'attachment; filename=export.zip'
    
    response = HttpResponse(wrapper, content_type=content_type)
    response['Content-Disposition'] = content_disposition
    return response

1 Answers1

0

It looks like you want to download images in a zip file, so this might be a duplicate of: download images in zip file

With some slight modifications your should define a view with something like:

from zipfile import ZipFile
def download_image(request, id):
    # Modele seems to be the model holding the modified collection
    target_model=Modele.objects.get(pk=id)
    # get a qs of assigned illustrations
    segmentee_set = target_model.image_segmentee.all()
    
    with ZipFile('export.zip', 'w') as export_zip:
        for image_model in segmentee_set:
            img_path =  image_model.illustration.path
            # below line should result in .write("/media/somefolder/image123.png", image123.png)
            export_zip.write(img_path, img_path.split("/")[-1]) 

    wrapper = FileWrapper(open('export.zip', 'rb'))
    content_type = 'application/zip'
    content_disposition = 'attachment; filename=export.zip'

    response = HttpResponse(wrapper, content_type=content_type)
    response['Content-Disposition'] = content_disposition
    return response

Then of course add the view to URLs and try to access this URL directly in your browser.

Make sure to read about managing files.

If this solution was helpful, you should optimize, error-check and investigate how in-memory files are generated and served, and decide if you want to store the generated zip files somewhere or if you have to generate them each time.

nOperator
  • 111
  • 1
  • 4
  • Thank you very much it was really helpful. There are a lot of folder inside the zip created but I will fix that to have only the images the user want to download. I will edit my first post with the solution maybe. – MatthieuQcc Aug 17 '21 at 12:57
  • I have added the missing import and a missing parentheses. export_zip.write(img_path, img_path.split("/")[-1]) I have just tried this line and it should return the correct path of the image, without folders. Would you run a print(img_path.split("/")[-1]) inside that loop please? – nOperator Aug 17 '21 at 14:24
  • When I print img_path.split("/")[-1] I have the path with the \ and not just the name of the file. I'm on windows it's for that. So I need to use img_seg.url and add a "." in front of the string. This solution works for me. I will edit my first post. Thanks for your help ! – MatthieuQcc Aug 18 '21 at 07:27
  • OK in case of windows just use split("\")[-1] instead, it would give you the filename. Glad I could help. – nOperator Aug 18 '21 at 08:03