본문 바로가기
python/Django

1. Django with bootstrap, 웹페이지 기본 프레임 및 메뉴 구성( top, left, main )

by 맑은안개 2021. 2. 26.

Django에서 웹페이지의 기본 프레임 구조를 잡는 법을 살펴본다. Django template 기능 중 하나인 block 요소를 사용하여 프레임 구조를 잡고 마지막에 부트스트랩을 사용해서 메뉴바를 조금 더 세련되게 변경해보자.


다음 내용을 알아본다.

 - 장고 프로젝트 및 App 생성

 - 장고 block을 사용한 메뉴 프레임 구성

 - 부트스트랩을 사용하여 네비게이션 바 구성

 - 부트스트랩을 사용하기 위한 장고 static 설정

개발환경

 - Python 3.9 ( 3.6 이상 요구 됨 )

 - Django 3.1.5 ( 3.1 이상 요구 됨 )

 - Bootstrap 5.x

프로젝트 및 App 생성

C:\django_exam> django-admin startproject sitemenu

C:\django_exam>cd sitemenu

C:\django_exam\sitemenu> python manage.py startapp demo

settings.py에 App 등록

INSTALLED_APPS = [
    'demo.apps.DemoConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

 

demo/templates/base.html

- base.html는 상단, 사이드 메뉴바가 있고 메인 컨텐츠를 출력하는 block 코드( {% block content %} {% endblock %} )가 있다. Django에서 block은 templates의 주요 기능이다.

- main 컨텐츠에 출력되는 모든 html은 base.html 을 extends하여 static 소스 부터 메인 프레임 위치가 지정된 block content를 얻게 되고 각 화면에서는 block content 안에 내용을 넣는다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Demo{% endblock %}</title>
    <style>

        .topnav {
            top: 0;
            height: 60px;
            width: 100%;
            position: fixed;
            z-index:1;
            background-color:#02343F;
            overflow: hidden;
            display: flex;
            justify-content: center;
        }

        .topnav .center { 
            display:flex;
            align-items:center;
        }

        .topnav a {
            text-align: center;
            margin: 0px 5px 0px 5px;
        }

        a {
            color: #F0EDCC;
            text-decoration: none;
            font-size: 25px;
        }

        a:hover {
            color: white;
        }

        .sidemenu {
            height: 100%;
            width: 200px;
            position: fixed;
            z-index:1;
            top: 60px;
            left: 0;
            background-color:#02343F;
            overflow-x: hidden;
            padding-top: 20px;
        }

        .sidemenu li {
            margin:10px;
        }

        .wrap_content {
            margin-top: 70px;
            margin-left: 210px;
            margin-right: 10px;
        }

        ul {
            list-style:none;
            list-style-position: outside;
        }

        body {
            margin: 0px;
            background-color: #F0EDCC;
        }

    </style>
</head>
<body>

    <div class="topnav">
        <div class="center">
            <div class="menu">
                <a href="{% url 'demo:home' %}">Home</a>
                <a href="{% url 'demo:board' %}">Board</a>
            </div>
        </div>
    </div>

    <div class="sidemenu">
        <ul>
            <li><a href="{% url 'demo:home' %}">home</a></li>
            <li><a href="{% url 'demo:board' %}">board</a></li>
            <li><a href="#">menu3</a></li>
            <li><a href="#">menu4</a></li>
        <ul>
    </div>

    <div class="wrap_content">
        <div id="content" name="content" class="container">
        {% block content %}
        {% endblock %}
        </div>
    </div>

</body>
</html>

 

demo/templates/index.html

- home.html, board.html을 만들고 index.html의 내용을 카피한다. ( 변경 된 페이지를 확인하기 위해 컨텐츠 내용을 변경하자 )

{% extends 'base.html' %}

{% block title %}Index page{% endblock %}

{% block content %}
<style>
	.card {
		padding: 10px;		
	}

	.card h3 {
		font-family: none;
	}
</style>

<h2>Index Page</h2>

<div style="display:flex;">
	<div class="card" style="width:33%;">
		<h3>Django</h3>
		Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
	</div>

	<div class="card" style="width:33%;">
		<h3>Django</h3>
		Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
	</div>

	<div class="card" style="width:33%;">
		<h3>Django</h3>
		Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
	</div>
</div>
{% endblock  %}

  1. {% extends 'base.html' %} 코드로 base.html을 확장한다.

  2. {% block content %} ... html ... { % endblock %} 안에 컨텐츠 내용을 넣는다. 

 

sitemenu/urls.py

from django.contrib import admin
from django.urls import path, include


from demo import views


urlpatterns = [
    path('', views.index, name='index'),
    path('demo/', include('demo.urls'))
]

  1. Indes url과 demo App의 urls.py에 정의된 url을 include 한다.

 

demo/urls.py ( 신규생성 )

from django.urls import path

from . import views

app_name = 'demo'
urlpatterns = [
    path('', views.index, name='index'),
    path('board/', views.board, name='board'),
    path('home/', views.home, name='home'),
]

  1. app_name 을 demo로 등록하여 네임스페이스를 지정한다. 

  2. 메뉴바에서 연결되는 home, board의 url을 등록한다.

 

demo/views.py

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'index.html', {'title':'data'})

def home(request):
    return render(request, 'home.html', {'title':'home'})    

def board(request):
    return render(request, 'board.html', {'title':'board'})    

  1. urls.py에 매핑된 view 객체를 생성한다.

 

결과페이지

index 페이지
board 페이지


Bootstrap 사용하여 메뉴바 변경

아래 부트스트랩 다운로드 페이지에서 소스를 다운받는다.

getbootstrap.com/docs/5.0/getting-started/download/

 

Download

Download Bootstrap to get the compiled CSS and JavaScript, source code, or include it with your favorite package managers like npm, RubyGems, and more.

getbootstrap.com

압축을 풀면 css / js 폴더가 있다. 폴더채로 demo/static/demo 폴더에 넣는다. 

vscode 메뉴트리

 

demo/templates/base.html

base.html 제일 상단에 {% load static %} 코드를 넣으면 static 요소에 접근 할 수 있다. base.html을 확장하고 있는 html들은 static 자원을 별도로 로드 할 필요 없다. 

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Demo{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'demo/css/bootstrap.css' %}">
    <script src="{% static 'demo/js/bootstrap.js' %}"></script>
    
 .. 이하 생략

  1. {% static "url" %} 을 사용하여 css, js파일을 로드한다.

 

부트스트랩 자원을 제대로 로드 하는지 확인한다.

- F12로 개발자도구 창을 열어 Network에서 제대로 로드 되었는지 확인한다.

부트스트랩 css 영향을 받아 일부 div의 모습이 변경되었다.

 

base.html의 내용을 변경하여 메뉴바를 변경한다. (navbar는 공식레퍼런스사이트에 공개된 내용을 가져왔다.)

demo/templates/base.html 전체 소스

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Demo{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'demo/css/bootstrap.css' %}">
    <script src="{% static 'demo/js/bootstrap.js' %}"></script>
    <style>

        .wrap_content {
            margin-top: 20px;
        }

        body {
            margin: 0px;
            background-color: #F0EDCC;
        }

    </style>
</head>
<body>
    <!--
    <div class="topnav">
        <div class="center">
            <div class="menu">
                <a href="{% url 'demo:home' %}">Home</a>
                <a href="{% url 'demo:board' %}">Board</a>
            </div>
        </div>
    </div>
    -->

    <!--
    <div class="sidemenu">
        <ul>
            <li><a href="{% url 'demo:home' %}">home</a></li>
            <li><a href="{% url 'demo:board' %}">board</a></li>
            <li><a href="#">menu3</a></li>
            <li><a href="#">menu4</a></li>
        <ul>
    </div>
    -->

    <nav class="navbar navbar-expand-md navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">My demo app</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link {% if title == 'home' %} active aria-current='page' {% endif %}"  href="{% url 'demo:home' %}">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link {% if title == 'board' %} active aria-current='page' {% endif %}" href="{% url 'demo:board' %}">Board</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                            Dropdown
                        </a>
                    <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                        <li><a class="dropdown-item" href="#">Action</a></li>
                        <li><a class="dropdown-item" href="#">Another action</a></li>
                        <li><hr class="dropdown-divider"></li>
                        <li><a class="dropdown-item" href="#">Something else here</a></li>
                    </ul>
                </ul>
                <form class="form-inline justify-content-center" style="text-align: center;">
                    <input class="form-control mr-sm-2" type="search" placeholder="Search for" aria-label="Search">
                </form>
            </div>
            
        </div>
    </nav>

    <div class="wrap_content">
        <div id="content" name="content" class="container">
        {% block content %}
        {% endblock %}
        </div>
    </div>

</body>
</html>

style 태그가 대부분 없어지면서 코드가 한결 가벼워졌다. ( 사이드 메뉴를 살리고 싶다면 사이드 메뉴바의 div를 풀면된다. )

 

결과 페이지

부트스트랩 적용 Index 페이지

 

마무리하며..

Django의 메뉴프레임을 셋팅하고 정적 자원(css, js)을 어떻게 관리하는지 알아보았다. block 요소는 Django template 기능 중 핵심기능이다. 이를 사용해서 subcontent 영역이나 footer영역을 나눌 수 있다.

 

  부트스트랩을 잘 사용하면 많은 효과를 볼 수 있다. 잘 꾸며진 다양한 컴포넌트와 이를 화면에 배치하는데 제공되는 여러 class 요소를 제공한다. 웹 페이지 디자인 요소에 약한 개발자에게는 더 좋은 선택지가 될 것이다. ( 나같은 사람에겐 너무 고마운 존재다. ㅠㅠ ) 

 

다음에는 부트스트랩 이해 제고를 위해 본 블로그에서 생성한 페이지에 주요 기능들을 구현해 본다.

반응형