Wagtail StreamField는 기존 Django Field와는 다르게 JSON 형식으로 이루어져 있다.
그래서 Django Field 처럼 query문으로 create, add 등을 쓸 수가 없다. StreamField는 Query set을 어떻게 사용해야하는지 알아보자.
참고 사이트
https://docs.wagtail.io/en/stable/topics/streamfield.html#streamfield
1. Models
user_management/models.py
@register_snippet
class UserPyCoin(index.Indexed, ClusterableModel):
user = models.ForeignKey(User, on_delete=models.CASCADE)
py_coin_count = models.IntegerField(default=0, verbose_name="파이코인 총갯수")
py_coin = StreamField(UserPyCoinBlock(), verbose_name="파이코인", blank=True)
panels = [
FieldPanel('user'),
FieldPanel('py_coin_count', widget=CountWidget()),
StreamFieldPanel('py_coin'),
]
일단 사용할 모델에 대해서 살펴보자. user 별로 streamfield인 py_coin을 추가해주고 py_coin의 갯수를 py_coin_count에 추가해주려고 한다. 그렇다면 streamfield인 py_coin이 어떤 구조인지 살펴보자.
user_management/blocks.py
class PyCoinBlock(StructBlock):
coin_explanation = CharBlock(required=False, label="코인 설명")
coin = CoinBlock(required=False, label='코인 개수', default=0)
date = DateBlock(required=True, label='획득 날짜')
coin_explanation은 어떻게 코인을 사용했고 얻었는지 설명을 적어준다.
coin은 얻은 코인의 갯수이다.
date는 coin을 얻은 날짜이다.
2. Ajax 통신
model을 보면 알 수 있듯이 user에게 코인을 적립해주는 기능이다. user가 quiz를 맞추면 ajax통신을 통해 quiz 정보와 갯수를 저장해주려고 한다.
js/card.js
jQuery.ajax({
url: card_page_url + "answer_check/", // 클라이언트가 HTTP 요청을 보낼 서버의 URL 주소
headers:{'X-CSRFToken':card_page_token},
data: {
title : card_page_title,
py_coin : 1,
}, // HTTP 요청과 함께 서버로 보낼 데이터
method: "POST", // HTTP 요청 메소드(GET, POST 등)
dataType: "json" // 서버에서 보내줄 데이터의 타입
}).done(function (data) {
if (data.status=='success') {
alert('성공입니다. 파이 코인이 적립되었습니다.');
}
else {
alert("서버 오류입니다. 새로고침 후 다시 실행해주세요.");
}
}).fail(function () {
alert("서버 오류입니다. 새로고침 후 다시 실행해주세요.");
}).always(function () {
});
Jquery Ajax를 통해 작성하였다. 요즘은 fetch를 사용하기 때문에 추후에 바꿔서 수정할 계획이다.
퀴즈를 맞추게 되면 Ajax의 POST를 통해서 서버와 통신하려고 한다.
3. StreamField Query Set
card/models.py
@route(r'^answer_check/$', name='answer_check')
def answer_check(self, request):
if request.method == 'POST' and request.is_ajax():
page_title = request.POST.get('title')
py_coin = request.POST.get('py_coin')
add_pycoin = [
('py_coin',{
'coin_explanation' : page_title,
'date' : timezone.localdate(),
'coin' : py_coin
},)
]
instance_user = UserPyCoin.objects.get(user=request.user)
instance_user.py_coin_count += int(py_coin)
instance_user.py_coin.append(add_pycoin[0])
instance_user.save()
return HttpResponse(json.dumps({'status':'success'}), content_type="application/json")
Wagtail이라서 route를 통해서 Ajax 통신을 구현하였다. 앞서 얘기 했던 것 처럼 StreamField는 JSON 형태의 데이터이다. 먼저 어떻게 데이터가 저장되어 있는지 데이터베이스를 통해서 확인해보자.
StreamField는 JSON 형식인 것을 확인 할 수 있다.
구조를 보자면
type, value, id 값으로 나누어져 있고 type에는 StreamField의 변수명 (py_coin), value는 각 변수의 값이 JSON 형식으로 저장되어 있고 id 값은 block의 고유 값이다.
우리는 type과 value만 추가해주면 된다. (아이디 값을 wagtail에서 자동으로 추가)
Python에서 저장해줄 때는 append를 통해 추가해주면 된다. 그리고 JSON형식은 튜플과 딕셔너리를 통해서 작성해주면 된다.
add_pycoin = [
('py_coin',{
'coin_explanation' : page_title,
'date' : timezone.localdate(),
'coin' : py_coin
},)
]
type을 정의해주기 위해 'py_coin'을 작성하였다. 그리고 실제 데이터에는 JSON을 형식에 맞게 딕셔너리로 작성하였다.
그리고 add_pycoin은 리스트 형식이기 때문에 첫번 째 데이터를 append 한다는 의미로 [0]을 붙여주면 된다.
instance_user.py_coin.append(add_pycoin[0])
이제 데이터베이스에 가서 확인하면 정상적으로 저장되는 것을 확인할 수 있다.
추가)
삭제
del instance_user.py_coin[-1]
삭제를 하고 싶다면 위와 같이 작성을 해주면 된다. JSON형식의 데이터로 List안에 저장되므로 파이썬 List와 같게 데이터를 제어하면 될 것이다.
수정
instance_user.py_coin[0] = ('heading', "My story")
코드 수정은 직접 리스트 번호로 접근해서 수정해야한다.
instance_user.py_coin[0]를 출력해보면 아래와 같이 나타난다.
<dl>
<dt>coin_explanation</dt>
<dd>코인입니다.</dd>
<dt>coin</dt>
<dd>1</dd>
<dt>date</dt>
<dd>2021-10-26</dd>
</dl>
그렇다면 데이터를 접근하려면 어떻게 해야할까?
page.body[0].block_type and page.body[0].value
위와 같이 접근할 수 있다. 다만 데이터의 직접 접근은 불가능하다고 한다. (tuple값이라서 바꿀 수가 없음)
'Back-End > Wagtail, Django' 카테고리의 다른 글
Wagtail Ajax (0) | 2021.10.29 |
---|---|
Wagtail Custom Admin Menu (0) | 2021.10.28 |
알아두면 좋을 것들 (0) | 2021.10.22 |
Wagtail StyleGuide + 추가 모듈 (0) | 2021.10.18 |
Wagtail Iamport 결제, 결제 페이지 (0) | 2021.10.14 |