책 '점프 투 플라스크'를 공부하면서 정리한 내용입니다.
출처 : https://wikidocs.net/book/4542
웹 페이지에 디자인을 적용하기 위해 CSS를 사용한다. CSS를 파이보에 적용하려면 CSS 파일이 pybo/static 디렉토리에 있어야 한다. 이때 CSS 파일은 플라스크에서 정적(static) 파일로 분류한다. 정적 파일은 주로 이미지(.png, .jpg)나 자바스크립트(.js), 스타일시트(.css)와 같은 파일을 의미한다.
정적 파일을 저장할 디렉토리는 템플릿 디렉토리와 마찬가지로 플라스크가 앱으로 지정한 모듈 아래에 static이라는 이름으로 생성하면 된다. 우리가 사용한 플라스크 앱은 pybo 모듈이므로 pybo 디렉토리 아래에 static 디렉토리를 생성한다.
그 후 style.css 파일을 작성한다. 답변을 등록할 때 사용하는 텍스트 창(textarea)의 너비를 100%로 넓히고(웹 브라우저 너비 기준), <답변등록> 버튼 위에 마진을 10px 추가한다.
textarea {
width:100%;
}
input[type=submit] {
margin-top:10px;
}
스타일시트를 질문 상세 조회 템플릿에 적용하기 위해 question_detail.html 파일에 다음 코드를 추가한다.
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
부트스트랩 설치 후 bootstrap.min.css 파일만 복사해서 pybo/static 디렉터리에 저장
질문 목록 조회 템플릿에 부트스트랩 적용
question_list.html 파일 맨 위에 있는 bootstrap.min.css 파일을 연결하는 것을 시작으로 전체를 수정해야 한다.
<link rel="stylesheet" \
href="{{ url_for('static', filename='bootstrap.min.css') }}">
<div class="container my-3">
<table class="table">
<thead>
<tr class="thead-dark">
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
{% if question_list %}
{% for question in question_list %}
<tr>
<td>{{ loop.index }}</td>
<td>
<a href="{{ url_for('question.detail', \
question_id=question.id) }}">{{ question.subject }}</a>
</td>
<td>{{ question.create_date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">질문이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
ul 엘리먼트로 표시한 기존 질문 목록을 table 엘리먼트로 표현하고, table 엘리먼트와 하위 엘리먼트에 부트스트랩을 적용했다. (부트스트랩이 제공하는 클래스 이용)
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap.min.css') }}">
<div class="container my-3">
<h2 class="border-bottom py-2">{{ question.subject }}</h2>
<div class="card my-3">
<div class="card-body">
<div class="card-text" style="white-space: pre-line;">{{ question.content }}</div>
<div class="d-flex justify-content-end">
<div class="badge badge-light p-2">
{{ question.create_date }}
</div>
</div>
</div>
</div>
<h5 class="border-bottom my-3 py-2">{{ question.answer_set|length }}개의 답변이 있습니다.</h5>
{% for answer in question.answer_set %}
<div class="card my-3">
<div class="card-body">
<div class="card-text" style="white-space: pre-line;">{{ answer.content }}</div>
<div class="d-flex justify-content-end">
<div class="badge badge-light p-2">
{{ answer.create_date }}
</div>
</div>
</div>
</div>
{% endfor %}
<form action="{{ url_for('answer.create', question_id=question.id) }}" method="post" class="my-3">
<div class="form-group">
<textarea name="content" id="content" class="form-control" rows="10"></textarea>
</div>
<input type="submit" value="답변등록" class="btn btn-primary">
</form>
</div>
질문과 답변은 부트스트랩의 card 컴포넌트를 이용해 카드에 담았다. card 컴포넌트는 게시물 1개를 담기에 적절하다.
지금까지 작성한 템플릿 파일은 표준 HTML 구조가 아니다. 어떤 운영체제나 브라우저를 사용하더라도 웹 페이지가 동일하게 보이고 정상적으로 동작하게 하려면 반드시 웹 표준을 지키는 HTML 문서를 작성해야 한다.
html, head, bodoy 엘리먼트가 있어야 하고 CSS 파일은 head 엘리먼트 안에 있어야 한다. 또한 head 엘리먼트 안에는 meta, title 엘리먼트 등이 포함되어야 한다.
모든 템플릿 파일을 앞에서 본 표준 HTML 구조로 변경하면 body 엘리먼트 바깥 부분은 모두 같은 내용이 중복되고, CSS 파일 이름이 변경되거나 추가되면 head 엘리먼트으 ㅣ내용을 수정하려고 일일히 찾아다녀야 하는 불편함이 있다.
플라스크에서는 이런 불편함을 해소하기 위해 템플릿 상속(extends) 기능을 제공한다. 단순히 템플릿을 표준 HTML 구조로 바꿀 뿐 아니라 템플릿 상속 기능까지 사용한다.
<!doctype html>
<html lang="ko">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap.min.css') }}">
<!-- pybo CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>Hello, pybo!</title>
</head>
<body>
<!-- 기본 템플릿 안에 삽입될 내용 Start -->
{% block content %}
{% endblock %}
<!-- 기본 템플릿 안에 삽입될 내용 End -->
</body>
</html>
body 엘리먼트에 {% block content %}와 {% endblock %} 템플릿 태그 부분이 base.html 템플릿 파일을 상속한 파일에서 구현할 영역이다.
{% extends 'base.html' %}
{% block content %}
(... 생략 ...)
{% endblock %}
기존 코드 생략