기존 템플릿을 커스텀 하는 방법에 대해서는 Django Admin-1에서 다루었다.
오늘 [템플릿 커스텀하기]에서는 동일한 내용을 조금 더 심화적으로 살펴볼 것이다.
django 어드민에 사용되는 템플릿은 모두 django모듈 내부에 contrib/admin/templates/admin
폴더 내부에 있다.
저 위치를 매번 찾아가는 것은 너무 귀찮은 방법인데 vscode사용자라면 폴더를 열지 않아도 내용을 살펴볼 수 있다.
먼저 admin.py에 들어간다.
장고에서 제공하는 기본 어드민을 사용하기 위해 django.contrib에서 admin을 가져왔을 것이다.
표시된 항목을 Ctrl + 클릭 (mac인 경우 Cmd + 클릭)하면 django.contrib.__init__.py
로 이동된다.
여기에서 상단 주소 표시줄을 누르면 원하는 위치로 이동이 가능하다. 이곳에서 contrib/admin/templates/admin
로 들어가 변경하고 싶은 템플릿을 찾으면 된다.
첫번째 글에서 템플릿 수정을 하기 위해 'DIRS': [BASE_DIR / 'templates']
을 추가했다.
django가 템플릿을 확인할 추가 위치를 지정한 것이다.
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / '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',
],
},
},
]
위에서 변경하고 싶은 기존 템플릿을 찾았다면, 이제 프로젝트의 루트에 templates/admin
폴더를 만들고 동일한 이름으로 내용을 복붙한 뒤에 파일을 수정하면 된다.
change list 에 표시한 위치에 버튼을 추가하고 싶다. change list는 change_list.html에서 가져오는데, change_list.html의 내용을 살펴보니 수정하고자 하는 부분은 다른 html에서 수정되는 듯 하다.
1.1)과 같은 방법으로 objct_tools.html을 찾는다.
파일을 열고 내용을 복사한 뒤에 동일한 이름으로 templates/admin
위치에 파일을 만든다.
제대로 연결되었는지 확인해 보기 위해
'Add'라는 단어를 '추가'로 바꿔보자.
{% load i18n admin_urls %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
{% url cl.opts|admin_urlname:'add' as add_url %}
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink">
<!-- 수정된 부분 시작 -->
{% blocktranslate with cl.opts.verbose_name as name %}{{ name }} 추가{% endblocktranslate %}
<!-- 수정된 부분 끝 -->
</a>
</li>
{% endif %}
{% endblock %}
성공적으로 변경되었다!
버튼을 html에서 보여주려면 버튼에 대한 정보를 넘겨야한다. html을 변경하기 전에 html에서 렌더링할 정보를 넘겨주는 부분을 먼저 작성하자.
admin.ModelAdmin
에서 changelist_view
를 오버라이딩할 것이다.
changelist_view
는 인자로 extra_context를 받는데, 이 extra_context는 context와 합쳐져 changelist와 연결된 html에 전달된다.
class UserAdmin(admin.ModelAdmin):
list_display = ('id', 'user_name', 'recent_login','isRecentlyLogined2')
fields = ('id',
('user_img_url', 'imgThumbnail'),
'user_name','user_pass',
('recent_login','isRecentlyLogined2'))
readonly_fields = ('isRecentlyLogined2', 'imgThumbnail')
...
def changelist_view(self, request, extra_context=None):
if(extra_context is None):
extra_context = {}
extra_context.update({'buttons':[
{'name':'네이버', 'url':'https://www.naver.com/'},
{'name':'구글','url':'https://www.google.com/'},
]})
return super().changelist_view(request, extra_context)
코드를 보면
changelist_view
에서 extra_context가 없으면 새로 만들고 changelist_view
에 넘겨주었다.이렇게 하면 이 정보가 changelist와 연결된 html에 전달된다.
Django는 html을 렌더링 할때 Django template 문법을 통한 편의를 제공한다.
{{변수명}}
을 통해 context로 제공한 변수에 접근할 수 있고, {% for elem in 변수명%}{% endfor %}
로 for문을 쓸 수도, {% for 변수명%}{% enfif %}
로 if문을 쓸 수도 있다.
자세한것은 공식 홈페이지의 설명을 참고하자.
이번에 쓸 것은 for문이다.
1)에서 가져온 change_list_object_tools.html을 연다.
{% load i18n admin_urls %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
{% url cl.opts|admin_urlname:'add' as add_url %}
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink">
{% blocktranslate with cl.opts.verbose_name as name %}{{ name }} 추가{% endblocktranslate %}
</a>
<!-- 추가된 부분 시작 -->
{% if buttons %}
{% for btn in buttons %}
<a href="{{btn.url}}" class="addlink">
{{btn.name}}
</a>
{% endfor %}
{% endif %}
<!-- 추가된 부분 끝 -->
</li>
{% endif %}
{% endblock %}
추가된 부분을 보면
{% if buttons %}
:먼저 buttons 라는 변수가 있는지 확인한다.{% for btn in buttons %}
: buttons가 있으면 for문을 통해 내부의 항목을 순회한다.<a href="{{btn.url}}" class="addlink"> {{btn.name}} </a>
: 각 항목에 대해 href와 content를 채운 a태그를 반환한다.저장한 뒤에 새로고침 해보면 정상적으로 버튼이 적용된 화면을 볼 수 있다.
링크도 정상적으로 작동한다.
버튼이 딱 달라 붙어 있는 게 마음에 들지 않는다면 Django Admin-3에서 작성한 css파일에 값을 추가해주면 된다.
/* static\css\custom.css */
...
.object-tools a.addlink{
margin-left: 5px;
}
최종 결과물은 다음과 같다.
버튼이 마음에 들게 추가되었다!
이번에는 change form을 수정해보자.
2번 항목의 반복이라 어렵지 않을 것이다.
change_form.html을 보면 원하는 부분이 submit_row와 비슷한 이름을 가진 html에 들어있는 듯 하다.
파일 목록을 살펴보니 submit_line.html이 있다.
내용을 보니 맞게 찾아온 것 같다.
파일을 templates/admin로 복사해온다.
테스트로 각 항목을 한글화 해보자.
{% load i18n admin_urls %}
<div class="submit-row">
{% block submit-row %}
{% if show_save %}<input type="submit" value="저장" class="default" name="_save">{% endif %}
{% if show_delete_link and original %}
{% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
<p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">삭제</a></p>
{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% translate 'Save as new' %}" name="_saveasnew">{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="저장 후 새 항목 추가" name="_addanother">{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% if can_change %}저장 후 계속 수정{% else %}{% translate 'Save and view' %}{% endif %}" name="_continue">{% endif %}
{% if show_close %}<a href="{% url opts|admin_urlname:'changelist' %}" class="closelink">{% translate 'Close' %}</a>{% endif %}
{% endblock %}
</div>
결과는 다음과 같다.
성공적으로 한글화되었다!
이번에는 changeform_view
를 오버라이딩 해야한다.
changeform에서는 이동이 아니라 기능 버튼을 만들어 볼 것이다.
클릭시 알럿창, 콘솔창에 메세지를 띄우는 js 코드를 넣어보자.
class UserAdmin(admin.ModelAdmin):
list_display = ('id', 'user_name', 'recent_login','isRecentlyLogined2')
fields = ('id',
('user_img_url', 'imgThumbnail'),
'user_name','user_pass',
('recent_login','isRecentlyLogined2'))
readonly_fields = ('isRecentlyLogined2', 'imgThumbnail')
...
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
if(extra_context is None):
extra_context = {}
extra_context.update({'buttons':[
{'name':'알럿 메세지', 'script':'alert("Hello")'},
{'name':'콘솔 메세지', 'script':'console.log("World")'},
]})
return super().changeform_view(request, object_id, form_url, extra_context)
html에 for문으로 버튼을 추가한다.
{% load i18n admin_urls %}
<div class="submit-row">
{% block submit-row %}
{% if show_save %}<input type="submit" value="저장" class="default" name="_save">{% endif %}
{% if show_delete_link and original %}
{% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
<p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">삭제</a></p>
{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% translate 'Save as new' %}" name="_saveasnew">{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="저장 후 새 항목 추가" name="_addanother">{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% if can_change %}저장 후 계속 수정{% else %}{% translate 'Save and view' %}{% endif %}" name="_continue">{% endif %}
{% if show_close %}<a href="{% url opts|admin_urlname:'changelist' %}" class="closelink">{% translate 'Close' %}</a>{% endif %}
{% endblock %}
<!-- 추가된 부분 시작 -->
{% if buttons %}
{% for btn in buttons %}
<button type="button" onclick="{{btn.script}}">
{{btn.name}}
</button>
{% endfor %}
{% endif %}
<!-- 추가된 부분 끝 -->
</div>
change_list에서 한것과 거의 동일하다.
change_list에서는 a태그에 href를 넣어주었다면 이번에는 button 태그에 onclick script를 넣어주었다는 것이 다르다.
저장 후 실행시켜보자.
스크립트 실행에 성공했다!
이제 원하는 대로 템플릿을 커스텀할 수 있을것이다.
https://github.com/hokim2407/django-admin_study/tree/56028dd6c6ad3497e955862eaf9d2560ec57e615