๐ฅ Admin Panel์ ์ด๋ฏธ์ง ํ์ผ ๋ํ๋ด๊ธฐ
- BASE_DIR ๊ธฐ์ค์ผ๋ก ๋ชจ๋ file๋ค์ด ์ ์ฅ๋ ์์น๋ settgins.py์ MEDIA_ROOT๋ฅผ ํตํด ์ค์ ํ ์ ์์ด์!
1) settgins.py & .gitignore
- MEDIA_ROOT๋ ImageField๋ก ์
๋ก๋๋๋ ์ด๋ฏธ์ง ํ์ผ์ด ์ ์ฅ๋ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋๋ฐ ์ฌ์ฉํด์.
- BASE_DIR์ Project ๋๋ ํ ๋ฆฌ๋ฅผ ์๋ฏธํด์,, ์ด์ Project ๋๋ ํ ๋ฆฌ ๋ด์ "uploads"์ ์ด๋ฏธ์งํ์ผ์ ์ ์ฅํ๋ ค๋ฉด ์๋์ฒ๋ผ ์ค์ ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
- ๐ MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
- "uploads" ๋๋ ํ ๋ฆฌ ๋ด์ ์ด๋ฏธ์ง ํ์ผ์ .gitignore์ ์ฌ๋ฆฌ์ง ์๊ธฐ ์ํด์๋ .gitignore์ ํด๋น ๋๋ ํ ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
๐ settgins.py
MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
๐ .gitignore
uploads/
2) upload_to
- ์ด๋ฏธ์ง ํ์ผ๋ค์ด ์ ์ฅ๋ "uploads" ๋๋ ํ ๋ฆฌ์ ๋ด์ ๋ชจ๋ ์ฌ์ง์ด ์ ์ฅ๋๋ฉด ์ด๋ ๋ชจ๋ธ์์ ์ ์ฅ๋ ์ด๋ฏธ์ง ํ์ผ์ธ์ง ํ์
ํ๋๋ฐ ์ด๋ ค์์ด ๋ฐ์ํฉ๋๋ค.
- ์ด์ ํด๋น ๋ชจ๋ธ์ ํ๋์ ๋ฐ๋ผ ์
๋ก๋ ๋๋ ์ด๋ฏธ์ง ํ์ผ์ ๊ตฌ๋ถํ๊ธฐ ์ํด "upload_to" ์ฌ์ฉํ ์ ์์ด์!
<class Photo(core_models.TimeStampedModel):
"""Photo Model Definition"""
caption = models.CharField(max_length=80)
file = models.ImageField(upload_to="room_photos",)
room = models.ForeignKey("Room", related_name="photos", on_delete=models.CASCADE)
def __str__(self):
return self.caption
1) settgins.py
- ์น๋ธ๋ผ์ฐ์ ์์ URL์ ํตํด ์ ์ฅ๋ ์ด๋ฏธ์ง ํ์ผ์ ์ ๊ทผํ ๋, ์ด๋ค ๊ฒฝ๋ก์์ ํด๋น file์ ํ์ํ ์ง ์ง์ ํด์ฃผ๋ ๊ฒ์ด MEDIA_URL ์ด์์!
๐ settgins.py
MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
MEDIA_URL = "/media/"
2) config.urls.py
- MEDIA_ROOT์ MEDIA_URL์ ์ค์ ํ๊ณ ๊ฒฝ๋ก๋ก ์ด๋ฏธ์ง ํ์ผ์ ํ์ํ ๋์๋์ ๊ฐ์ ์ค๋ฅ ๋ฐ์ํ๋ ๊ฒ์ urls.py์ ๊ฒฝ๋ก ์ค์ ์ด ๋์ง ์์๊ธฐ ๋๋ฌธ์ด์์
- ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๊ธฐ ์ํด urls.py์์ settgins.py์ ์ ๊ทผํด์ผํ๋๋ฐ์,, ํ์ผ์ ์ํฌํธํ๋๊ฒ ์๋๋ผ, ํ์ผ์ ๋ฐ์ํ ๋ด์ฉ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด settgins.py๋ ์๋์ ๊ฐ์ด import ํฉ๋๋ค.
- ๐ from django.conf import settings
- Django์์ ์ ์ ํ์ผ์ ์ ๊ณตํ๊ธฐ ์ํด์ static์ import ํด์ผ ํด์!
- ๐ from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("admin/", admin.site.urls),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
3. Admin Panel์ ์ด๋ฏธ์ง ํ์ผ ๋ํ๋ด๊ธฐ
1) Outline Admin Panel
- ์ด๋ฏธ์ง ํ์ผ์ Admin Panel์ ๋ํ๋๊ธฐ ํ๊ธฐ ์ํด ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ฅผ img ํ๊ทธ์ ๋ด์ returnํด ๋ณผ๊ป์:)
@admin.register(models.Photo)
class PhotoAdmin(admin.ModelAdmin):
"""Photo Admin Dfinition"""
list_display = ("__str__", "get_thumbnail", )
def get_thumbnail(self, obj):
return f"<img src="{obj.file.url}"/>"
get_thumbnail.short_description = "Thumbnail"
- ๋ฐํํ์๋๋,, ์ด๋ฏธ์ง๊ฐ ์๋ string์ผ๋ก ๋ํ๋ฉ๋๋ค
- ์ด๋ XSS(Cross-Site Scripting)์ ๊ฐ์ ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ Django๊ฐ ์น์ฌ์ดํธ๋ฅผ ๋ณดํธํ๊ณ ์๊ธฐ ๋๋ฌธ์ด์์! ์ด์ Django์๊ฒ ์ด "tag๋ ์์ ํ html tag์ผ"๋ผ๊ณ ์๋ ค์ค์ผํ๋๋ฐ์,, ์ด๋ด ๋ mark_safe()๋ฅผ ์ฌ์ฉํฉ๋๋ค. mark_safe() ์๋ ์์นํ๊ณ ์์ด์!
- ๐ from django.utils.html import mark_safe
from django.utils.html import mark_safe
@admin.register(models.Photo)
class PhotoAdmin(admin.ModelAdmin):
"""Photo Admin Dfinition"""
list_display = ("__str__", "get_thumbnail", )
def get_thumbnail(self, obj):
return mark_safe(f'<img width="50px" src="{obj.file.url}"/>')
get_thumbnail.short_description = "Thumbnail"
2) Inline Admin Panel
- Admin ์์ ๋ค๋ฅธ Admin์ ๊ฐ์ ธ์ ๋ํ๋ผ ์ ์๋ ๋ฐฉ๋ฒ์ InlineModelAdmin ๊ธฐ๋ฅ์ด๋ผ ํ๋๋ฐ์,, InlineModelAdmin ์ฌ์ฉํ๊ธฐ ์ํด์๋ Inline์ ํ์ํ ๋ชจ๋ธ์ Class๋ก ๋ง๋ ๋ค, ๋ํ๋ด๊ณ ์ํ๋ Admin Class ๋ด๋ถ์ "inline" ์์ฑ์ผ๋ก ํ์ํ ๋ชจ๋ธ์ ํด๋์ค๋ฅผ ๋ช
์ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
- ์ด๋ ๊ฒ ๋ด๋ถ์ Admin Panel์ ๊ฐ์ ธ์ ์ฌ์ฉํ๋ฉด, Admin Site๋ฅผ ์ด๋ํ๋ฉฐ ์์
ํ๋ ์๊ณ ๋ฅผ ์ค์ฌ์ค๋๋ค:)
from django.contrib import admin
from . import models
class PhotoInline(admin.TabularInline):
model = models.Photo
@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):
"""Room Admin Dfinition"""
inlines = (PhotoInline,)