dJango Template 에서 settings 값 사용하기

dJango 를 이용해서 만들고 있는 어플리케이션이 html view 와 rest api ( json )을 모두 지원하게 하려고 한다. 요청 URL 의 내용을 보고, api 요청인지, view 요청인지 판단하여 분기처리를 하기 위해 rest 처리용 urls 와 화면용 urls 를 분리하였다.

url(r'^api/product/', include('products.api_urls', namespace='product_api')),
url(r'^view/product/', include('products.view_urls', namespace='product_view')),

요청 url 이 /api/ 로 시작하면 api_urls 에 매핑되어 있는 RestAPI 용 view 가 실행이 되고, /view/ 로 시작하면 화면 출력용 view 가 호출되면서 지정한 template 에 의한 화면이 출력되게 된다.

따라서, template 에서 사용하는 링크는 /view/를 포함하고 있어야 화면간에 이동(link)을 할 수 있게 된다.

        <ul>
            
                <li><a href="/view/product/6/">testName1</a></li>
            
                <li><a href="/view/product/4/">testName</a></li>
            
                <li><a href="/view/product/3/">testName</a></li>
            
        </ul>
    

문제는 화면 요청을 특정하는 ‘/view/’ 라는 문자열을 하드코딩하지 않고, settings.py 에 아래와 같이 정의해 놓고,

VIEW_URL_CTX = '/view/'
API_URL_CTX = '/api/'

template 에서는 <a href="{{ VIEW_URL_CTX }}product/... > 와 같은 식으로 사용하고 싶었다.

하지만 template 에서는 사용자가 settings 에 정의한 값을 꺼내어 사용할 수 없었다. 그럴법도 한것이, 만약 대규모 프로젝트라면 settings.py 에는 DB 접속 정보부터 각종 설정에 이르는 민감하고 중요한 내용들이 들어있기 때문에 자유롭게 해당 값을 읽어서 사용할 수 있다면 문제가 될 소지가 많다.

설정은 모두 settings에 모아두고 그 값을 template 에서 사용하기 위해서는 어떻게 해야 할까?
context processor도 하나의 방법이 될 수 있지만 필자는 dJango 의 custom tag를 사용해서 위 문제를 해결하기로 했다.

그럼 custom tag를 만드는 방법을 알아보도록 하자.

먼저 custom tag를 만들기 위해서는 ‘templatetags’ 디렉토리를 만들어야 한다. 정확하게 얘기하면 __init__.py 가 포함되어 있는 python pacakge 를 만들어야 한다. 패키지 이름도 반드시 ‘templatetags’ 이어야 한다.

패키지를 만들었다면 패키지 custom tag를 구현할 py파일을 생성한다. 이때 생성하는 py 파일의 이름은 자유롭게 지정해도 좋다.

dJango 의 custom tag 는 tag 메소드를 정의하는 방법(argumemt의 갯수)에 따라 tag 의 형태가 많이 달라지므로 필요한 형식에 따라 주의깊게 tag를 정의해야 한다.

필자는 tag를 <a href=””{{ TAG_NAME }}”> 처럼 사용하고 싶기 때문에(즉,tag에 전달하는 argumement가 없다) assignment_tag를 사용하기로 했다. ( tag의 다양한 유형은 https://docs.djangoproject.com/en/1.7/howto/custom-template-tags/ 를 참고하도록 하자.)

from django import template

from django.conf import settings



register = template.Library()




from django import template
from django.conf import settings

register = template.Library()

@register.assignment_tag(takes_context=True)
def get_view_url_ctx(context):
    return getattr(settings, 'VIEW_URL_CTX', '')

@register.assignment_tag(takes_context=True)
def get_api_url_ctx(context):
    return getattr(settings, 'API_URL_CTX', '')

위와 같은 내용으로 templatetags/product_tags.py를 만들었다.

위 파일에서는 django.conf 의 settings를 import 하여 사용하고 있다. tag 구현체에 decorator를 달아서 tag유형을 assignment_tag 로 지정하였다.

이렇게 custom tag를 만들었으면 이제 template 에서 사용할 수 있다. template 에서 custom tag를 사용하려면 tag 파일을 load 해야 한다.template 파일의 시작하는 부분에 {% load your_template_tag_file_name %} 과 같이 적어준다.

필자의 환경에서는 abstract base template 을 정의해 놓고, 각각의 어플리케이션의 화면들이 base template을 상속하는 형태로 되어 있기 때문에 최상위 template파일에 아래와 같이 적어주었다.

{% load product_tags %}

이렇게 template에서 tag파일을 로딩하면 이제 tag를 사용할 수 있게 되는데, tag는 {% %} 안에 tag 이름과 argument를 적어서 사용하게 된다. 하지만 필자는 마치 settings에 정의한 global 변수처름 {{ TAG_NAME }} 과 같이 사용하고 싶어 alias를 지정해서 사용하기로 했다.

{% get_view_url_ctx as VIEW_URL_CTX %}
{% get_api_url_ctx as API_URL_CTX %}

이렇게 하면 template 파일에서 아래와 같이 {{ }} 안에 tag 를 사용할 수 있게 되고, 마치 settings에 정의한 값을 그대로 template 에서 사용하는 것처럼 보이게 할 수 있다.

{% block content %}
    {% if latest_product_list %}
        <ul>
            {% for product in latest_product_list %}
                <li><a href="{{ VIEW_URL_CTX }}product/{{ product.product_id }}/">{{ product.product_name }}</a></li>
            {% endfor %}
        </ul>
    {% else %}
        <p>등록된 상품이 없습니다 </p>
    {% endif %}

    <div>
        <img src="{{ STATIC_URL }}product/images/200ok.jpg"/>
    </div>
{% endblock %}