본문 바로가기
프로그래밍/웹서버

[Django] 게시글에 이미지를 보여주기 위해 겪은 일

by 오답노트의 주인 2022. 10. 8.

목표

장고를 배우기 위해 보통 블로그를 만들고 CRUD하는 과정을 진행한다. 보통 게시글 모델을 만들 때 TextField로 내용을 작성하고 사진 하나 첨부하려고 ImageField를 쓴다.

 

글 쓰고 사진 하나 달랑 넣으면 게시글이라고 하기엔 매우 아쉽다. 글 사이사이에 이미지를 넣고 싶었다. 그리고 들여쓰기나 리스트 등등 html태그들을 활용한 게시글을 작성하려면 어떻게 해야할지 고민이었다.

고민

글 사이사이에 사진이 들어가려면 어떻게 해야할까? 처음엔 이미지가 여러 개 포함될 수 있다고 생각해 게시글 모델을 만들고 이미지 모델도 만든 후 외래키관계를 만들려 했다. 하지만 이미지의  위치를 특정지을 수 없고 게시글을 수정할 때 오류가 날게 뻔해보였다.

 

다음으로 생각해본건 이미지를 먼저 올리고 그 이미지의 경로를 img태그에 담아 저장하는 방법이었다. 결과물을 가져올 때 html형식으로 갖고오기 때문에 다른 태그들도 활용할 수 있겠다고 여겨졌다. 

 

하지만 html태그 사이에 <script>를 넣는다면(XSS) 그대로 서버폭발이므로 내 스스로 만들기에는 불가능하다고 판단해 해결방법을 찾아 돌아다녀보았다.

 

반나절 구글링을 한 결과 아래 링크에서 실마리를 찾을 수 있었다.

 

https://ko.wikipedia.org/wiki/%EC%9C%84%EC%A7%80%EC%9C%84%EA%B7%B8

 

위지위그 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 위지위그(WYSIWYG: What You See Is What You Get, "보는 대로 얻는다")는 문서 편집 과정에서 화면에 포맷된 낱말, 문장이 출력물과 동일하게 나오는 방식을 말한다. 이는

ko.wikipedia.org

우리가 평소에 글을 쓸 때 이용하던 에디터들을 전부 위지위그라고 부른다. 사용자가 게시글을 다듬기위해 여러가지 도구들을 제공하는 에디터를 말한다. 

 

에디터로 작업한 결과물이 html형식을 유지한 데이터이기 때문에 에디터마다 다르게 보일 수는 있겠으나 전달받은 데이터의 html형식을 유지하여 화면에 나타내기 때문에 TextField와는 다르게 이미지도 보여주고 파일도 보여주고 별별일을 다 할 수 있다. 이런 점에서 내가 두 번째로 생각한 내용과 일치한다.

시행착오

장고는 이런 에디터를 지원하지 않기 때문에 서드파티앱을 끌어다 써야 한다. 처음 찾아본 앱으로는 summernote가 있었다.

 

https://github.com/summernote/django-summernote 

 

GitHub - summernote/django-summernote: Simply integrate Summernote editor with Django project.

Simply integrate Summernote editor with Django project. - GitHub - summernote/django-summernote: Simply integrate Summernote editor with Django project.

github.com

한국 개발자분이 관리를 하셨던 것으로 보여 거부감없이 이용해보았다. 잘 작동하길래 안심하고 이미지 업로드를 해보았더니 웬걸, 업로드는 되지만 이미지를 보여주지 않았다. 

 

내부 로직을 살펴보니 bleach라는 패키지를 이용해서 XSS공격을 막기 위해 입력된 html소스를 뜯어 위험이 될 만한 태그와 속성들을 지우고 있었다. 여러 태그들과 속성들이 있었는데, img태그는 남겨두도록 되어 있었지만 src속성은 지워버리라고 되어있었다. 이 부분을 고쳐주니 정상적으로 작동했다.

 

하지만 작성했던 게시물을 다시 수정하려고 에디터를 열어보니 형식이 깨져있었다. 표를 작성했었는데 표는 어디가고 공백이 나를 반겼다. 

 

무엇보다도 마지막 업데이트가 작년...이다. 결국 다른 앱을 찾아보게 되었다.

 

두 번째로 찾아본건 ckeditor다. summernote를 먼저 접해본 이유는 구글링을 하다가 ckeditor의 일부 기능이 유료라는 글을 보았기 때문이다. 쓸게 그것밖에 보이지 않아 일단 써보았는데 유료는 아니더라. 누가 그런 말을 한거야?

 

summernote를 쓸 때 겪었던 문제들은 없었다. 이미지와 파일 업로드는 물론이고 수정하려고 다시 에디터를 켰는데 서식이 깨지는 일은 없었다.

구현

기본적인 장고 프로젝트 설치는 이미 되었다고 생각한다. 나는 장고를 REST API로만 활용할 생각이어서 템플릿을 작성하는 일은 안하기로 했다.

""" 사용한 패키지 버전 """

Django==4.1.1
django-ckeditor==6.5.1
djangorestframework==3.14.0
Pillow==9.2.0
postgres==4.0

공식문서에 있는 튜토리얼대로 설치를 진행한다.

# settings.py

INSTALLED_APPS = [
   ...
   "ckeditor",
   "ckeditor_uploader",
]

STATIC_URL = "/static/"

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

MEDIA_URL = "/media/"

MEDIA_ROOT = os.path.join(BASE_DIR, "media/")

# CKEDITOR CONFIG

CKEDITOR_UPLOAD_PATH = "uploads/"

X_FRAME_OPTIONS = "SAMEORIGIN"
# urls.py

urlpatterns = [
    ...
    path("ckeditor_uploader/", include("ckeditor_uploader.urls")),
]

path에 들어가는 경로는 마음대로 설정해도 괜찮다. 여기까지 설정하고 모델을 작성한다.

from django.db import models

from ckeditor_uploader.fields import RichTextUploadingField


class Post(models.Model):
    ...
    content = RichTextUploadingField()

진짜 이렇게만 만들고 migrate 후 어드민페이지로 가기만해도 에디터를 만질 수 있다. 

저장한 다음 Post모델에 대한 viewset을 간단하게 작성 후 내용을 요청해보면 아래처럼 뜬다.

아직 클라이언트를 만들지 않아서 이 데이터 그대로 가져다 쓰면 되는지 모르겠지만, 클라이언트에서 파싱을 한 후 그대로 보여주면 될 것 같다고 생각한다.

 

위 사진에서 경로의 호스트부분이 없는데, 클라이언트에서 호스트를 추가한 후 변환하면 되지 않을까 한다.

댓글