Django Admin-3 : 내용 커스텀하기(HTML/JS/CSS)

Ho Kim·2022년 11월 1일
0

지난 글에서는 추가적으로 어드민에서 보여주고 싶은 항목을 추가하는 작업을 했다. 이번 글에서는 그 항목을 조금 더 자유도 있는 방법으로 수정하는 방법을 알아볼 것이다.

1. HTML 커스텀하기

지난 글에 이어서, 유저가 자신의 프로필 사진을 올릴 수 있게 되었다고 하자.
파일 업로드에 대해서는 다음에 다루기로 하고, 일단 이미지의 주소를 받을 것이다.

from django.db import models
from django.utils import timezone
from datetime import timedelta
from django.contrib import admin

class User(models.Model):
	id = models.CharField(primary_key=True, verbose_name="아이디",max_length=200)
	user_name = models.CharField(verbose_name="이름",max_length=200)
	user_pass = models.CharField(verbose_name="비밀번호",max_length=200)
	recent_login = models.DateTimeField( verbose_name="최근 로그인", )
	updated_at = models.DateTimeField(auto_now=True, verbose_name="수정일", )
	created_at = models.DateTimeField(auto_now_add=True, verbose_name="생성일", )
 
	user_img_url = models.CharField(verbose_name="유저 이미지 주소",max_length=200)
 
	def __str__(self):
		return f"{self.id} ({self.user_name})"

	@admin.display(
		boolean=True,
  		description="최근 로그인 여부"
	)
	def isRecentlyLogined(self):
		recent = timezone.now() - timedelta(days=10)
		return self.recent_login > recent
		
	class Meta:
		managed = True
		db_table = 'user' 
		verbose_name_plural = '유저' 

모델이나 데이터베이스에 변경사항이 발생하면 반드시 아래 코드를 실행시켜 데이터베이스와 모델을 동기화 시켜주어야 한다.

  python3 manage.py makemigrations
  python3 manage.py migrate

모델에서 managedTrue로 두면 위 코드를 실행했을때 모델에 작성한 대로 데이터베이스가 변경된다.
이러한 변경을 원하지 않을 경우 managed를 반드시 False로 두어야 한다.

이미지 주소는 받았는데, 이미지가 어떤 이미지인지는 주소를 복사해 주소창에 붙여넣어야만 알 수 있다.

이 이미지를 미리보기로 보여주려면 어떻게 해야할까?

1. HTML 넣기

지난 글에서 모델과 어드민 양쪽에서 커스텀 항목을 추가하는 방법에 대해 다뤘는데, 모델이 복잡해지는 것을 별로 좋아하지 않으므로 어드민쪽의 코드만 설명해보려고 한다. 기본적인 내용은 동일하므로 모델쪽에서도 스스로 추가해볼 수 있을 것이다.

from django.contrib import admin
from .models import User
from django.utils import timezone
from datetime import timedelta

from django.utils.html import mark_safe

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')

    @admin.display(
		boolean=True,
  		description="최근 로그인 여부"
	)
    def isRecentlyLogined2(self, obj):
        recent = timezone.now() - timedelta(days=10)
        return obj.recent_login > recent
    
    @admin.display(
  		description="이미지 미리보기"
	)
    def imgThumbnail(self,obj):
        return mark_safe(f"<img src='{obj.user_img_url}' />")
		

admin_site.register(User, UserAdmin)

이번에 추가된 imgThumbnail을 살펴보자

1) mark_safe

장고는 모든 텍스트를 escape 시켜 전달한다.
따라서 아무리 포맷에 맞는 html 코드 문자열을 넘겨주어도 텍스트 그 자체로 출력될 뿐, html로 변환되어 표시되지 않는다.
이 텍스트에 대해 escape를 생략하도록 하는 것이 mark_safe라는 함수이다.
mark_safe로 감싸면 해당 문자열을 escape 시키지 않고 그대로 출력한다.

2) f-string

따옴표 앞에 f를 붙여주면 포맷팅을 간편하게 할 수 있다.
f"{변수}" 식으로 써주면 변수의 값이 출력된다.

이렇게 하면 이미지 html이 그대로 출력되어 썸네일을 확인할 수 있다.

2. JS 넣기

하지만 아직 부족하다.

url을 수정해도 반드시 저장을 해야만 썸네일을 확인할 수 있다.
링크 수정 후 썸네일 확인하기 버튼을 누르면 변경될 썸네일을 미리보기 하고 싶다.

1) 버튼 추가하기

먼저 버튼을 추가하자


...

    @admin.display(
  		description="이미지 미리보기"
	)
    def imgThumbnail(self,obj):
        return mark_safe(f"""
                         <img src='{obj.user_img_url}' id='previewImg'/>
                         <button type='button' id='previewBtn'> 이미지 미리보기</button></button>
                         """)
                         
...
		


버튼이 생겼다!

2-1) 기능 만들기(django가 .js를 찾을 수 있도록 하기)

버튼에 자바스크립트로 기능을 추가해야한다.

자바스크립트는 클라이언트가 url로 접근할 수 있어야하므로 접근 가능한 static 폴더에 들어 있어야한다.
settings.py에 현재 프로젝트 루트에 static 폴더를 놓을거라고 알려줘야 js를 찾을 수 있다.
STATICFILES_DIRS 을 설정하자.


BASE_DIR = Path(__file__).resolve().parent.parent

...

STATICFILES_DIRS = [
    BASE_DIR / "static",
]
...

자세한 내용은 django docs를 참고하면 된다.

2-2) 기능 만들기(js 작성)

프로젝트의 루트에 static폴더를 생성하고, js 폴더 내부에 imgPreview.js 파일을 생성한다.

window.addEventListener('load', ()=>{
	previewBtn.addEventListener("click", () => {
		previewImg.src = id_user_img_url.value;

	});
})

window가 로딩 된 뒤에 동작하도록 load 이벤트 리스너 내부에서 previewBtn에 클릭 이벤트를 붙인다.
클릭시 동작하는 내용은 previewImg의 src가 내가 입력한 이미지 값으로 바뀌는 것이다.

언제부터인지는 모르지만 엘리먼트의 id를 이용해 요소에 바로 접근할 수 있게 되었다. getElementById를 하지 않아도 되어서 코드가 깔끔해졌다!

참고로, django 모델에서 불러온 필드는 자동으로 id_필드네임으로 아이디를 가진다.

3) 어드민에 js 연결하기

해당 어드민에서 불러올 js 는 어드민 내부의 Media 클래스에 적어주면 된다.


class UserAdmin(admin.ModelAdmin):
	...
    class Media:
        js = ( '/static/js/imgPreview.js', )

이렇게 하면 저장하지 않아도 이미지 미리보기 버튼을 눌렀을때 이미지가 변하는 것을 확인할 수 있다.

3. css 넣기

기능은 만족스러운데, 이제 버튼이 너무 못생긴게 거슬린다.
버튼 자체에 css를 추가해보자.

1) css파일 만들기

위에서 static 폴더 설정은 완료했으므로, static/css/custom.css를 만들자.

button{
	background: #4caf50;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    color: white;
    cursor: pointer;
}

2) 어드민에서 css 불러오기

css는 불러오는 방식이 js와 유사하다. 어드민 하단에 다음 코드를 추가하면 된다.


class UserAdmin(admin.ModelAdmin):
	...
    class Media:
        js = ( '/static/js/imgPreview.js', )
        css = {'all': ('/static/css/custom.css', )}
		

성공적으로 css를 변경했다!



상세 코드는 다음을 참고:

https://github.com/hokim2407/django-admin_study/tree/a4cecd66f49fbf566f26fc003fc1abda5aac4c8b

0개의 댓글