How to upload images in Django without 504 Gateway Timeout

How to upload images in Django without 504 Gateway Timeout

·

5 min read

Have you ever tried uploading images in Django and encountered 504 Gateway Timeout? Then this blog is for you. What we will implement in this tutorial is an image uploader in Django with crop option. The upload is done asynchronously using AJAX function.

Assuming you have the basic Django coding experience, we can start with models. Create a Photo model to store uploaded images.

from django.db import models

class Photo(models.Model):
    file = models.ImageField(default='images/dp/avatar.png', upload_to='images/dp/')

    def __str__(self):
        return self.file.url

Now create the view to handle image upload.

def add_dp(request):
    if request.method == 'POST':
        data = request.FILES['croppedImage2']
        postRoot = os.path.join(settings.MEDIA_ROOT, 'images/dp/')
        postRoot = postRoot.replace("\\", "/")
        fs = FileSystemStorage(location=postRoot)
        id_1 = str(uuid.uuid1())
        uuid_filename = id_1 + '.' + imghdr.what(data)
        filename = fs.save(uuid_filename, data)
        file_url = 'images/dp/' + filename
        photo = Photo.objects.create(file=file_url)
        return JsonResponse({"done":True})

We will use croppie plugin to crop the images first. Install the plugin following instructions on this link- Croppie . Include css and js files in index.html

<link rel="stylesheet" href="croppie.css" />
<script src="croppie.js"></script>

Create the button in index.html

 <button type="button" class="btn btn-primary btn-sm dpBtn"
    user_id={{ request.user.id }} url="{% url 'userprofile:add_dp' %}"
   data-toggle="modal" data-target="#exampleModalDp">
  <i class="feather-camera"></i> Change profile image
  </button>

Create a modal to open when user clicks the button

     <!-- Modal DP ---------->
<div class="modal fade" id="exampleModalDp" tabindex="-1" role="dialog"
 aria-labelledby="exampleModalDpTitle"
 aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLongTitle">Add Profile Image</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">

            <div class="col col-md-12">

            </div>

            <form id="mydpform" action="">
                {% csrf_token %}
                <label for="fileDp">Image</label>
                <input type="file" accept=".png, .jpg, .png" id="fileDp"/>

            </form>


        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>

        </div>
    </div>
</div>
</div>
<!-- End Modal DP-->

Now create a croppie modal to open the cropbox

<!-- croppie dp-->
<div class="modal " tabindex="-1" role="dialog" id="uploaddpModal">
<div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <h5 class="modal-title">Modal title</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">
            <div class="row">
                <div class="col col-lg-12 col-md-10 col-sm-4 text-center">
                    <div id="image_demo_dp"></div>
                </div>

            </div>
            <div id="progress-wrp2">
                <div id="progress-bar2"></div>
                <div class="status">0%</div>
            </div>

        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-primary crop_image_dp">Crop and Save</button>
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        </div>
    </div>
</div>
</div>
<!-- End croppie dp -->

Include js to handle file crop and file upload


//---------------------------------- Dp -----------//
var image_crop2 = $('#image_demo_dp').croppie({
    viewport: {
        width: 300,
        height: 300,
        type:'square'
    },
    boundary:{
        width: 350,
        height: 350
    }
});

/// catching up the cover_image change event and binding the image into my croppie. Then show the modal.
$('#fileDp').on('change', function(){
    var reader = new FileReader();
    reader.onload = function (event) {
        image_crop2.croppie('bind', {
            url: event.target.result,
        });
    }
    reader.readAsDataURL(this.files[0]);
    $('#uploaddpModal').modal('show');
           $('#exampleModalDp').modal('hide');

});

/// Get button click event and get the current crop image
$('.crop_image_dp').click(function(event){
    var actionURL= $('.dpBtn').attr("url");
    let id =  $('.dpBtn').attr("user_id");
    console.log(actionURL);
       $('#progress-wrp2').show();
             $('#progress-bar2').show();

    image_crop2.croppie('result', {type: 'blob', size: 'original', format: 'jpeg', quality: 0.5, }).then(function(blob) {

                    let formData = new FormData();
                    formData.append('croppedImage2', blob);
                    formData.append('csrfmiddlewaretoken', '{{ csrf_token }}');
                    formData.append('id', id);

                          $.ajax({
                            url: actionURL,  //server script to process data
                            type: 'POST',
                            data: formData,
                            cache: false,
                            contentType: false,
                            processData: false,
                            success: function reloadPage() {

                                location.reload(true);
                            },     xhr: function () {
                                                //upload Progress
                                                var xhr = $.ajaxSettings.xhr();
                                                if (xhr.upload) {
                                                    xhr.upload.addEventListener('progress', function (event) {
                                                        var percent = 0;
                                                        var position = event.loaded || event.position;
                                                        var total = event.total;
                                                        if (event.lengthComputable) {
                                                            percent = Math.ceil(position / total * 100);
                                                        }
                                                        //update progressbar

                                                        $("#progress-bar2").css("width", +percent + "%");
                                                        $(".status").text(percent + "%");
                                                    }, true);
                                                }
                                                return xhr;
                                            },

                        }
                    );

    });

});

//---------------------------------- end Dp  -----------//

Now your image uploader is ready. Now you can upload high quality images without getting timeout error.