지난 글에서는 추가적으로 어드민에서 보여주고 싶은 항목을 추가하는 작업을 했다. 이번 글에서는 그 항목을 조금 더 자유도 있는 방법으로 수정하는 방법을 알아볼 것이다.
지난 글에 이어서, 유저가 자신의 프로필 사진을 올릴 수 있게 되었다고 하자.
파일 업로드에 대해서는 다음에 다루기로 하고, 일단 이미지의 주소를 받을 것이다.
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
모델에서
managed
를True
로 두면 위 코드를 실행했을때 모델에 작성한 대로 데이터베이스가 변경된다.
이러한 변경을 원하지 않을 경우managed
를 반드시False
로 두어야 한다.
이미지 주소는 받았는데, 이미지가 어떤 이미지인지는 주소를 복사해 주소창에 붙여넣어야만 알 수 있다.
이 이미지를 미리보기로 보여주려면 어떻게 해야할까?
지난 글에서 모델과 어드민 양쪽에서 커스텀 항목을 추가하는 방법에 대해 다뤘는데, 모델이 복잡해지는 것을 별로 좋아하지 않으므로 어드민쪽의 코드만 설명해보려고 한다. 기본적인 내용은 동일하므로 모델쪽에서도 스스로 추가해볼 수 있을 것이다.
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
을 살펴보자
장고는 모든 텍스트를 escape 시켜 전달한다.
따라서 아무리 포맷에 맞는 html 코드 문자열을 넘겨주어도 텍스트 그 자체로 출력될 뿐, html로 변환되어 표시되지 않는다.
이 텍스트에 대해 escape를 생략하도록 하는 것이 mark_safe
라는 함수이다.
mark_safe
로 감싸면 해당 문자열을 escape 시키지 않고 그대로 출력한다.
따옴표 앞에 f를 붙여주면 포맷팅을 간편하게 할 수 있다.
f"{변수}"
식으로 써주면 변수의 값이 출력된다.
이렇게 하면 이미지 html이 그대로 출력되어 썸네일을 확인할 수 있다.
하지만 아직 부족하다.
url을 수정해도 반드시 저장을 해야만 썸네일을 확인할 수 있다.
링크 수정 후 썸네일 확인하기 버튼을 누르면 변경될 썸네일을 미리보기 하고 싶다.
먼저 버튼을 추가하자
...
@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>
""")
...
버튼이 생겼다!
버튼에 자바스크립트로 기능을 추가해야한다.
자바스크립트는 클라이언트가 url로 접근할 수 있어야하므로 접근 가능한 static 폴더에 들어 있어야한다.
settings.py에 현재 프로젝트 루트에 static 폴더를 놓을거라고 알려줘야 js를 찾을 수 있다.
STATICFILES_DIRS
을 설정하자.
BASE_DIR = Path(__file__).resolve().parent.parent
...
STATICFILES_DIRS = [
BASE_DIR / "static",
]
...
자세한 내용은 django docs를 참고하면 된다.
프로젝트의 루트에 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_필드네임
으로 아이디를 가진다.
해당 어드민에서 불러올 js 는 어드민 내부의 Media 클래스에 적어주면 된다.
class UserAdmin(admin.ModelAdmin):
...
class Media:
js = ( '/static/js/imgPreview.js', )
이렇게 하면 저장하지 않아도 이미지 미리보기 버튼을 눌렀을때 이미지가 변하는 것을 확인할 수 있다.
기능은 만족스러운데, 이제 버튼이 너무 못생긴게 거슬린다.
버튼 자체에 css를 추가해보자.
위에서 static 폴더 설정은 완료했으므로, static/css/custom.css를 만들자.
button{
background: #4caf50;
padding: 10px 15px;
border: none;
border-radius: 4px;
color: white;
cursor: pointer;
}
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