Custom Widget을 작성하는 방법에 대해서 기술하려고 한다.
아무리 찾아봐도 나오지 않아 그냥 생각대로 해봤더니 성공했다.
Wagtail에서 Codemirror Widget을 만들고 적용하는 방법으로 해결 했다.
1. Widget 만들기
myapp/widgets.py
from django.forms import widgets
from wagtail.utils.widgets import WidgetWithScript
#custom widget 적용
class MyCustomWidget(WidgetWithScript, widgets.Textarea):
template_name = 'widgets/codingwidget.html'
def __init__(self, attrs=None):
default_attrs = {}
if attrs:
default_attrs.update(attrs)
super().__init__(default_attrs)
class Media:
js = ('test.js',)
Codemirror를 적용하기 위해서는 Textarea가 필요하므로 django widget에서 textarea.html을 가져와야 한다.
(widget만드는 방법은 wagtail 자체에서 widget 만드는 부분을 참고하여 작성해보았다.)
default_attrs는 정의 할 attrs값을 적어주면 되는데 id값은 정의가 불가능 하다. (wagtail에서 widget을 구별할 때 id값으로 구별하기 때문에 그렇다.)
ex) default_attrs = {'class':'test'} 이런식으로 태그의 속성 값을 정의 해줄 수가 있다.
template_name에서는 사용할 widget template을 적어주면된다.
2. 사용할 Widget 가져오기
django/forms/widgets/textarea.html
<textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
code mirror에서는 textarea가 필요하기 때문에 textarea widget을 가져왔다.
(다른 widget이 필요하다면 django widget공식문서를 확인하거나 wagtail이나 django widget에서 찾아보자!)
textarea.html을 그대로 복사해서 우리가 새로 만들 widget html에 붙여넣는다.
templates/widgets/codingwidget.html
<textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById('{{ widget.attrs.id }}'), {
mode: "python",
theme: "dracula",
lineNumbers: true,
});
editor.setSize("100%","100%");
</script>
그리고 필요한 css나 js를 작성해 주면 된다.
Codemirror javascript를 작성하였다. textarea의 id값이 필요한데 widget의 정보는 {{ widget }}을 통해 확인할 수 있다.
{'name': 'mtf-0-testfield', 'is_hidden': False, 'required': False, 'value': 'ddd', 'attrs': {'cols': '40', 'rows': '10', 'id': 'id_mtf-0-testfield'}, 'template_name': 'widgets/codingwidget.html'}
내가 작성한 widget에서는 위와 같은 정보가 있었다. 접근 방법은 {{ widget.name }} 이런방법으로 접근하면 되는데
attrs는 {{ widget.attrs.id }}와 같이 한번 더 접근해주면 된다. 이걸로 우리는 codemirror 적용에 필요한 id값을 얻을 수가 있다.
JS, CSS 추가방법
Widget에 JS파일이나 CSS 추가하고 싶다면 Custom Widget에 Midea를 설정해주면 된다.
class Media:
js = ('test.js',)
주의)
'test.js'하고 뒤에 , 를 꼭 붙여야한다. 그래야지 'test.js'를 하나의 문자열로 인식하고 가져올 수 있다.
3. Widget 적용 하기
myapp/models.py
class MytestRelated(Orderable):
page = ParentalKey('CardPage', on_delete=models.CASCADE, related_name='mtf')
testfield = models.TextField(null=True, blank=True)
panels = [
FieldPanel('testfield', widget=MyCustomWidget())
]
나는 Inlinepanel을 통해 여러개의 codemirror 필드를 사용하려고 ParentalKey를 사용하였다.
(필드 하나만 필요하다면 그냥 Page 모델에 필드를 정의하고 FieldPanel에 widget을 우리가 만든 widget을 적어주면된다.)
CardPage라는 Page모델에 추가시켜보겠다.
class CardPage(Page):
content_panels = Page.content_panels + [
InlinePanel('mtf', label="test"),
]
4. 결과
정상적으로 적용되어 있는 codemirror widget을 확인할 수 있다.
추가) Inline으로 작성된 필드들을 html에서 표현해보자.
ParentalKey로 정의되어 있으므로 따로 return 값을 정의해주어야 한다. CardPage 맨 아래에 추가시켜보자.
@property
def codes(self):
codes = [n.testfield for n in self.mtf.all()]
return codes
이렇게 되면 html에서 page.codes로 가져올 수 있다.
card_page.html
{% for code in page.codes %}
{{ code }}
{% endfor %}
번외) custom model 작성방법
모델을 custom 해서 새로 작성할 경우가 생긴다. 이럴경우 다음과 같이 model을 custom 하면 된다.
class MytestField(models.Model):
testfield = models.TextField(null=True, blank=True)
panels = [
FieldPanel('testfield', widget=MyCustomWidget())
]
class Meta:
abstract = True
'Back-End > Wagtail, Django' 카테고리의 다른 글
Wagtail 중복 로그인 방지 (Django사용) (0) | 2021.10.06 |
---|---|
Wagtail Video (0) | 2021.10.01 |
Wagtail Custom Field, Panel (0) | 2021.09.29 |
Wagtail hooks로 RichTextField에 구글 폰트 적용 (0) | 2021.09.19 |
Wagtail Custom Block Field 만들기 (0) | 2021.09.19 |