Django #4 - Django로 첫 페이지 만들기

Corner·2022년 4월 23일
0

django

목록 보기
6/14
post-thumbnail

CDN 골격 잡기

Global Navigation Bar를 만들어 볼 것이다. GNB라고도 하는데 실무에서 화면 설계서 등 GNB라고 표기되는 경우가 있으니 실무에서 처음 접할때 모르는 용어라면 검색하면서 익히도록 하자.

메인 메뉴가 들어갈 사이트의 첫 페이지를 만들어보자.

사이트의 첫 페이지는 특정 앱에 속한게 아니므로 프로젝트 디렉토리(mysite)에 만든다.

마찬가지로 url, view, templates 순으로 코딩하면 된다.

urls.py

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

from .views import HomeView

urlpatterns = [
    path('admin/', admin.site.urls),

    path('', HomeView.as_view(), name='home'),
    path('todo/', include('todo.urls')),
]

views.py

from django.views.generic import TemplateView


class HomeView(TemplateView):
    template_name = 'home.html'

Root 경로에 templates 경로를 생성하여 home.html을 생성한다.

templates/home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    Welcome to HOME!
</body>
</html>

http://127.0.0.1:8000/ url에 메인 페이지가 잘 뜨는지 확인한다.

메뉴 코딩하기 💻

base.html을 만들어서 작업한다.

아래 준비물들을 검색하여 cdn 링크들을 전부 가져온다.

준비물

css

  • bootstrap
  • fontawesome (부트스트랩 4부터는 glyphicon을 지원하지 않기 때문에 폰트어썸을 사용하겠다.)
  • favicon.ico
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css">
<link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">

장고의 static 템플릿 태그를 사용하기 위해서 HTML 최상단에 로드시켜준다.

{% load staticfiles %}
{# Django 3.x 부터는 {% load static %} 으로 변경한다. #}

js

  • jquery.js
  • popper.js
  • bootstrap.js
<!-- Bootstrap core JavaScript -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

파비콘은 아래 링크에서 다운을 받는다.

구글 드라이브 📲 파비콘


Bootstrap으로 화면 만들기

장고의 static 템플리 태그를 사용하기 위해서 로드 문법을 사용해야 한다.

Django 3.x 버전 미만

python {# {% load staticfiles %} #}

Django 3.x 부터는 {% load static %} 으로 변경한다.

{% load static %}

base.html

{#{% load staticfiles %}#}
{% load static %}
{# Django 3.x 부터는 {% load static %} 으로 변경한다. #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css">
    <link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">
    {#    장고의 static 템플릿 태그를 사용하기 위해서 로드를 시켜준다.#}

</head>
<body>

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</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 active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</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>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled">Disabled</a>
        </li>
      </ul>
      <form class="d-flex">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>

<!-- Bootstrap core JavaScript -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


</body>


</html>

그리고 home.html에서는 base.html을 상속받는다. 모든 내용을 지우고 아래 코드만 작성한다.

{%  extends 'base.html' %}

이후 페이지를 확인해본다.

필자는 Custom 다크 색상을 클래스명을 넣어서 커스텀을 진행했으니 마음껏 커스텀을 해본다.

커스텀 소스

{#{% load staticfiles %}#}
{% load static %}
{# Django 3.x 부터는 {% load static %} 으로 변경한다. #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css">
    <link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">
    {#    장고의 static 템플릿 태그를 사용하기 위해서 로드를 시켜준다.#}

</head>
<body style="padding-top: 90px;">


<!-- Main Menu -->
<nav class="navbar navbar-expand-sm navbar-dark bg-primary fixed-top">

    <span class="navbar-brand mx-5 mb-0 font-weight-bold font-italic">Vue-Django System</span>

    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'home' %}">Home</a></li>
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'todo:vonly' %}">VueOnly</a></li>
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'todo:create' %}">DjangoOnly</a></li>

            <li class="nav-item dropdown mx-1 btn btn-primary">
                <a class="nav-link dropdown-toggle text-white" href="#" data-toggle="dropdown">Util</a>
                <div class="dropdown-menu">
                    <a class="dropdown-item" href="{% url 'admin:index' %}">Admin</a>
                    <div class="dropdown-divider"></div>
                </div>
            </li>
        </ul>

        <form class="form-inline my-2">
            <input class="form-control mr-sm-2" type="search" placeholder="Search">
        </form>

        <ul class="navbar-nav ml-5 mr-5">
            <li class="nav-item dropdown mx-1 btn btn-primary">
                <a class="nav-link dropdown-toggle text-white" href="#" data-toggle="dropdown">
                    <i class="fas fa-user"></i>&nbsp; Anonymous &nbsp;</a>
                <div class="dropdown-menu">
                    <a class="dropdown-item" href="{% url 'home' %}">Login</a>
                    <a class="dropdown-item" href="{% url 'home' %}">Register</a>
                </div>
            </li>
        </ul>

    </div>
</nav>

<div class="container">
</div>
<!-- Bootstrap core JavaScript -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


</body>


</html>

추가로 block 태그들을 이용해 이왕같이 블럭 코드를 추가한다.

{#{% load staticfiles %}#}
{% load static %}
{# Django 3.x 부터는 {% load static %} 으로 변경한다. #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}home.html{% endblock %}</title>
    {# block 태그의 이름을 title로 정한다.#}
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css">
    <link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">
    {#    장고의 static 템플릿 태그를 사용하기 위해서 로드를 시켜준다.#}

    {% block extra-style %}{% endblock %}
    {# 하위 html 파일에서 추가로 스타일을 지정할 수 있기 때문에 extra-style 블럭을 지정했다. #}
</head>
<body style="padding-top: 90px;">


<!-- Main Menu -->
<nav class="navbar navbar-expand-sm navbar-dark bg-primary fixed-top">

    <span class="navbar-brand mx-5 mb-0 font-weight-bold font-italic">Vue-Django System</span>

    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'home' %}">Home</a></li>
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'todo:vonly' %}">VueOnly</a></li>
            <li class="nav-item mx-1 btn btn-primary">
                <a class="nav-link text-white" href="{% url 'todo:create' %}">DjangoOnly</a></li>

            <li class="nav-item dropdown mx-1 btn btn-primary">
                <a class="nav-link dropdown-toggle text-white" href="#" data-toggle="dropdown">Util</a>
                <div class="dropdown-menu">
                    <a class="dropdown-item" href="{% url 'admin:index' %}">Admin</a>
                    <div class="dropdown-divider"></div>
                </div>
            </li>
        </ul>

        <form class="form-inline my-2">
            <input class="form-control mr-sm-2" type="search" placeholder="Search">
        </form>

        <ul class="navbar-nav ml-5 mr-5">
            <li class="nav-item dropdown mx-1 btn btn-primary">
                <a class="nav-link dropdown-toggle text-white" href="#" data-toggle="dropdown">
                    <i class="fas fa-user"></i>&nbsp; Anonymous &nbsp;</a>
                <div class="dropdown-menu">
                    <a class="dropdown-item" href="{% url 'home' %}">Login</a>
                    <a class="dropdown-item" href="{% url 'home' %}">Register</a>
                </div>
            </li>
        </ul>

    </div>
</nav>

<div class="container">
    {#    본문이 들어갈 자리를 content block으로 지정한다.#}
    {% block content %}{% endblock %}
</div>

{# 푸터 블럭 지정 #}
{% block footer %}{% endblock %}
<!-- Bootstrap core JavaScript -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

{% block extra-script %}{% endblock %}

</body>
</html>

다른 html에 base.html 상속받기

todo_vue_only.html

{% extends 'base.html' %}
{% block title %}todo_vue_only.html{% endblock %}

{% block extra-style %}
    <style>
        body {
            text-align: center;
            background-color: #ddd;
        }

        .inputBox {
            margin: auto;
            width: 70%;
            background: white;
            height: 50px;
            border-radius: 50px;
            line-height: 50px;
        }

        .inputBox .name {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 90px;
            padding-left: 20px;
            line-height: 20px;
        }

        .inputBox .item {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 400px;
            margin-left: 50px;
            padding-left: 20px;
            line-height: 20px;
        }

        .todoList {
            list-style: none;
            padding: 10px 0;
            text-align: left;
        }

        .todoList li {
            display: flex;
            height: 50px;
            line-height: 50px;
            margin: 0.5rem 0;
            padding: 0 0.9rem;
            background: white;
            border-radius: 5px;
        }

        .removeBtn {
            font-size: 20px;
            cursor: pointer;
            height: 30px;
            line-height: 0;
            margin: auto 0 auto auto;
        }
    </style>
{% endblock %}
{% block content %}
    <div id='app'>

        <h1>My Todo App !</h1>
        <strong>서로 할 일이나 의견을 공유해 봅시다.</strong>
        <br>


        <div class="inputBox">
            <input class="name" type="text" placeholder="name ..." v-model.trim="name">
            <input class="item" type="text" placeholder="type anything welcomed ..."
                   v-model.trim="newTodoItem" @keyup.enter="add_todo">
            <button class="btn btn-info btn-sm" @click="add_todo">ADD</button>
        </div>

        <ul class="todoList">
            <li v-for="(todoItem, index) in todoItems">
                <span>{todoItem.name}::: {todoItem.item}</span>
                <button class="removeBtn btn btn-danger btn-sm" @click.stop="remove_todo(todoItem, index)">&#x00D7
                </button>
            </li>
        </ul>

    </div>
{% endblock %}
{% block extra-script %}
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            delimiters: ['{', '}'], // 중괄호를 하나만 사용하겠다는 문법 수정
            el: '#app',
            data: {
                name: '',
                newTodoItem: '',
                todoItems: [
                    {name: '김석훈', item: 'Django 와 Vue.js 연동 프로그램을 만들고 있습니다.'},
                    {name: '홍길동', item: '이름을 안쓰면 홍길동으로 나와요...'},
                    {name: '이순신', item: '신에게는 아직 열두 척의 배가 있사옵니다.'},
                    {name: '성춘향', item: '그네 타기'},
                ],
            },
            methods: {
                add_todo: function () {
                    console.log("add_todo()...");
                    if (this.name === '') {
                        this.name = '홍길동';
                    }
                    if (this.newTodoItem === '') {
                        return;
                    }
                    this.todoItems.push({name: this.name, item: this.newTodoItem});
                    this.name = '';
                    this.newTodoItem = '';
                },
                remove_todo: function (todoItem, index) {
                    console.log(todoItem);
                    this.todoItems.splice(index, 1);    /* from index, count */
                    // axios delete
                },
                clear_input: function () {
                    this.name = '';
                    this.newTodoItem = '';
                },
            },
        })
    </script>
{% endblock %}

todo_confirm_delete.html

{% extends 'base.html' %}
{% block title %}todo_confirm_delete.html{% endblock %}

{% block extra-style %}
    <style>
        body {
            text-align: center;
            background-color: #ddd;
        }

        .inputBox .name {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 70px;
            padding-left: 20px;
        }

        .inputBox .item {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 400px;
            margin-left: 50px;
            padding-left: 20px;
        }

        .todoList li {
            display: flex;
            height: 50px;
            line-height: 50px;
            margin: 0.5rem 0;
            padding: 0 0.9rem;
            background: white;
            border-radius: 5px;
        }

    </style>
{% endblock %}
{% block content %}
    <div id='app'>

        <h1>Todo Delete</h1>
        <p>
            Are you sure to delete {{ object }} ?
        </p>
        <br>

        <form action="." method="post"> {% csrf_token %}
            <button type="submit" class="btn btn-danger btn-sm">Confirm</button>
        </form>

    </div>
{% endblock %}

todo_list.html

{% extends 'base.html' %}
{% block title %}todo_list.html{% endblock %}

{% block extra-style %}
    <style>
        body {
            text-align: center;
            background-color: #ddd;
        }

        .todoList {
            list-style: none;
            padding: 10px 0;
            text-align: left;
        }

        .todoList li {
            display: flex;
            height: 50px;
            line-height: 50px;
            margin: 0.5rem 0;
            padding: 0 0.9rem;
            background: white;
            border-radius: 5px;
        }

        .removeBtn {
            margin-left: auto;
            font-size: 20px;
            cursor: pointer;
        }
    </style>
{% endblock %}
{% block content %}
    <div id='app'>

        <h1>My Todo App !</h1>
        <strong>서로 할 일이나 의견을 공유해 봅시다.</strong>
        <br>

        <ul class="todoList">
            {#        v-for문 대신에, 장고에서 제공하는 템플릿 태그로 바꾼다. #}
            {% for todo in object_list %}
                <li>
                    <span>{{ todo.name }}::: {{ todo.todo }}</span>
                    <span class="removeBtn"><a href="{% url 'todo:delete' todo.id %}">&#x00D7</a></span>
                </li>
            {% endfor %}
        </ul>

    </div>
{% endblock %}

todo_form.html

{% extends 'base.html' %}
{% block title %}
    todo_form.html
{% endblock %}
{% block extra-style %}
    <style>
        body {
            text-align: center;
            background-color: #ddd;
        }

        .inputBox {
            margin: auto;
            width: 70%;
            background: white;
            height: 50px;
            border-radius: 50px;
            line-height: 50px;
        }

        .inputBox .name {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 90px;
            padding-left: 20px;
            line-height: 20px;
        }

        .inputBox .item {
            border-style: none;
            border-bottom: 1px solid #ddd;
            width: 400px;
            margin-left: 50px;
            padding-left: 20px;
            line-height: 20px;
        }

        .todoList li {
            display: flex;
            height: 50px;
            line-height: 50px;
            margin: 0.5rem 0;
            padding: 0 0.9rem;
            background: white;
            border-radius: 5px;
        }

    </style>
{% endblock %}

{% block content %}
    <div id='app'>

        <h1>My Todo App !</h1>
        <strong>서로 할 일이나 의견을 공유해 봅시다.</strong>
        <br>


        {#    csrf 토큰 공격을 방지하는 csrf 토큰을 넣는다. 장고에서 제공해주는 템플릿 태그이다. #}
        <form class="inputBox" action="." method="post"> {% csrf_token %}
            <input class="name" type="text" placeholder="name ..." name="name">
            <input class="item" type="text" placeholder="type anything welcomed ..."
                   name="todo">
            <button class="btn btn-info btn-sm" type="submit">ADD</button>
        </form>


    </div>
{% endblock %}

이제 모든화면에서 메뉴가 잘 나오는지 확인한다.


Home.html 코딩하기

{% extends 'base.html' %}

{% load static %}

{% block title %}home.html{% endblock %}

{% block extra-style %}
<style type="text/css">

.home-window {
    background-image: url("{% static 'img/lion.jpg' %}");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 100%;
    height: 500px;
    border-top: 10px solid #ccc;
    border-bottom: 10px solid #ccc;
    color: yellow;
    padding: 20px 0 0 20px;
}
.title {
    color: #c80;
    font-weight: bold;
}
.powered {
    position: relative;
    top: 77%;
    color: #cc0;
    font-style: italic;
}

.footer-wrapper {
    background: #456;
    color: #eee;
    line-height: 50px;
}
.footer-wrapper a {
    color: #ff9;    /* footer-right text */
}
.footer-wrapper a:hover {
    color: #0ff;
}
footer ul li {
    text-align: center;
}

</style>
{% endblock extra-style %}

{% block content %}
    <div class="home-window">
        <h2 class="title">Django - Python Web Programming</h2>
        <h4 class="powered"><i class="fas fa-cog"></i> powered by django and bootstrap.</h4>
    </div>

    <hr style="margin: 10px 0;">

    <div class="row text-center">
        <div class="col-sm-6">
            <h3>Todo App</h3>
            <p>With Todo app, you can manage, prioritize, and complete the most important things
                you need to do every day. I can focus on the most important things
                and I can do my day more deliberately.
                You can also share lists with colleagues, friends, and family.</p>
        </div>
        <div class="col-sm-6">
            <h3>Blog App</h3>
            <p>This application makes it possible to log daily events or write your own interests
                such as hobbies, techniques, etc.
                A typical blog combines text, digital images, and links to other blogs, web pages,
                and other media related to its topic.</p>
        </div>
    </div>
{% endblock content %}

{% block footer %}
<footer class="fixed-bottom footer-wrapper">
    <div class="container">
        <div class="row">
            <div class="col-md-4">
                <p>Copyright &copy; 2019 DjangoBook by shkim</p>
            </div>
            <div class="col-md-8">
                <ul class="list-inline float-right">
                    <li class="list-inline-item">
                        <a href="#" data-toggle="tooltip" data-placement="top" title="준비중입니다">Introduction</a>
                    </li>
                    <li class="list-inline-item">
                        <a href="#" data-toggle="tooltip" data-placement="top" title="준비중입니다">Help</a>
                    </li>
                    <li class="list-inline-item">
                        <a href="#" data-toggle="tooltip" data-placement="top" title="준비중입니다">Policy</a>
                    </li>
                    <li class="list-inline-item">
                        <a href="#" data-toggle="tooltip" data-placement="top" title="준비중입니다">Something</a>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</footer>
{% endblock footer %}

{% block extra-script %}
<script>
$(function () {
    $('[data-toggle=tooltip]').tooltip();
});
</script>
{% endblock extra-script %}

메인 화면의 이미지는

구글 드라이브📁

해당 링크에서 자료를 받거나, 원하는 어떠한 이미지를 사용해도 좋다.


GitHub Source

👉🏻깃허브 소스

profile
Full-stack Engineer. email - corner3499@kakao.com,

0개의 댓글