진행률 표시줄이 있는 AJAX 파일을 Django를 사용하여 블록으로 업로드합니다.

안녕하세요!!!
파일 업로드기를 만들 수 있는 여러 가지 방법과 기술이 있습니다.Django는 어떤 종류의 파일도 불러올 수 있는 서버를 만들 수 있습니다. 그러나 문제는 Django가 전체 파일을 불러오고, 불러온 후에 페이지를 다시 불러올 수 있다는 것입니다. 이 경우 사용자는 한 작업만 수행할 수 있습니다.만약 파일 크기가 매우 작다면, 이것은 번거로움을 가져오지 않지만, 파일 크기가 증가함에 따라 일이 까다로워질 것이다.
사이트를 유연하게 하는 관건은 사용자가 여러 임무를 동시에 완성할 수 있도록 하는 것이다.만약 당신이 1GB 크기의 동영상을 올리고 있다면, 동영상이 올라오기 전에는 아무것도 할 수 없습니다.얼마나 고통스러운가!기가바이트 크기의 파일을 처리할 때 파일을 전체적으로 업로드한다는 생각은 매우 나쁘다는 것을 증명한다. 파일을 블록으로 나누어 업로드한다는 개념이 있어 여기서 매우 편리하다.청크는 특정 시간의 파일 인스턴스입니다.블록 업로드 파일은 파일을 더 작은 블록으로 나누어 각 블록을 동시 업로드해야 합니다.
이 자습서에서는 AJAX 요청 및 응답 주기를 사용하여 Django 서버에 파일을 블록으로 업로드하는 방법을 살펴봅니다.시간을 낭비하지 말고 재미있는 부분으로 넘어가자.

우리의 프로젝트를 세우다


(프로젝트 설정이 준비되어 있으면 이 부분을 건너뛸 수 있음)

새 Django 프로젝트 만들기


django-admin startproject fileUploader
cd fileUploader

프로젝트 관리


python manage.py runserver

프로젝트에 새 프로그램 만들기


python manage.py startapp uploader
업로드러 프로그램을 프로젝트에 포함시키기 위해 코드를 빠르게 설정합니다.
  • URL을 만듭니다.py 파일 업로드 프로그램
  • 프로젝트 수준 URL을 구성합니다.py 파일은 이 파일의 URL을 포함합니다.
  • from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('fileUploader/', include('uploader.urls')),
    ]
    
  • fileUploader 아래에 static, 미디어,templates 세 개의 폴더를 만듭니다.
  • 정적 폴더에 css와 js 두 개의 폴더를 만듭니다.
  • index라는 파일을 만듭니다.템플릿 폴더 내의 html
  • 앱이라는 파일을 만듭니다.css 폴더의 css
  • 앱이라는 파일을 만듭니다.js 폴더 내의 js
  • 프로젝트 레벨 설정을 구성합니다.이 변경 사항을 포함하는py 파일
  • INSTALLED_APPS = [
        ...
        'uploader',
    ]
    
    TEMPLATES = [
        {
            ...
            'DIRS': [os.path.join(BASE_DIR,'templates')],
            ...
        }
    ]
    
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static')
    ]
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    MEDIA_URL = '/media/'
    
    이렇게 해서 우리는 설치를 완성했다.우리들은 실제의 실현으로 전환합시다.

    사용자 인터페이스 설정


    색인html


    UI가 포함된 HTML 파일입니다.나는 줄곧 매우 간단해서 너는 마음대로 할 수 있다.보시다시피 bootstrap 4 구성 요소와 맞춤형 CSS를 사용합니다.PS: 양식에 csrf 토큰이 포함되어 있는지 확인:)
    {% load static %}
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
            integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
            crossorigin="anonymous">
        <title>AJAX + DJANGO File Uploader</title>
        <link rel="stylesheet" href="{% static 'css/app.css' %}">
    </head>
    <body>
        <div class="col-lg-6 col-md-6" style="margin: 0 auto; display: block; margin-top: 100px;">
            <form enctype="multipart/form-data" method="POST" action="">
                {% csrf_token %}
                <div class="form-group">
                    <label>Select file to upload.</label>
                    <input type="file" class="form-control" id="fileupload" placeholder="Select file">
                </div>
                <input type="submit" value="Upload" id="submit" class="btn btn-success">     
            </form>
            <div id="uploaded_files"></div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="{% static 'js/app.js' %}"></script>
    </body>
    </html>
    

    응용 프로그램.css


    UI를 보다 일관성 있게 사용할 수 있도록 자체 CSS를 추가합니다.또한 파일을 업로드할 때 동적으로 표시되는 진행률 막대에 스타일을 추가했습니다.
    #myProgress {
        width: 100%;
    }
    #uploaded_files {
        margin-top: 25px;
        display: flex;
    }
    label {
        font-weight: bold;
    }
    .file-icon i {
        font-size: 60px;
        color: rgb(0, 0, 0);
    }
    .file-details {
        margin-top: -2px;
        padding-left: 10px;
        width: 100%;
    }
    .file-details p {
        margin-bottom: -7px;
    }
    small {
        margin-top: 0;
        color: black;
    }
    
    이것이 바로 우리 사용자 인터페이스의 표시 방식이다

    응용 프로그램.js


    이것이 바로 우리 코드의 핵심이다.나는 이곳에서 대상을 대상으로 하는 방법을 사용했는데 함수식 방법도 잘 작동할 수 있고 거의 변화가 없다.
    max length라는 속성은 한 번에 업로드할 수 있는 블록의 최대 크기를 나타냅니다.단추를 눌렀을 때 이벤트가 터치될 때 upload () 방법이 있습니다.
    class FileUpload {
        constructor(input) {
            this.input = input
            this.max_length = 1024 * 1024 * 10; // 10 mb
        }
    
        upload() {
            this.create_progress_bar();
            this.initFileUpload();
        }
    
    initFileUpload() {
        this.file = this.input.files[0];
        this.upload_file(0, null);
    }
    
    (function ($) {
        $('#submit').on('click', (event) => {
            event.preventDefault();
            var uploader = new FileUpload(document.querySelector('#fileupload'))
            uploader.upload();
        });
    })(jQuery);
    

    initFileUpload() 방법


    다음은 사용된 변수 목록입니다.
  • existingPath - 파일이 전체 업로드 또는 이전 블록을 포함하는 업로드 경로
  • 로 사용할 수 있는 경우null
  • nextChunk-파일의 다음 부분
  • currentChunk-파일의 현재 부분
  • uploadedChunk - 지금까지 업로드된 모든 블록의 집합
  • formData - 서버에 전송될 데이터를 저장하는 대상입니다.
  • 끝 - 업로드 종료 여부.
  • 우선 FormData의 실례를 만들고 서버에 보낼 모든 값을 추가합니다.그런 다음 $를 사용하여 AJAX 인스턴스를 만듭니다.ajax () 에는 많은 속성이 있습니다.여기는 저희가 사용했어요.
  • xhr() - 업로드된 파일의 양을 계산합니다
  • .
  • error() - 일부 작업을 수행할 때 오류가 발생했을 때 호출
  • success() - 작업이 성공적으로 끝났을 때 호출
  • url - 요청한 url
  • 유형 - 요청 방법
  • 데이터 유형 - 우리가 전달하는 데이터 유형
  • 데이터 - 전달될 실제 데이터
  • upload_file(start, path) {
            var end;
            var self = this;
            var existingPath = path;
            var formData = new FormData();
            var nextChunk = start + this.max_length + 1;
            var currentChunk = this.file.slice(start, nextChunk);
            var uploadedChunk = start + currentChunk.size
            if (uploadedChunk >= this.file.size) {
                end = 1;
            } else {
                end = 0;
            }
            formData.append('file', currentChunk);
            formData.append('filename', this.file.name);
            formData.append('end', end);
            formData.append('existingPath', existingPath);
            formData.append('nextSlice', nextChunk);
            $('.filename').text(this.file.name)
            $('.textbox').text("Uploading file")
            $.ajaxSetup({
            // make sure to send the header
                headers: {
                    "X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value,
                }
            });
            $.ajax({
                xhr: function () {
                    var xhr = new XMLHttpRequest();
                    xhr.upload.addEventListener('progress', function (e) {
                        if (e.lengthComputable) {
                            if (self.file.size < self.max_length) {
                                var percent = Math.round((e.loaded / e.total) * 100);
                            } else {
                                var percent = Math.round((uploadedChunk / self.file.size) * 100);
                            }
                            $('.progress-bar').css('width', percent + '%')
                            $('.progress-bar').text(percent + '%')
                        }
                    });
                    return xhr;
                },
    
                url: '/fileUploader/',
                type: 'POST',
                dataType: 'json',
                cache: false,
                processData: false,
                contentType: false,
                data: formData,
                error: function (xhr) {
                    alert(xhr.statusText);
                },
                success: function (res) {
                    if (nextChunk < self.file.size) {
                        // upload file in chunks
                        existingPath = res.existingPath
                        self.upload_file(nextChunk, existingPath);
                    } else {
                        // upload complete
                        $('.textbox').text(res.data);
                        alert(res.data)
                    }
                }
            });
        };
    

    진행 표시줄 만들기() 방법


    여기에 파일을 업로드할 때 표시되는 안내 진도표를 만들었습니다.사용자는 얼마나 큰 발전을 이루었는지 직관적으로 볼 수 있는데, 이것은 항상 좋은 일이다.
    create_progress_bar() {
            var progress = `<div class="file-icon">
                                <i class="fa fa-file-o" aria-hidden="true"></i>
                            </div>
                            <div class="file-details">
                                <p class="filename"></p>
                                <small class="textbox"></small>
                                <div class="progress" style="margin-top: 5px;">
                                    <div class="progress-bar bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
                                    </div>
                                </div>
                            </div>`
            document.getElementById('uploaded_files').innerHTML = progress
        }
    
    이렇게 해서 우리는 앞부분을 완성했다.이제 이 코드를 시도하기 위해 모델과 서버를 구축합시다.

    서버 설정(업로드 프로그램)


    인터넷 주소.py


    요청한 URL
    urlpatterns = [
        path('', views.index, name='index'),
    ]
    

    의견.py


    서버에 보내는 요청은 보기에 정의된 함수로 처리됩니다.피야.POST 요청을 받으면 데이터를 검색하여 새 파일이나 미디어 폴더에 첨부된 기존 파일을 만들고 파일이 저장된 경로를 응답으로 보냅니다.파일을 바이너리 모드로 저장합니다.
    from django.shortcuts import render
    from django.http import JsonResponse
    import os
    from .models import File
    
    def index(request):
        if request.method == 'POST':  
            file = request.FILES['file'].read()
            fileName= request.POST['filename']
            existingPath = request.POST['existingPath']
            end = request.POST['end']
            nextSlice = request.POST['nextSlice']
    
            if file=="" or fileName=="" or existingPath=="" or end=="" or nextSlice=="":
                res = JsonResponse({'data':'Invalid Request'})
                return res
            else:
                if existingPath == 'null':
                    path = 'media/' + fileName
                    with open(path, 'wb+') as destination: 
                        destination.write(file)
                    FileFolder = File()
                    FileFolder.existingPath = fileName
                    FileFolder.eof = end
                    FileFolder.name = fileName
                    FileFolder.save()
                    if int(end):
                        res = JsonResponse({'data':'Uploaded Successfully','existingPath': fileName})
                    else:
                        res = JsonResponse({'existingPath': fileName})
                    return res
    
                else:
                    path = 'media/' + existingPath
                    model_id = File.objects.get(existingPath=existingPath)
                    if model_id.name == fileName:
                        if not model_id.eof:
                            with open(path, 'ab+') as destination: 
                                destination.write(file)
                            if int(end):
                                model_id.eof = int(end)
                                model_id.save()
                                res = JsonResponse({'data':'Uploaded Successfully','existingPath':model_id.existingPath})
                            else:
                                res = JsonResponse({'existingPath':model_id.existingPath})    
                            return res
                        else:
                            res = JsonResponse({'data':'EOF found. Invalid request'})
                            return res
                    else:
                        res = JsonResponse({'data':'No such file exists in the existingPath'})
                        return res
        return render(request, 'index.html')
    

    모형.py


    모델이 있기 전에 우리는 데이터를 저장할 수 없다.다음은 저희가 이 업로드기를 어떻게 만드는지.
    class File(models.Model):
        existingPath = models.CharField(unique=True, max_length=100)
        name = models.CharField(max_length=50)
        eof = models.BooleanField()
    
    터미널에서 이 명령을 실행하여 모델을 이식합니다
    python manage.py makemigrations
    python manage.py  migrate
    
    지금 우리는 모두 우리의 응용 프로그램을 테스트할 준비가 되어 있다.브라우저로 이동하여 서비스 URL을 실행하고 파일을 선택한 다음 업로드를 클릭합니다.너는 네가 방금 지은 아름다운 물건을 볼 수 있다.나는 진도표가 아주 빨리 채워질 것 같아서 이번에는 더 큰 파일을 시도해 보자. (네가 원하는 크기는 하나도 접지 않을 것이다.) 파일이 어떻게 블록으로 업로드되는지 보자.
    이것은 출력된 몇 개의 스냅숏이다.


    다음은 이 코드의 GitHub 저장소 링크입니다.

    shubhamkshatriya25 / AJAX 파일 업로드기


    AJAX 요청 및 응답 주기를 사용하여 Django 서버에 파일을 블록으로 업로드할 수 있는 파일 업로드기


    AJAX 파일 업로드기


    코드 조회가 필요하지 않도록 이 프로젝트의 블로그 링크입니다.

    설치되지 않은 경우 로컬 컴퓨터에django를 설치합니다.

    pip install django
    

    프로젝트를 실행합니다.

    python manage.py runserver
    

    다음은 이 인터넷 응용의 일별이다.





    View on GitHub
    이것이 네가 오늘 새로운 것을 배울 수 있도록 도와줄 수 있기를 바란다.너도 인터넷에서 나에게 연락할 수 있다.소중한 시간 감사합니다.
    안녕히 계세요!

    좋은 웹페이지 즐겨찾기