정적 파일(static files)

  • 렌더링(Rendering)하는 과정에서 필요한 추가적인 파일로 템플릿에서 css, 사진, 폰트와 같은 것들은 정적 파일(static files)에 따로 모아 관리해야 합니다.

  • 정적파일을 위한 디렉토리 구조는 템플릿과 같은 샌드위치 구조(foods/static/foods) 입니다.

    ※ 샌드위치 구조를 사용해야 하는 이유

      ex). A라는 앱의 templates 폴더의 index.html
          B라는 앱의 templates 폴더의 index.html
    
      settings.py 파일에 TEMPLATES = ['APP_DIRS': True]는 각각의 앱에 templates 폴더가 있으니 template(index.html)을 찾을 때는 templates 폴더에서 찾으세요 라는 의미  
    
      그리고 INSTALLED_APPS = ['A', 'B'] 이런식으로 되어있으면 템플릿(index.html)을 찾을때 항상 A앱의 templates 폴더를 먼저 탐색하게 되어 B앱의 templates 폴더의 template에 접근이 불가능합니다.  
    
      이런 문제를 해결하기 위해 각각의 templates폴더에 각각의 앱 이름을 한 번 더 사용해 폴더를 만들어줍니다.  
    
  • 정적 파일을 템플릿에 사용하고자 할 때는 다음과 같이 적어줍니다.
      # index.html
      {% load static %}
        
    

    {% load static %} 이런 것을 템플릿 언어(Template language) 중에서 템플릿 태그라고 합니다.

  • 그리고 이미지, 폰트등의 소스를 템플릿 파일에 다음과 같이 입력하면 됩니다.
      # index.html
    
      <link rel="stylesheet" href={% static 'foods/css/styles_detail.css' %}>
    

템플릿 언어(Template Language)

  • HTML에 동적인 능력을 부여해줍니다.
  • 템플릿 언어에는 크게 템플릿 변수, 템플릿 태그, 템플릿 필터, 템플릿 주석이 있습니다.
    • 템플릿 변수: 템플릿에 {{ 변수명 }}라고 적으면 view에서 넘겨 받은 값이 여기로 쏙 들어가게 됩니다. 또한 {{ 변수명.속성 }} 으로 변수에 속성이 있으면 속성에도 다음과 같이 접근할 수 있습니다.

    • 템플릿 필터: {{ 변수명|필터 }}라고 적으면 템플릿 변수를 특정 형식으로 변환할 수 있습니다. 예를 들면 {{ bread|upper }} 라고 적으면 문자열 전체를 대문자로 변수를 변환시켜 줍니다.

    • 템플릿 태그: {% 태그 %}{% end태그 %}라고 적으면 템플릿에 로직을 적용할 수 있습니다.

템플릿 변수 사용해서 동적인 느낌 가져보기

  • view에서는 자신이 가지고 있는 데이터를 클라이언트에게 보내기 전에 템플릿에 한 번 보내서 렌더링 한 후에 클라이언트에게 응답(Response)합니다.

데이터를 view에서 직접 만든 경우

# view.py

def index(request):
    today = datetime.today().date()
    context = {"date":today}
    return render(request, 'foods/index.html', context=context)

만약 유저가 domain/foods/index 라고 요청을 보냈을 때 오늘 날짜를 돌려주는게 이 앱의 목적이라고 하면 view에서는 일단 오늘의 날짜를 가질 것이고 이 값을 템플릿에 보내주면 됩니다. 이 때 render함수의 세 번째 인자로 context에 그 변수를 전달해줍니다. 그러면 템플릿에 그 변수를 템플릿 변수를 이용해 저장하면 우리는 응답(Response)으로 실시간으로 변하는 변수를 유저에게 전달해줄 수 있습니다.

# index.html

<h2>{{ date }}</h2>

데이터를 유저로부터 받아온 경우

🔔 동적 URL (Dynamic URL)
유저가 누르는 버튼에 따라 응답(Response)의 미세한 값만 다를 뿐, 템플릿은 같게 하고 싶은 경우에 저희는 동적 URL을 사용할 수 있고 이를 우아한 URL이라고도 부릅니다.

예를 들어 다음과 같이 각각의 메뉴에 대한 이름, 가격, 이미지를 보여주는 템플릿을 제공한다고 할 때, 이를 위해 각각의 URL 경로를 다 따로 적으면 굉장히 비효율적이게 됩니다.

# urls.py

urlpatterns = [
    path('menu/', views.index),
    path('menu/chicken', views.chicken),
    path('menu/pizza', views.pizza),
    path('menu/pasta', views.pasta)
]

이를 해결하기 위해 동적 URL을 도입하면 다음과 같이 나타낼 수 있습니다.

# urls.py 

urlpatterns = [
    path('menu/', views.index),
    path('menu/<str:food>', views.food_detail),
]

이렇게 하면 menu/문자열food을 요청하면 foodfood_detail에 인자로 들어가게 됩니다. 그러면 이 값을 받아 하나의 템플릿으로 여러 응답(Response)를 만들 수 있는 것입니다.

# views.py

def food_detail(request, food):
    context = {"name":food}
    return render(request, 'foods/detail.html', context=context)
# detail.html

<h2>{{ food }}</h2>

또 다른 예시로 만약 요청된 문자열이 치킨일 경우 이름, 가격, 이미지를 응답한다고 해보겠습니다. 이 때 유의할 점이 이미지는 정적 파일에 저장되어 있어서 {% static {{img_path}} %} 이런식으로 저장해야 될 것 같은데 템플릿 언어는 이렇게 템플릿 태그 안에 템플릿 변수가 들어올 수 없습니다. 그래서 이 때는 특별한 템플릿 태그를 사용해야 합니다. 바로 {% get_static_prefix %}{{변수}}입니다.

<img src={% get_static_prefix %}{{img_path}}>

템플릿 중복 코드 없애기(feat.상속)

  • {% include '부품 템플릿' %}, {% extends '부모 템플릿' %}과 같은 템플릿 태그를 이용해 템플릿을 조금 더 구조적으로 작성할 수 있습니다.
# base.html (부모 템플릿)  

<html lang="en">
{% include 'head.html' %}

<body style="font-family: 'NanumBarunpenR';">

    {% include 'header.html' %}

    <hr>

    {% block content %}
    {% endblock %}

    <hr>

    {% include 'footer.html' %}

</body>
</html>
# create.html (자식 템플릿)  

{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

  <div style="text-align:center; max-width: 500px; margin: 4rem auto">
      <div class="mb-4">
          <h4>Signup</h4>
      </div>
      <form action="{% url 'accountapp:create' %}" method="post">
        {% csrf_token %}
        {% bootstrap_form form %}
        <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
      </form>

  </div>

{% endblock %}

에러 페이지 처리하기

🔔상태코드
요청에 대한 처리 결과가 어떻게 되었는지 알려주는 코드

1XX: 요청을 받아 진행중
2XX: 요청에 대한 처리 결과가 정상
3XX: 요청을 완료하기 위해 추가적인 동작 필요
4XX: 클라이언트의 요청에 문제가 있음 (404: 요청한 자원이 없다, 403: 접근 권한이 없다)
5XX: 서버가 요청을 처리하는 과정에서 문제가 발생

# views.py
from django.http import Http404

if ~:
else:
    raise Http404("이런 음식은 없습니다")

URL에 이름 부여하기

  • URL에 이름을 부여해주면 나중에 구조가 바뀌더라도 모든 소스코드를 보지 않고도 URL을 관리할 수 있습니다.
# urls.py  

from django.urls import path
from . import views

urlpatterns = [
    path('diary/page/<int:page_id>/', views.page_detail, name='page-detail'),
# page_list.html

<a href="{% url 'page-detail' obj.id %}">

Tags:

Categories:

Updated: