Chapter 6-2 Bootstrap 적용으로 블로그 UI 개선하기

2025. 5. 9. 10:05·Django

💻 Chapter 06. Bootstrap 적용으로 블로그 UI 개선하기


🎯 목표

Django 블로그 프로젝트에 Bootstrap 5를 적용하여 UI/UX를 대폭 개선합니다. 네비게이션 바, 버튼, 리스트, 폼 등 전체적인 구조를 리팩토링합니다.


1️⃣ base.html에 Bootstrap 적용

✅ 흐름 설명

  1. 모든 페이지의 기본 레이아웃이 되는 base.html에서 Bootstrap CSS와 JS를 불러옵니다.
  2. 네비게이션 바에 Bootstrap 클래스(d-flex, bg-black, text-white)를 적용하여 스타일을 통일합니다.
  3. 인증 상태에 따라 로그인/로그아웃 버튼을 다르게 표시하며, 버튼에 btn btn-sm 클래스를 지정합니다.
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>블로그 프로젝트</title>
  <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
</head>
<body>
  <nav class="d-flex justify-content-between py-2 px-4 bg-black text-white">
    <div>
      <a class="text-decoration-none text-white" href="{% url 'blog:list' %}">홈</a>
    </div>
    <div style="text-align: right">
      {% if request.user.is_authenticated %}
        <form action="{% url 'logout' %}" method="POST" class="d-inline">
          {% csrf_token %}
          <button class="btn btn-danger btn-sm">로그아웃</button>
        </form>
        {{ request.user.username }}
      {% else %}
        <a href="{% url 'signup' %}">회원가입</a>
        <a href="{% url 'login' %}">로그인</a>
      {% endif %}
    </div>
  </nav>
  <div class="container">
    {% block content %}{% endblock %}
  </div>
  <script src="{% static 'js/bootstrap.bundle.js' %}"></script>
  {% block js %}{% endblock %}
</body>
</html>

2️⃣ 블로그 목록 페이지 (blog_list.html)

✅ 흐름 설명

  1. 블로그 목록을 object_list 반복문으로 출력
  2. 각 글 제목을 link-primary 스타일로 링크
  3. 생성 버튼은 btn btn-sm btn-primary, 검색은 form-control-sm 사용
  4. 페이지네이션에 Bootstrap의 pagination, page-item, page-link 적용
<div class="mt-2">
  <h1 class="d-inline">블로그 목록</h1>
  <a href="{% url 'blog:create' %}" class="float-end btn btn-sm btn-primary">생성</a>
</div>
<hr>

{% for blog in object_list %}
        <div class="my-1">
            <a href="{% url 'blog:detail' blog.pk %}" class="link-primary link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover">
                [{{ blog.get_category_display }}] {{ blog.title }} - <small>{{ blog.created_at|date:"Y-m-d" }}</small>
            </a>
        </div>
{% endfor %}

<form method="get" class="my-3 d-flex">
  <input class="form-control-sm" name="q" type="text" placeholder="검색어 입력" value="{{ request.GET.q }}">
  <button class="btn btn-sm btn-info ms-2">검색</button>
</form>

<ul class="pagination">
  <!-- 페이지네이션 버튼 구성 (이전/다음/현재 페이지) -->
</ul>

3️⃣ 블로그 상세 페이지 (blog_detail.html)

✅ 흐름 설명

  1. 제목과 작성자 정보 출력
  2. 작성자 본인 또는 관리자일 경우 수정/삭제 버튼 노출
  3. 삭제 버튼은 자바스크립트 confirm() 확인창을 통해 제출
<div class="mt-2 d-flex justify-content-between">
  <h1>{{ blog.title }}</h1>
  {% if request.user == blog.author or request.user.is_superuser %}
    <div>
      <a class="btn btn-sm btn-warning" href="{% url 'blog:update' blog.pk %}">수정</a>
      <form id="delete_form" action="{% url 'blog:delete' blog.pk %}" method="POST" style="display: inline">
        {% csrf_token %}
        <button type="button" id="delete_btn" class="btn btn-sm btn-danger">삭제</button>
      </form>
    </div>
  {% endif %}
</div>
<hr>
<p>{{ blog.content }}</p>
<a class="btn btn-sm btn-info" href="{% url 'blog:list' %}">목록</a>
<script>
document.querySelector('#delete_btn').addEventListener('click', function() {
  if(confirm('삭제하시겠습니까?')) {
    document.querySelector('#delete_form').submit();
  }
})
</script>

4️⃣ 블로그 작성/수정 통합 (blog_form.html)

✅ 흐름 설명

  1. blog_create.html과 blog_update.html을 통합하여 blog_form.html로 재구성
  2. BlogCreateView, BlogUpdateView에서 get_context_data()를 활용해 버튼 라벨 등 구분
<h1 class="mt-2">블로그 {{ sub_title }}</h1>
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <button class="btn btn-primary">{{ btn_name|default:"저장" }}</button>
</form>

 

3. views.py ( 생성, 업데이트 에 함수추가 )

class BlogCreateView(...):
    ...
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '작성'
        context['btn_name'] = '생성'
        return context

class BlogUpdateView(...):
    ...
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['sub_title'] = '수정'
        context['btn_name'] = '수정'
        return context

 

4. blog_form.html body부분 JS block 추가

    {% block js %}
        <script>
            document.querySelectorAll('select, input, textarea').forEach(function(ele){
                ele.classList.add('form-control');
            })
        </script>
    {% endblock %}

5️⃣ 로그인 및 회원가입 페이지 (registration/login.html, signup.html)

1. form_js.html 를 새로만들어서 다른곳에서도 사용할수있게 만든다. base.html같이

<script>
    document.querySelectorAll('select, input, textarea').forEach(function(ele){
        ele.classList.add('form-control');
    })
</script>

  

 

2. blog_form.html 부분에서 form_js 를 불러온다

    {% block js %}
        {%  include 'form-js.html' %}
    {% endblock %}

✅ 흐름 설명

  • Django 기본 Form 출력 방식에 Bootstrap 버튼만 추가하여 UI 개선 및 바디부분 연결 추가

1. login.html

{% extends 'base.html' %}
{% block content %}
    <h1 class="mt-2">로그인</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}  <!-- 폼 데이터를 p 태그로 출력 -->
        <button class="btn btn-primary">로그인</button>
    </form>
{% endblock %}
{% block js %}
        {%  include 'form-js.html' %}
{% endblock %}

 

2.signup.html 

{% extends 'base.html' %}
{% block content %}
    <h1 class="mt-2">회원가입</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button class="btn btn-primary">가입하기</button>
    </form>
{% endblock %}
{% block js %}
        {%  include 'form-js.html' %}
{% endblock %}

✅ 최종 요약

  • base.html에서 전체 Bootstrap 적용을 통해 디자인 통일
  • CRUD, 인증, 상세 페이지까지 일괄 UI 리팩토링
  • 통합 폼으로 재사용성과 유지보수성 강화
  • 다음 단계에서 댓글 모델과 템플릿을 연결하여 블로그 완성도를 높입니다 ✅

'Django' 카테고리의 다른 글

Chapter 6-4 Django 블로그에 댓글 기능 추가하기  (0) 2025.05.09
Chapter 6-3 댓글 기능 시작하기 - 모델과 관리자 설정  (0) 2025.05.09
Chapter 6-1 [블로그] 댓글 기능 만들기 - Static Files 설정과 Bootstrap 적용  (0) 2025.05.09
Chapter 5-8 📌 Mini Project - Admin 권한으로 모든 게시글 수정/삭제 가능하게 만들기  (0) 2025.05.08
Chapter 5-7 📌 Django URL 구조 정리 - include와 앱 네임스페이스로 FBV/CBV 분리하기  (0) 2025.05.08
'Django' 카테고리의 다른 글
  • Chapter 6-4 Django 블로그에 댓글 기능 추가하기
  • Chapter 6-3 댓글 기능 시작하기 - 모델과 관리자 설정
  • Chapter 6-1 [블로그] 댓글 기능 만들기 - Static Files 설정과 Bootstrap 적용
  • Chapter 5-8 📌 Mini Project - Admin 권한으로 모든 게시글 수정/삭제 가능하게 만들기
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (702)
      • Python (32)
      • 프로젝트 (43)
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (40)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (4)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
Chapter 6-2 Bootstrap 적용으로 블로그 UI 개선하기
상단으로

티스토리툴바