Python/Django

[Django][RestAPI] Image Path로 서버에 이미지 업로드하기

S0PH1A 2019. 7. 24. 12:41
반응형

[Django][RestAPI] Image Path로 서버에 이미지 업로드하기


서버에서는 사용자 PC에 있는 이미지의 경로만 갖고 해당 위치의 이미지를 서버로 복사(이동)할 수 없다.
파일 열기(불러오기)기능을 하는 <input type="file">을 이용하면 가능하지만, JS에서 서버로 넘긴 path만으로는 Chrome에서 사용자 PC에 접근을 막았기(fakepath, Chrome보안정책) 때문에 불가능했다.

 

Electron(NodeJS)에서 서버로 RestAPI(Django Rest FrameWork)를 통해서 이미지 경로만 갖고 여러 개의 이미지를 한번에 전송하려면 base64로 인코딩(encode/encoding)한 값을 서버로 전달 한 후 서버에서 base64를 이미지로 디코딩(decode/decoding)해주면 된다.

 

 

먼저, Electron에서 path에 존재하는 이미지를 base64로 인코딩 해준다.

(아래 예제에서는 Client에서 base64변환 후 Main에서 Rest API로 전달했지만, Main에서 모두 처리해도 상관은 없다.)

  • Electron Client 부분

    const {
        ipcRenderer,
        remote
    } = require('electron')
    const fs = require('fs')
    
    const filepath = "C:\Users\user\images\aaa.png"
    
    // 변환
    function base64_encode(file) {
        let buf = fs.readFileSync(file);
        let base64 = buf.toString('base64');
        return base64;
    };
    const _base64 = base64_encode(filepath)
    
    ipcRenderer.sendSync('sPOST', _base64)
  • Electron MainProcess 부분

    // index.js
    const {
      ipcMain
    } = require("electron");
    
    // ...생략...
    
    ipcMain.on("sPOST", async (event, data) => {
      event.returnValue = await post(data)
    })
    
    function post(data) {
        return new Promise(function (resolve, reject) {
            const _URL = `http://127.0.0.1:8000/image/`
            const data = Object.assign({
                headers: {
                    'Content-type': 'application/json',
                    },
                }, param)
    
                axios.post(_URL, data).then((response) => {
                    if (response.status === 201) { // created = 201
                        resolve(response.data)
                        } else resolve(false)
                    })
                    .catch((error) => {
                        console.log(error)
                        resolve(false)
                    });
                })
    }

Django Rest API에서 사용할 모델(Model)을 아래와 같이 간단하게 선언했다.

 

Django에서 Image관련 Field를 제공한다.

  * ImageField

     - ImageField를 사용하려면 settings.py에 MEDIA_ROOT를 정의해야 한다.

     - https://docs.djangoproject.com/ko/2.2/faq/usage/#how-do-i-use-image-and-file-fields

# models.py
from __future__ import unicode_literals

from django.db import models
from django_mysql.models import Model

class Image(models.Model):
    name = models.CharField(max_length=500, primary_key=True)   # 파일명
    image = models.ImageField(upload_to='uploads', blank=True)  # 이미지
    base64 = models.TextField(blank=True)                       # base64 

 

마지막으로, base64를 Image로 변환(디코딩)하는 부분을 serializers.py에 선언했다.

# serializers.py
from rest_framework import serializers 
from .models import Image

from django.core.files.base import ContentFile    
import uuid
import base64

class ImageSerializer(serializers.ModelSerializer):

    class Meta:
        model = Image        
        fields = '__all__'

    def create(self, validated_data):
        image_name = str(uuid.uuid4())  # image name 생성

        # 있으면 업데이트 없으면 생성
        result, created = FileList.objects.get_or_create(
                name=image_name,
                base64=validated_data.get('base64', None),  # base64
                image=ContentFile(base64.b64decode(validated_data.get('base64', None)), name=image_name + '.png')  # Image
        )

        return result

 

반응형