본문 바로가기
Python/Django

Django 실시간 채팅 : 이미지 전송 구현

by Byeong 2025. 1. 5.

 

 요즘 사용하는 채팅어플은 단순히 텍스트 전송을 넘어 이미지나 파일을 공유하는 기능이 필수이다. 그래서 DjangoReact를 사용하여 이미지 전송 기능을 구현했다. 이 글에서는 이미지 전송 방법에 대해 고민하고 구현하는 과정을 담았다.


이미지 전송 로직

처음에는 웹소켓(WebSocket)으로 직접 이미지 파일을 전송하려고 했다.

  1. 웹소켓으로 이미지 파일 전송
  2. 이미지 파일 저장
  3. 이미지 URL 반환

하지만, 웹소켓은 텍스트 기반 통신이므로 이미지 파일을 Base64로 인코딩해야 했다. 이 과정에서 파일 크기가 커지면 서버 부하와 연결 지연 문제가 발생할 수 있다는 점을 발견했다. 

 

 이러한 문제를 해결하기 위해 HTTP 요청을 통해 이미지를 업로드하고, 저장된 이미지의 URL을 반환한 뒤 이를 웹소켓으로 전송하는 방식으로 변경했다.

  1. 클라이언트에서 HTTP 요청으로 이미지 업로드
  2. 서버에서 이미지 파일 저장 후 URL 반환
  3. 반환된 URL을 웹소켓으로 상대방에게 전송

구현하기

Django 백엔드 서버 

 

1. 미디어 파일 설정

#setting.py
...

MEDIA_URL = '/media/'  # 미디어 파일 접근 URL
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

...

#config/urls.py
...

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

 

미디어 파일 저장 경로와 URL르 설정.

 

2. 이미지 저장 API 

 

- 모델 정의

#models.py

class Message(models.Model):
	...
	image = models.FileField(upload_to="chat_images/",blank=True, null=True)

 

upload_to를 통해 이미지를 저장할 디렉토리를 설정합니다. 여기서는 media/chat_images/에 파일이 저장된다.

 

-뷰 정의

 

#views.py

def post(self, request):
	...
    
    #이미지 파일 가져오기
    image = request.FILES.get('image')

    #메시지 저장 이미지 저장
    message = Message.objects.create(
        chat_room=room,
        sender_user=user,
        image=image)
	
    #이미지 URL생성 
    image_url = request.build_absolute_uri(message.image.url)
    return Response({'image_url': image_url}, status=status.HTTP_200_OK)

 

POST 요청을 들어온 이미지 파일을 저장하고 URL을 반환한다. 

 


React 프론트엔드

1.  이미지 업로드 및 URL 요청

const handelImage = async (image) => {
        ...

        const response = await apiClient.post('/api/chat/message/create/', {
            'image': image
        }, {
            headers: {
                "Content-Type": "multipart/form-data", // 파일 업로드 시 필수
            },
        });
        return response.data.image_url;

        ...
    };

 Django 서버에 이미지 URL를 요청한다. Content-Type을 multipart/form-data로 설정해야 Django 서버에서 request.FILES로 파일을 처리할 수 있다.

 

 HTML에 form 태그에 enctype = "multipart/form-data" 가 같은 의미로 "파일이나 이미지를 서버로 전송할 때 인코딩 되면 파일의 경로명만 전송되고 파일 내용이 전송되지 않기 때문에 모든 문자를 인코딩하지 않음을 명시하는 옵션이다"

 

 

2. 웹소켓으로  이미지 URL 전송

const sendMessage = async () => {
        let image_url = null;

        if (image) {
            image_url = await handelImage(image); // 이미지 URL 생성
        }
        
        // 메시지 전송
        chatSocketRef.current.send(
            JSON.stringify({ message, image: image_url, sender_user })
        );

        ...
        
    };

요청받은 URL를  웹소켓으로 전송해 준다. 


마무리 

 HTTP와 웹소켓을 결합하면 두 프로토콜의 장점을 극대화해서 이미지 전송 방식을 구현했다. 이 방법 이외에서 Celey를 이용하는 방법과 이미지를 서버에서 실시간으로 처리하거나, 웹소켓만을 사용한 Base64 이미지 전송 방식을 비교하는 것도 좋은 공부가 될 거 같다.

 


구현 프로젝트 : https://github.com/Byeong98/chat