CMS를 만든 이유
처음에 장고로 모바일뷰를 마케터가 직접 조작하면서 웹을 생성할수 있는 페이지를 만들 수 있냐는 요구사항이 들어왔었습니다. 처음 들었을 때는 막막했는데 먼저 이런 페이지가 어떤 페이지인지 명칭이 뭔지 찾아봤는데 CMS라는 기술로 웹사이트 웹 저작물들을 발행할 때 매우 수월하게 도와주며 비슷한 규격인 페이지를 쉽게 만들 수 있게 도와주는 서비스입니다.
Django로 만들 수 있는 CMS 서비스들의 특징들
Django CMS
Django CMS는 “기한이 있는 완벽주의자를 위한” 웹 애플리케이션 프레임워크인 Django로 구축된 최신 웹 퍼블리싱 플랫폼입니다.
Django CMS는 CMS에서 기대할 수 있는 일반적인 기능에 대한 기본 지원을 제공하지만 개발자가 쉽게 사용자 정의하고 확장하여 정확한 요구사항에 맞는 사이트를 만들 수도 있습니다.
공식 문서 : https://docs.django-cms.org/en/latest/index.html
Django Wagtail
StreamField
이 필드를 이용하면 , rich, long-form을 만들 수 있고, 간단한 에디터를 사용할 수 있습니다.
- Classy implementation
- StreamField를 사용하면 editor에서 콘텐츠 유형의 혼합 시퀀스를 작성할 수 있습니다. 이것은 데이터베이스의 단일 JSON 필드로 직렬화되며 HTML 표현을 사용하여 template에 내용을 출력하는 간단한 방법을 제공합니다.
- Simple editing
- 이러한 블록 타입을 equal citizens로 처리함으로써 주로 텍스트용으로 설계된 인터페이스로 이동하지 않고 각 블록에 대한 편집 컨트롤을 필요에 따라 단순하거나 복잡하게 만들 수 있습니다.
- Content economy
- 일단 풍부한 텍스트 영역 마인드셋을 벗어나면, 이것을 통해 더 장리할 수 있는 방법을 찾을 수 있습니다.
Localization
- Entry-level localization
- 언어 및 국가에 따라 다른 사이트로 로컬라이즈 해줍니다.
- 직관적인 UI
- wagtail에서 직접 콘텐츠 번역
Elasticsearch
- Elasticsearch는 Wagtail과의 간단한 통합과 뛰어난 성능을 갖춘 우수한 오픈 소스 검색 엔진 입니다.
- 이것을 통해 Wagtail또한 검색 인터페이스를 통해 이루어진 쿼리에 대한 간단한 통계를 수집합니다. 관리 인터페이스 또한 페에지, 이미지 및 문서에 대한 빠르고 원활한 액세스를 제공하기 위해 광범위한 검색을 사용합니다.
Wagtail로 선택한 이유
탄탄한 공식 문서 및 튜토리얼
먼저 wagtail로 선택한 이유는 공식문서가 쉽고 이해하기 편하게 구성되어 있고 장고 지식을 조금만 알아도 쉽게 만들 수 있기 때문입니다.
- https://wagtail.io/
- https://docs.wagtail.io/en/stable/?_ga=2.238527424.1142387937.1640922674-1934704751.1639460095
youtube에 있는 튜토리얼 영상
문서로만 빠른 시간내로 이해하는데는 한계가 있는데 wagtail은 youtube에 친절하게 따라할 수 있는 프로젝트가 있었습니다.
요구사항 처리가능
요구 사항 중에 아래와 같은 내용들이 있었는데 이것을 만족하는 것들이 wagtail이였습니다.
- url을 마케터가 쉽게 바꿀 수 있나? (o)
- 다양한 블록을 사용해서 이미지와 버튼을 쉽게 넣을수 있는가? (o)
- 페이지 끼리 연동이 쉽나? (o)
- 쉽게 페이지 한개를 생성할 수 있나? (o)
- 개발자도 1~2주내로 학습해서 쉽게 구현할 수 있는가? (o)
주의사항
wagtail을 선택한 것은 저의 개인적인 생각이므로 django cms랑 비교해서 너무 wagtail만 옳다는 생각하지는 말고 두개를 비교하면서 어느게 본인에게 잘 맞는지 또한 어느것이 자신의 핏과 맞는지 확인하고 선택해서 개발을 진행하시길 바랍니다.😀😀
Django Wagtail 시작하기
먼저 시작하기전에 위에 튜토리얼을 어느정도 시청했다는 전제하에 설명을 진행하겠습니다.
필요한 Blcok 및 App들
Block
- AppLinkBlock : 앱 또는 외부 페이지로 가기 위한 Block
- TitleAndTextBlock : 제목과 부제목 또는 앱에서 빈공백을 위한 Block
- FAQBlock : 질문을 클릭하면 답변을 쉽게 볼 수 있게 도와주는 Block
- RichTextBlock : RichText를 사용할 수 있게 도와주는 Block
- ImageBlock : 이미지를 사용할 수 있게 도와주는 Block
- ManyImageBlock : carousel image를 사용하기위해 도와주는 Block
- YoutubeVideoBlock : youtube동영상을 넣을수 있게 도와주는 Block
APP
- home : 프로젝트 생성시 기본적으로 생성되는 앱입니다
- flex : 자유로운 페이지를 만들기 위한 앱입니다.
- notice : 공지사항을 관리하기 위한 앱입니다.
- streams : streamfield에 들어갈 blocks들을 세팅하기 위한 app
프로젝트 세팅하기(Flex Page까지만)
먼저 wagtail프로젝트를 생성하겠습니다.
pip install wagtail
mkdir cms
cd cms
wagtail start config .
cms라는 디렉터리를 만든 후 그곳에서 작업을 진행하겠습니다.
그러면 다음과 같이 생성 된 것을 확인할 수 있습니다.
그 후 다음과 같은 명령어를 입력하겠습니다.
python manage.py migrate
python manage.py runserver
그러면 장고에서 항상 나오던 로켓이 아닌 무슨 신기한 알이 나오는 것을 확인할 수 있습니다. 그러면 기본 세팅은 끝이 났습니다.
이제 wagtail은 대부분의 페이지들을 admin에서 생성합니다. 따라서 django에서 admin을 생성해줄 때 사용하는 명령어를 통해 관리자 계정을 생성하겠습니다.
python manage.py createsuperuser
그 후 admin페이지에 접속한 후 로그인이 잘 동작되는지 확인하겠습니다.
url : localhost:8000/admin
Flex, Streams 앱 생성하기
django-admin startapp flex
django-admin startapp streams
그러면 flex와 streams디렉터리가 잘 생성된 것을 확인할 수 있습니다. 그 후 django에서 app등록한 것 처럼 config에 있는 base.py에 들어가서 INSTALLED_APPS에 streams와 flex를 추가하겠습니다.
INSTALLED_APPS = [
"home",
"search",
"streams",
"flex",
...
...
]
먼저 streamfield에 들어갈 blocks들을 만들어주기위해 streams앱에 blocks.py라는 파일을 생성하겠습니다.
그 후 다음과 같이 코드를 작성하겠습니다.
from wagtail.core import blocks
from wagtail.images.blocks import ImageChooserBlock
class AppLinkBlock(blocks.StructBlock):
link = blocks.CharBlock(required=True, help_text="앱 링크 작성")
button_title = blocks.CharBlock(required=False, help_text="링크 타이틀 작성")
image = ImageChooserBlock(required=False, help_text="버튼 이미지")
is_fixed = blocks.BooleanBlock(
required=False,
help_text="버튼 플로팅 여부",
default=False,
)
is_image = blocks.BooleanBlock(
required=False, help_text="버튼 이미지 사용 여부", default=False
)
class Meta:
template = "streams/link_block.html"
icon = "edit"
label = "app link"
class TitleAndTextBlock(blocks.StructBlock):
"""
Title and text and nothing else
"""
title = blocks.CharBlock(required=False, help_text="Add yourt title")
text = blocks.TextBlock(required=False, help_text="Add yourt text")
class Meta:
template = "streams/title_and_text_block.html"
icon = "edit"
label = "Title & Text"
class FAQBlock(blocks.StructBlock):
"""
Title and text and nothing else
"""
title = blocks.CharBlock(required=False, help_text="Add yourt title")
text = blocks.RichTextBlock(blank=True)
class Meta:
template = "streams/faq_block.html"
icon = "edit"
label = "FAQ "
class RichTextblock(blocks.RichTextBlock):
"""ㄱ
Richtext with all the features
"""
class Meta:
template = "streams/richtext_block.html"
icon = "doc-full"
label = "Full RichText"
class ImageBlock(blocks.StructBlock):
image = ImageChooserBlock()
class Meta:
template = "streams/image_block.html"
icon = "placeholder"
label = "이미지"
class ManyImageBlock(blocks.StructBlock):
"""
cards with image and text and button(s).
"""
title = blocks.CharBlock(required=True, help_text="add your title")
images = blocks.ListBlock(
blocks.StructBlock(
[
("image", ImageChooserBlock(required=True)),
]
)
)
class Meta:
template = "streams/many_image_block.html"
icon = "placeholder"
label = "ManyImage"
class YoutubeVideoBlock(blocks.StructBlock):
"""
cards with image and text and button(s).
"""
youtube_id = blocks.CharBlock(required=True, help_text="유튜브 video id 입력")
class Meta:
template = "streams/youtube_block.html"
icon = "edit"
label = "youtube video"
그 후 templates폴더 아래에 streams를 생성한 다음 필요한 템플릿들을 생성해주면 되겠습니다. 여기서 한개만 예시를 들겠습니다.
streams/templates/streams/link_block.html
{% load wagtailimages_tags %}
{% if self.is_fixed %}
<style>
#under {
position: fixed;
bottom: 0;
font-weight: bold;
width: 100%;
}
</style>
{% endif %}
<div class="d-grid gap-2" {% if self.is_fixed %}id="under"{% endif %}>
{% if self.is_image %}
{% image self.image original as img %}
<a href="{{ self.link }}">
<img src="{{ img.url }}" class="d-block mh-50 w-100" alt="{{ img.alt }}">
</a>
{% else %}
<a class="btn btn-primary" href="{{ self.link }}" role="button" style="background-color:#393f7b;border-color:#393f7b;">{{ self.button_title }}</a>
{% endif %}
</div>
이렇게 self를 통해 block에 선언해 준 것들을 불러올 수 있습니다. 이제 이런식으로 만들어진 block들을 flex에서 불러오겠습니다.
그리고 wagtail은 views.py가 아닌 models.py에서 대부분 작업을 진행합니다. 마찬가지로 flex앱에서도 models.py에서 진행하겠습니다.
from django.db import models
from wagtail.core.fields import StreamField
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.core.models import Page
from wagtail.images.blocks import ImageChooserBlock
from streams import blocks
# Create your models here.
class FlexPage(Page):
template = "flex/flex_page.html"
subtitle = models.CharField(max_length=100, null=True, blank=True)
content = StreamField(
[
("title_and_text", blocks.TitleAndTextBlock()),
("full_richtext", blocks.RichTextblock()),
("app_button", blocks.AppLinkBlock()),
("image", blocks.ImageBlock()),
("youtube_id", blocks.YoutubeVideoBlock()),
("images", blocks.ManyImageBlock()),
("faq", blocks.FAQBlock()),
],
null=True,
blank=True,
)
content_panels = Page.content_panels + [
FieldPanel("subtitle"),
StreamFieldPanel("content"),
]
class Meta:
verbose_name = "Flex Page"
verbose_name_plural = "Flex Pages"
그 후 flex도 마찬가지로 template에 html을 생성해줘야하는데 block을 자유자재로 사용하게 다음과 같이 생성하면 되겠습니다.
flex/templates/flex/flex_page.html
{% extends "base.html" %}
{% load wagtailcore_tags wagtailimages_tags %}
{% block content %}
{% if self.subtitle %}
<div>
{{ self.subtitle }}
</div>
{% endif %}
{% for block in page.content %}
{% include_block block %}
{% endfor %}
{% endblock %}
이제 makemigrations와 migrate를 통해 적용하겠습니다.
python manage.py makemigrations flex
python manage.py migrate flex
페이지 생성하기
위에 그림과 같이 따라하면 다음과 같이 Flex Page가 생긴 것을 확인할 수 있습니다. 여기서 FlexPage에 들어가면 다음과 같이 편집할 수 있는 공간이 나오는 것을 확인할 수 있습니다.
이런식으로 streamsfields에서 생성한 것들로 자유롭게 편집할 수 있습니다. Content에 있는 항목들은 원하는 만큼 계속 생성할 수 있습니다.
또한 PROMOTE탭에 들어가서 페이지에 링크도 직접 수정할 수 있습니다.
Django Wagtail 결과물
'Django > Django개념' 카테고리의 다른 글
Django multiple DB 문서정리 (0) | 2022.12.19 |
---|---|
django transaction(장고 트랜잭션) (0) | 2022.08.25 |
Django Channel Tutorial Part 1 (0) | 2021.07.28 |
왜 Django에서 PostgreSQL을 DB로 사용할까? (0) | 2020.12.01 |
models.py 살펴보기 (0) | 2020.11.18 |
댓글