편집 인터페이스 사용자 정의¶
탭 인터페이스 사용자 정의¶
표준으로 Wagtail은 페이지용 패널을 ‘콘텐츠’와 ‘홍보’라는 두 개의 탭으로 구성합니다. 스니펫의 경우 Wagtail은 모든 패널을 한 페이지에 넣습니다. 사이트의 요구 사항에 따라 특정 페이지 유형이나 스니펫에 대해 이를 사용자 정의할 수 있습니다. 예를 들어 사이드바 콘텐츠에 대한 추가 탭을 추가할 수 있습니다. 이는 페이지 또는 스니펫 모델에 edit_handler 속성을 지정하여 수행할 수 있습니다. 예를 들어:
from wagtail.admin.panels import TabbedInterface, TitleFieldPanel, ObjectList
class BlogPage(Page):
# 필드 정의 생략
content_panels = [
TitleFieldPanel('title', classname="title"),
FieldPanel('date'),
FieldPanel('body'),
]
sidebar_content_panels = [
FieldPanel('advert'),
InlinePanel('related_links', heading="관련 링크", label="관련 링크"),
]
edit_handler = TabbedInterface([
ObjectList(content_panels, heading='콘텐츠'),
ObjectList(sidebar_content_panels, heading='사이드바 콘텐츠'),
ObjectList(Page.promote_panels, heading='홍보'),
ObjectList(Page.settings_panels, heading='설정'), # 기본 설정은 이제 사이드바에 표시되지만 `TabbedInterface` 에 있어야 합니다.
])
ObjectList 에서 permission 을 사용하여 권한을 설정하여 전체 패널 그룹을 특정 사용자로 제한할 수 있습니다.
from wagtail.admin.panels import TabbedInterface, TitleFieldPanel, ObjectList
class FundingPage(Page):
# 필드 정의 생략
shared_panels = [
TitleFieldPanel('title', classname="title"),
FieldPanel('date'),
FieldPanel('body'),
]
private_panels = [
FieldPanel('approval'),
]
edit_handler = TabbedInterface([
ObjectList(shared_panels, heading='세부 정보'),
ObjectList(private_panels, heading='관리자 전용', permission="superuser"),
ObjectList(Page.promote_panels, heading='홍보'),
ObjectList(Page.settings_panels, heading='설정'), # 기본 설정은 이제 사이드바에 표시되지만 `TabbedInterface` 에 있어야 합니다.
])
Panel 및 PanelGroup 클래스 작업에 대한 자세한 내용은 패널를 참조하십시오.
서식 있는 텍스트(HTML)¶
Wagtail은 서식 있는 텍스트 콘텐츠(HTML)를 만들고 이미지, 비디오, 문서와 같은 미디어를 포함하기 위한 범용 WYSIWYG 편집기를 제공합니다. 모델에 이를 포함하려면 모델 필드를 정의할 때 RichTextField 함수를 사용하십시오.
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel
class BookPage(Page):
body = RichTextField()
content_panels = Page.content_panels + [
FieldPanel('body'),
]
RichTextField 는 Django의 기본 TextField 필드에서 상속되므로 일반 Django 필드를 사용하는 것처럼 모든 필드 매개변수를 RichTextField 에 전달할 수 있습니다. 이 필드는 특수 패널이 필요하지 않으며 FieldPanel 로 정의할 수 있습니다. 그러나 RichTextField 의 템플릿 출력은 특수하며 포함된 콘텐츠를 보존하기 위해 필터링해야 합니다. 리치 텍스트 (필터)를 참조하십시오.
max_length 가 지정되면 길이 유효성 검사는 서식 있는 텍스트 서식을 자동으로 무시합니다. 동일한 방식으로 최소 길이를 적용하려면 validators 인수의 일부로 wagtail.rich_text.RichTextMinLengthValidator 인스턴스를 전달하십시오.
서식 있는 텍스트 필드의 기능 제한¶
기본적으로 서식 있는 텍스트 편집기는 사용자에게 텍스트 서식 지정 및 이미지와 같은 포함된 콘텐츠 삽입을 위한 다양한 옵션을 제공합니다. 그러나 서식 있는 텍스트 필드를 더 제한된 기능 집합으로 제한하고 싶을 수 있습니다. 예를 들어:
필드는 색인 페이지에서 가져올 요약과 같은 짧은 텍스트 스니펫을 위한 것일 수 있으며, 여기서 포함된 이미지나 비디오는 부적절할 수 있습니다.
페이지 콘텐츠가 StreamField를 사용하여 정의될 때 제목, 이미지, 비디오와 같은 요소는 일반적으로 일반 단락 텍스트에 사용되는 서식 있는 텍스트 블록 유형과 함께 자체 블록 유형이 지정됩니다. 이 경우 서식 있는 텍스트 콘텐츠 내에 제목과 이미지가 존재하도록 허용하는 것은 중복됩니다(그리고 일관성 없는 디자인을 초래할 수 있음).
이는 허용하려는 기능에 대한 식별자 목록과 함께 features 키워드 인수를 RichTextField 에 전달하여 달성할 수 있습니다.
body = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link'])
기본 Wagtail 설치에서 제공되는 기능 식별자는 다음과 같습니다.
h2,h3,h4- 제목 요소bold,italic- 굵게/기울임꼴 텍스트ol,ul- 순서 있는/순서 없는 목록hr- 가로줄link- 페이지, 외부 및 이메일 링크document-link- 문서 링크image- 포함된 이미지embed- 포함된 미디어( 임베디드 콘텐츠 참조)
몇 가지 추가 기능 식별자도 있습니다. 기본적으로 활성화되어 있지는 않지만 식별자 목록에서 사용할 수 있습니다. 다음과 같습니다.
h1,h5,h6- 제목 요소code- 인라인 코드superscript,subscript,strikethrough- 텍스트 서식blockquote- 인용문
새 기능을 만드는 프로세스는 다음 페이지에 설명되어 있습니다.
서식 있는 텍스트 기능 그룹의 이름을 지정하기 위한 설정을 제공할 수도 있습니다. WAGTAILADMIN_RICH_TEXT_EDITORS를 참조하십시오.
서식 있는 텍스트 편집기의 이미지 형식¶
로드 시 Wagtail은 image_formats.py 파일이 있는 모든 앱을 검색하고 내용을 실행합니다. 이는 RichTextField 편집기에서 이미지를 삽입할 때 편집기에게 표시되는 서식 옵션을 사용자 정의하는 방법을 제공합니다.
예를 들어 “thumbnail” 형식을 추가합니다.
# image_formats.py
from wagtail.images.formats import Format, register_image_format
register_image_format(Format('thumbnail', 'Thumbnail', 'richtext-image thumbnail', 'max-120x120'))
시작하려면 Format 클래스, register_image_format 함수 및 선택적으로 unregister_image_format 함수를 가져옵니다. 새 Format 을 등록하려면 Format 개체를 인수로 사용하여 register_image_format 을 호출합니다. Format 클래스는 다음 생성자 인수를 사용합니다.
name
형식을 식별하는 데 사용되는 고유 키입니다. 이 형식을 등록 취소하려면 이 문자열을 유일한 인수로 사용하여 unregister_image_format 을 호출합니다.
label
RichTextField 에 이미지를 삽입할 때 선택기 양식에 사용되는 레이블입니다.
classname
생성된 <img> 태그의 class 속성에 할당할 문자열입니다.
참고
제공하는 모든 클래스 이름에는 프런트엔드 CSS 코드의 일부로 별도로 작성된 CSS 규칙이 일치해야 합니다. classname 값을 left 로 지정하면 생성된 마크업에서 해당 클래스가 출력되도록만 보장되며 이미지가 왼쪽으로 정렬되지는 않습니다.
filter_spec
이미지 변환을 만드는 문자열 사양입니다. 자세한 내용은 템플릿에서 이미지 사용하는 방법를 참조하십시오.
등록을 취소하려면 Format 의 name 문자열을 유일한 인수로 사용하여 unregister_image_format 을 호출합니다.
경고
Format 개체를 등록 취소하면 이를 참조하는 페이지를 보거나 편집할 때 오류가 발생합니다.
날짜 필드 유효성 검사¶
NoFutureDateValidator 는 사용자가 미래 날짜를 입력하는 것을 방지합니다. 이는 다음과 같이 과거 또는 현재 날짜만 포함해야 하는 필드에 특히 유용합니다.
생년월일
역사적 사건 날짜
이미 게시된 콘텐츠의 게시 날짜
완료된 프로젝트의 완료 날짜
from django.db import models
from wagtail.fields import NoFutureDateValidator
from wagtail.admin.panels import FieldPanel
from wagtail.models import Page
class EventPage(Page):
event_date = models.DateField(
validators=[NoFutureDateValidator()],
help_text="이 이벤트가 발생한 날짜"
)
birth_date = models.DateField(
validators=[NoFutureDateValidator("생년월일은 미래 날짜일 수 없습니다.")],
help_text="사람의 생년월일"
)
content_panels = Page.content_panels + [
FieldPanel('event_date'),
FieldPanel('birth_date'),
]
유효성 검사기는 선택적 사용자 정의 오류 메시지도 허용합니다.
# 기본 메시지 사용: "날짜는 미래 날짜일 수 없습니다."
event_date = models.DateField(validators=[NoFutureDateValidator()])
# 사용자 정의 메시지 사용
birth_date = models.DateField(
validators=[NoFutureDateValidator("유효한 생년월일을 입력하십시오.")]
)
입력한 날짜가 오늘 날짜 이후이면 유효성 검사기에서 유효성 검사 오류가 발생합니다.
생성된 양식 사용자 정의¶
- class wagtail.admin.forms.WagtailAdminModelForm¶
- class wagtail.admin.forms.WagtailAdminPageForm¶
Wagtail은 모델에 구성된 패널을 사용하여 양식을 자동으로 생성합니다.
기본적으로 이 양식은 페이지의 경우 WagtailAdminModelForm 또는 WagtailAdminPageForm을 하위 클래스로 지정합니다.
사용자 정의 기본 양식 클래스는 모든 모델에서 base_form_class 속성을 설정하여 구성할 수 있습니다.
스니펫에 대한 사용자 정의 양식은 WagtailAdminModelForm을 하위 클래스로 지정해야 하며,
페이지에 대한 사용자 정의 양식은 WagtailAdminPageForm을 하위 클래스로 지정해야 합니다.
이를 사용하여 양식에 비모델 필드를 추가하거나, 필드 콘텐츠를 자동으로 생성하거나, 모델에 대한 사용자 정의 유효성 검사 논리를 추가할 수 있습니다.
from django import forms
from django.db import models
import geocoder # Wagtail에 없음, 예시용 - https://geocoder.readthedocs.io/
from wagtail.admin.panels import TitleFieldPanel, FieldPanel
from wagtail.admin.forms import WagtailAdminPageForm
from wagtail.models import Page
class EventPageForm(WagtailAdminPageForm):
address = forms.CharField()
def clean(self):
cleaned_data = super().clean()
# 이벤트가 끝나기 전에 시작하는지 확인
start_date = cleaned_data['start_date']
end_date = cleaned_data['end_date']
if start_date and end_date and start_date > end_date:
self.add_error('end_date', '종료 날짜는 시작 날짜 이후여야 합니다.')
return cleaned_data
def save(self, commit=True):
page = super().save(commit=False)
# 제출된 날짜에서 기간 필드 업데이트
page.duration = (page.end_date - page.start_date).days
# 주소를 지오코딩하여 위치 가져오기
page.location = geocoder.arcgis(self.cleaned_data['address'])
if commit:
page.save()
return page
class EventPage(Page):
start_date = models.DateField()
end_date = models.DateField()
duration = models.IntegerField()
location = models.CharField(max_length=255)
content_panels = [
TitleFieldPanel('title'),
FieldPanel('start_date'),
FieldPanel('end_date'),
FieldPanel('address'),
]
base_form_class = EventPageForm
Wagtail은 이 양식의 새 하위 클래스를 모델에 대해 생성하여
panels 또는 content_panels 에 정의된 모든 필드를 추가합니다.
모델에 이미 정의된 모든 필드는 이러한 자동으로 추가된 필드로 재정의되지 않으므로
모델 필드에 대한 양식 필드는 사용자 정의 양식에 추가하여 재정의할 수 있습니다.
생성된 복사 페이지 양식 사용자 정의¶
- class wagtail.admin.forms.CopyForm¶
페이지를 복사할 때 Wagtail은 사용자가 복사된 페이지를 수정할 수 있도록 양식을 생성합니다. 기본적으로 이 양식은 CopyForm을 하위 클래스로 지정합니다. 사용자 정의 기본 양식 클래스는 모든 모델에서 copy_form_class 속성을 설정하여 구성할 수 있습니다. 사용자 정의 양식은 CopyForm을 하위 클래스로 지정해야 합니다.
이를 사용하여 모델별로 복사된 양식에 대한 변경 사항을 지정할 수 있습니다.
예를 들어 슬러그 필드를 자동으로 증가시킵니다.
from django import forms
from django.db import models
from wagtail.admin.forms.pages import CopyForm
from wagtail.admin.panels import FieldPanel
from wagtail.models import Page
class CustomCopyForm(CopyForm):
def __init__(self, *args, **kwargs):
"""
슬러그를 자동으로 증가시키기 위해 기본 복사 양식을 재정의합니다.
"""
super().__init__(*args, **kwargs)
suffix = 2 # 초기 슬러그를 증가된 슬러그로 설정
parent_page = self.page.get_parent()
if self.page.slug:
try:
suffix = int(self.page.slug[-1])+1
base_slug = self.page.slug[:-2]
except ValueError:
base_slug = self.page.slug
new_slug = base_slug + f"-{suffix}"
while not Page._slug_is_available(new_slug, parent_page):
suffix += 1
new_slug = f"{base_slug}-{suffix}"
self.fields["new_slug"].initial = new_slug
class BlogPage(Page):
copy_form_class = CustomCopyForm # 모든 EventPage 모델에 대한 사용자 정의 복사 양식 설정
introduction = models.TextField(blank=True)
body = RichTextField()
content_panels = Page.content_panels + [
FieldPanel('introduction'),
FieldPanel('body'),
]