CMS는 Content Management System의 약자이다. 기존 블로그에 소개한 Wagtail 화면 구현방법은 FrontEnd와 BackEnd가 분리 되지 않아 FrontEnd에서 데이터를 표현할 때에는 HTML에 템플릿 언어를 통해 구현했다.
하지만, 개발 규모가 커져서 FrontEnd개발자와 BackEnd 개발자가 따로 있게 된다면 FrontEnd 개발자도 템플릿 언어와 BackEnd에 대해서 알아야 하는 문제가 생긴다. FrontEnd와 BackEnd가 분리되지 않는 것이다. 스마트폰 APP으로도 서비스를 출시하고 싶을 때에도 문제가 생긴다. 데이터의 표현 방법이 전부 다르기 때문이다.
그래서 나온 것이 API이다. BackEnd에서는 API서버로 데이터를 보내주고 API서버를 통해 FrontEnd에서 필요한 데이터만 가져와서 사용하는 것이다. 이렇게 되면 BackEnd와 FrontEnd가 분리되어 개발 능률이 향상된다. 그렇다면 지금부터 Wagtail에서 API를 사용하는 방법에 대해서 알아보자.
Wagtail에서는 API v2를 사용한다. 기본적으로 Wagtail은 Django 기반이기 때문에 Django RestFrameWork도 필요하다.
from wagtail.api.v2.views import PagesAPIViewSet
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.images.api.v2.views import ImagesAPIViewSet
from wagtail.documents.api.v2.views import DocumentsAPIViewSet
# Create the router. "wagtailapi" is the URL namespace
api_router = WagtailAPIRouter('wagtailapi')
# Add the three endpoints using the "register_endpoint" method.
# The first parameter is the name of the endpoint (eg. pages, images). This
# is used in the URL of the endpoint
# The second parameter is the endpoint class that handles the requests
api_router.register_endpoint('pages', PagesAPIViewSet)
api_router.register_endpoint('images', ImagesAPIViewSet)
api_router.register_endpoint('documents', DocumentsAPIViewSet)
위의 코드에서 PagesAPIViewSet은 Wagtail에서 우리가 작성한 모든 Page의 Set이다. 그리고 앞에 'pages'는 이곳을 경로로 들어가겠다는 의미이다. 즉, 127.0.0.1:8000/api/v2/pages/ 로 접속하면 pages의 Set을 볼 수 있다. 그리고 'pages'말고 'pages-set'같은 이름으로 바꾸었을 때에는 'pages'대신 'pages-set'으로 접속하면 된다.
특정한 page의 정보가 보고 싶다면 끝에 page의 id 를 추가 해주면된다. 기본적으로 127.0.0.1:8000/api/v2/pages/3/는 홈페이지 이다.
추가) Site port Setting
Wagtail Site에 들어가보면 Port가 80으로 되어 있을 것이다. 8000으로 바꿔주자.
Navigation Bar나 Footer에 표시된 Menu를 누르면 관련 링크로 이동하는 것인데,
하드 코딩없이 서버에서 Data로 관리하는 방법이다.
새로운 menus App을 만들어서 진행했다.
1. Models.py
"""Menus models"""
from django.db import models
from django_extensions.db.fields import AutoSlugField
from wagtail.admin.edit_handlers import (
MultiFieldPanel,
InlinePanel,
FieldPanel,
PageChooserPanel,
)
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from wagtail.snippets.models import register_snippet
from wagtail.core.models import Orderable
class MenuItem(Orderable):
link_title = models.CharField(
blank=True,
null=True,
max_length=50,
)
link_url = models.CharField(
max_length=500,
blank=True,
)
link_page = models.ForeignKey(
"wagtailcore.Page",
null=True,
blank=True,
related_name="+",
on_delete=models.CASCADE,
)
open_in_new_tab = models.BooleanField(default=False, blank=True)
page = ParentalKey("Menu", related_name="menu_items")
panels = [
FieldPanel("link_title"),
FieldPanel("link_url"),
PageChooserPanel("link_page"),
FieldPanel("open_in_new_tab"),
]
@property
def link(self) -> str:
if self.link_page:
return self.link_page.url
elif self.link_url:
return self.link_url
return '#'
@property
def title(self):
if self.link_page and not self.link_title:
return self.link_page.title
elif self.link_title:
return self.link_title
return "Missing Title"
@register_snippet
class Menu(ClusterableModel):
"""The main menu clusterable model."""
title = models.CharField(max_length=100)
slug = AutoSlugField(populate_from="title", editable=True)
panels = [
MultiFieldPanel(
[
FieldPanel("title"),
FieldPanel("slug"),
], heading="Menu",
),
InlinePanel("menu_items", label="Menu Item")
]
def __str__(self):
return self.title
Model은 Orderable과 ClusterableModel 2개를 만들어주었다. 간단하게 설명하자면 Orderable은 순서배치가 가능한 모델을 말하고 Clusterable은 나열가능한 모델을 갖는 모델을 말한다. 즉, Clusterable을 순서배치가 가능한 Orderable 모델을 가질 수 있다.
@property를 통해 link title과 link url을 리턴해주었다.
def에 -> str을 사용하면 리턴값이 문자열이 된다.
django_extensions에 AutoSlugField가 있다.
title = models.CharField(max_length=100)
slug = AutoSlugField(populate_from="title", editable=True)
populate_form에 slug로 변환할 변수를 넣으면 자동으로 slug를 만들어준다. 수정가능하게 하고 싶다면 eidtable값을 True로 해준다.
2. menus_tags.py
menus/templatetags/menus_tags.py
from django import template
from ..models import Menu
register = template.Library()
@register.simple_tag()
def get_menu(slug):
return Menu.objects.get(slug=slug)
Custom Template tag 기능을 사용하여 get_menu라는 이름의 함수를 만들어준다.
template에서 get_menu를 호출하면 Menu objects에서 slug 값이 같은 객체를 찾아서 리턴해준다.
3. Template
admin 페이지에서 snippets에 있는 Menu로 이동해서 Main Nav라는 title의 모델을 하나 만들어준다.
base.html
{% load menus_tags %}
{% get_menu "main-nav" as navigation %}
{% for item in navigation.menu_items.all %}
<li class="nav-item">
<a class="nav-link" href="{{ item.link }}"{% if item.open_in_new_tab %} target="_blank"{% endif %}>{{ item.title }}</a>
</li>
{% endfor %}
main-nav의 변수를 slug로 get_menu 함수에 전달해서 return 값을 받아 navigation이라는 template 변수로 받는다.