Today Sangmin Learned
article thumbnail
728x90

1. Template 상속

이번에는 base.html을 사용하여 템플릿 상속을 해볼 것이다. base.html에는 Navbar가 들어가고, 다른 일반 페이지에서는 extends base.html을 통해 Navbar를 받아온 뒤에 페이지별로 필요한 정보만 보이게끔 하여 코드 수를 줄일 것이다.

 

1. crud2/crud2 폴더에 templates 폴더를 만들고 그 안에 base.html을 넣는다. 부트스트랩으로부터 가져온 Navbar이다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
      crossorigin="anonymous"
    ></script>
    <title>BLOG</title>
    <style>
      body {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <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"
                href="#"
                tabindex="-1"
                aria-disabled="true"
                >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>
    <div class="container">{% block content %} {% endblock %}</div>
  </body>
</html>

{% block content %}와 {% endblock %} 사이에 페이지마다 필요한 정보가 들어간다.

 

2. settings.py > TEMPLATES > DIRS에 '프로젝트 폴더 명/templates'를 추가해준다.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['crud2/templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

 

3. home.html을 수정해준다. 우리가 위에서 불러온 Navbar가 담긴 base.html을 상속받아서 사용한다.

{% extends 'base.html' %}
    {% block content %}
      <header>
        <h1>Blog</h1>
      </header>

      <h4><a href="{% url 'new' %}">새 글 작성하기</a></h4>
    
      {% for blog in blogs%}
        <h3>{{ blog.title }}</h3>
        {{ blog.writer}}</br>
        {{ blog.summary }}
        <a href="{% url 'detail' blog.id %}">...more</a>
        <a href="{% url 'delete' blog.id%}">Delete Post</a> 
      {%endfor %}
    {% endblock %}

이제 서버를 켜고 들어가면 아래와 같이 Navbar가 들어간 것을 확인할 수 있다.

이렇게 바꾸는 작업을 detail, new, update HTML파일에 각각 해준다. body태그 내부에 있는 부분만 떼온 뒤에 1행에 {% extends 'base.html' %}, 그리고 떼온 부분들을 {% block content %}와 {% endblock %}으로 감싸주면 된다.

템플릿 상속을 통해 중복된 코드를 줄일 수 있고, CSS를 상속된 템플릿에 모두 적용할 수 있다. 

2. 앱 분리

지금 우리는 한 가지의 앱(blog)을 썼다. 한 군데에다가 모두 관리한다면 가독성이 무엇보다 제일 떨어지게 된다. 그래서, 앱 별로 URL을 따로 분리하는 것이 효과적이다.

 

1. 현재 있는 App 폴더 내부에 urls.py를 만들고 아래 코드를 넣어준다. (본인 기준으로 하면 crud2/blog/urls.py이다.)

# app폴더 urls.py
# urls.py에서 blog앱에서 사용하는 url을 모두 가져옵니다.

from django.urls import path
from . import views #현재 폴더에 있는 views에 접근하기 때문

app_name = 'blog' # app_name에는 앱 이름을 넣어줍니다.

urlpatterns = [
    path('<int:id>', views.detail, name='detail'),
    path('new/', views.new, name='new'),
    path('create/', views.create, name='create'),
    path("update/<int:id>", views.update, name="update"),
    path('delete/<int:id>', views.delete, name="delete"),
]

그리고 메인 urls.py(본인 기준 crud2/crud2/urls.py이다.)를 아래와 같이 수정해준다.

# 프로젝트폴더 urls.py
from django.contrib import admin
from django.urls import path, include # include 작업을 분리해서 앱의 urls.py로 넘겨준다
import blog.views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', blog.views.home, name="home"),
    path('blog/', include('blog.urls')),
]

여기서 include는, 'http://127.0.0.1:8000/blog/' 다음에 들어갈 URL들에 대해서 blog 폴더의 urls.py에 정의된 경로들이 들어갈 것이라는 의미이다.

 

2. 이제 home.html을 수정해준다.

{% extends 'base.html' %}
    {% block content %}
      <header>
        <h1>Blog</h1>
      </header>
      <h4><a href="{% url 'blog:new' %}">새 글 작성하기</a></h4>
      {% for blog in blogs%}
        <h3>{{ blog.title }}</h3>
        {{ blog.writer}}</br>
        {{ blog.summary }}
        <a href="{% url 'blog:detail' blog.id %}">...more</a>
      {%endfor %}
    {% endblock %}

detail에서 blog:detail과 같은 형태로 바뀌었다. blog 앱의 urls.py로 넘어간 URL들에 대해서는 저렇게 (앱이름:경로) 로 적어줘야 한다. 그 부분을 하기 위해

1. new.html의 form action 부분에 url 'create'를 url 'blog:create'로

2. 앱의 views.py에서 create 함수 마지막 redirect를 'blog:detail'로

바꿔주면 된다.

 

3. Static

Static을 통해 우리는 Django에서 CSS 스타일링을 제대로 할 수 있게 된다.

1. 앱 폴더 내부에 static 폴더를 만든다. 그 다음 이미지(어떤 이미지든 상관없다.)를 static 폴더 안에 저장해준다.

 

2. 사진을 띄우기 위해 settings.py에서 해당 파일이 어디에 위치해있는지를 명시해줘야 한다.

settings.py로 가서 내리다보면 STATIC_URL = '/static/' 으로 되어있는 부분이 나올텐데, 그 아래에 다음과 같은 코드를 추가해준다. 

# 맨 위에 os를 import 해줘야한다.
import os

STATICFILES_DIRS = [
	os.path.join(BASE_DIR, 'blog', 'static') # BASE_DIR/blog/static
	# os.path.join(BASE_DIR, '앱이름', 'static')
]

# static django에서는 편의를 위해 흩어져있는 static파일을 한곳에 모으는데, 
# 그때 파일을 모아줄 위치를 나타낸다.
STATIC_ROOT = os.path.join(BASE_DIR, 'static') # BASE_DIR/static

3. 이제 여러 앱(여기서는 1개지만, 여러개로 가정한다.) 각각의 static 폴더 내부에 있는 이미지들을 base에 모으기 위해 다음과 같은 명령어를 작성한다.

(venv) sangminpark@Sangminui-MacBookPro-16 crud2 % python manage.py collectstatic
Found another file with the destination path 'world.png'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure every static file has a unique path.

129 static files copied to '/Users/sangminpark/Desktop/Django/crud2/static'.

이렇게 떴다면 성공이다. 이제 최상위 디렉토리에 static 폴더가 생겼을텐데, 이 폴더는 settings.py의 STATICFILES_DIRS 경로 내부에 있는 모든 static 파일들을 한곳에 모아준다. 이 폴더의 위치는 STATIC_ROOT에 설정해준 곳에 생긴다.

 

4. templates 내부에서 static 폴더 안에 있는 파일들을 가져오기 위해 templates에 static 파일들을 불러오겠다는, 장고 내장 명령어인 {% load static %}을 사용해야한다. 예를 들어 base.html에 static 파일을 사용해보자.

{% load static %]
<img src = "{% static '파일이름.확장자' %}" alt = "">
    <div class = "container">
        {% block content %}
        {% endblock %}
    </div>

이렇게 container div 위에 넣어주면 된다.

결과물

이미지가 잘 뜨는 것을 확인할 수 있다.

'Django' 카테고리의 다른 글

[Django] CRUD - U, D  (0) 2021.07.22
[Django] CRUD - R, C  (0) 2021.07.21
[Django] Model & Admin  (2) 2021.07.21
profile

Today Sangmin Learned

@steadily-worked

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!