Django Admin
1. Django Admin ๊ฐ์
ํญ๋ชฉ | ์ค๋ช
|
๊ธฐ๋ฅ | ๋ฐ์ดํฐ ๊ด๋ฆฌ ์ธํฐํ์ด์ค ์๋ ์์ฑ |
์์น | /admin/ ๊ฒฝ๋ก ๊ธฐ๋ณธ ์ ๊ณต |
์ฅ์ | DB ํ
์ด๋ธ์ ๋ํ CRUD UI ์๋ ์ ๊ณต |
์ ์ ์กฐ๊ฑด | superuser ์์ฑ ํ์ |
2. ๊ด๋ฆฌ์(superuser) ์์ฑ
python manage.py createsuperuser
Shell
๋ณต์ฌ
์คํ ํ username, email, password ์
๋ ฅ
3. admin ์ฌ์ดํธ ์ ์
โข
โข
๋ก๊ทธ์ธ: ์์์ ์์ฑํ superuser ๊ณ์
4. ๋ชจ๋ธ admin์ ๋ฑ๋กํ๊ธฐ
์์ ๋ชจ๋ธ
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
Python
๋ณต์ฌ
๋ฑ๋ก ๋ฐฉ๋ฒ
# admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Python
๋ณต์ฌ
๋ฑ๋ก๋ง ํ๋ฉด /admin/์์ ์๋์ผ๋ก ๊ด๋ฆฌ UI ์ ๊ณต๋ฉ๋๋ค! 


5. Admin ์ปค์คํฐ๋ง์ด์ง
์์: PostAdmin ํด๋์ค ์ ์
# admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'created_at') # ๋ชฉ๋ก์ ๋ณด์ด๋ ํ๋
search_fields = ('title',) # ๊ฒ์
list_filter = ('created_at',) # ํํฐ๋ง
ordering = ('-created_at',) # ์ ๋ ฌ
Python
๋ณต์ฌ
6. ์ปค์คํ
User ๋ชจ๋ธ admin ๋ฑ๋ก ์์
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ['username', 'email', 'nickname', 'is_staff']
fieldsets = UserAdmin.fieldsets + (
('์ถ๊ฐ ์ ๋ณด', {'fields': ('nickname', 'phone')}),
)
Python
๋ณต์ฌ
7. ForeignKey ๊ด๊ณ ์ inline ์ฌ์ฉ
# models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
text = models.TextField()
Python
๋ณต์ฌ
# admin.py
class CommentInline(admin.TabularInline):
model = Comment
extra = 1
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
inlines = [CommentInline]
Python
๋ณต์ฌ
์ค์ต ๊ณผ์ ์์
์ค์ต๋ช
| ๋ชฉํ |
๊ธฐ๋ณธ Post ๋ชจ๋ธ admin ๋ฑ๋ก | ๋ฑ๋ก๋ง ํด๋ CRUD UI ์ ๊ณต๋จ ํ์ธ |
list_display ์ค์ | ๋ชฉ๋ก์ ID, ์ ๋ชฉ, ๋ ์ง ํ์ |
search ๊ธฐ๋ฅ ์ถ๊ฐ | ์ ๋ชฉ์ผ๋ก ๊ฒ์ |
ํํฐ ์ถ๊ฐ | ๋ ์ง๋ณ ํํฐ๋ง |
์ปค์คํ
User ๋ชจ๋ธ ๋ฑ๋ก | nickname, phone ํ์ |
inline ๊ด๊ณ ๊ตฌํ | ๊ฒ์๊ธ์ ๋๊ธ inline์ผ๋ก ๊ด๋ฆฌ |
์์ฝ
ํญ๋ชฉ | ์ค๋ช
|
๊ธฐ๋ณธ ๋ฑ๋ก | admin.site.register()๋ก ๊ฐ๋จํ ๊ด๋ฆฌ UI ์์ฑ |
์๋ํ | ๋ชจ๋ธ ๊ตฌ์กฐ ๊ธฐ๋ฐ์ผ๋ก CRUD ์ธํฐํ์ด์ค ์๋ ์์ฑ |
์ปค์คํฐ๋ง์ด์ง | ModelAdminํด๋์ค๋ก ๊ฒ์/ํํฐ/์ ๋ ฌ/inline ๊ธฐ๋ฅ ์ถ๊ฐ |
ํ์ฅ์ฑ | ์ปค์คํ
User ๋ชจ๋ธ ํฌํจ ๋ชจ๋ ๋ชจ๋ธ ๊ด๋ฆฌ ๊ฐ๋ฅ |
Django Admin ํ์ฅ ์ค์ต ์๋ฃ
๋ฒํธ | ์ฃผ์ | ์ค๋ช
|
1 | readonly_fields | ์ฝ๊ธฐ ์ ์ฉ ํ๋ ์ง์ (์์ ๋ถ๊ฐ ํ๋) |
2 | prepopulated_fields | ์ ๋ชฉ ์
๋ ฅ ์ slug ์๋ ์์ฑ |
3 | actions | ์ ํ ํญ๋ชฉ์ ๋ํ ์ผ๊ด ์์
์ ์ |
4 | formfield_overrides | ๊ด๋ฆฌ์ ํ์ด์ง์์ ์์ ฏ ์ปค์คํฐ๋ง์ด์ง |
5 | list_display | ๋ชฉ๋ก ํ๋ฉด์์ ํ์ํ ํ๋ ์ง์ |
6 | search_fields | ๊ฒ์์ฐฝ์์ ๊ฒ์ํ ํ๋ ์ค์ |
7 | list_filter | ์ฌ์ด๋ ํํฐ๋ฐ๋ก ๋ชฉ๋ก ํํฐ๋ง ๊ธฐ๋ฅ ์ ๊ณต |
8 | ์ปค์คํ
User ๋ฑ๋ก | CustomUser ๋ชจ๋ธ์ admin์ ๋ฑ๋กํ๊ณ ํ๋ ํ์ |
9 | Inline ๊ด๊ณ | ๋ถ๋ชจ(admin)์์ ์์ ๋ชจ๋ธ ๊ด๋ฆฌ |
1. readonly_fields โ ์ฝ๊ธฐ ์ ์ฉ ํ๋ ์ง์
๊ฐ๋
ํน์ ํ๋๋ ์์ ์์ด ๋ณด๊ธฐ๋ง ๊ฐ๋ฅํ๊ฒ ์ค์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
์ค์ต ๋ชฉํ
โข
created_at, updated_at ํ๋๋ฅผ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ค์
์ค์ต ์ฝ๋
# board/admin.py
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
readonly_fields = ('created_at', 'updated_at')
Python
๋ณต์ฌ
2. prepopulated_fields โ slug ์๋ ์์ฑ
๊ฐ๋
slug ํ๋๋ฅผ title ์
๋ ฅ ์ ์๋์ผ๋ก ์ฑ์์ค
slug๋?
์์ด ์๋ฌธ์ + ์ซ์ + ํ์ดํ(-) ์ผ๋ก ๊ตฌ์ฑ๋ URL-friendly ๋ฌธ์์ด
โข
์์
์ ๋ชฉ (title) | slug | URL |
"์ฅ๊ณ ๊ด๋ฆฌ์ ์ค์ " | django-admin-settings | /post/django-admin-settings |
"ํ์ด์ฌ ์น ํฌ๋กค๋ง ์
๋ฌธ" | python-web-crawling | /post/python-web-crawling |
URL Slug ์ค์
1.
๋ชจ๋ธ ์ค์ : slug ํ๋ ์ถ๊ฐ
2.
๊ด๋ฆฌ์ ์ค์ : ์๋ ์ฌ๋ฌ๊ทธ ์์ฑ
a.
post(๊ฒ์๊ธ)์ ๊ฒฝ์ฐ ์ ๋ชฉ(title)์ ๊ธฐ์ค์ผ๋ก ์ฌ๋ฌ๊ทธ ์๋ ์์ฑ
3.
URL ์ค์
a.
urls.py ์ค์ ํ์ผ์์ slug ๋ก URL ๋งคํ ์ค์
4.
View ์ค์
a.
ํน์ ๋ฐ์ดํฐ๋ฅผ slug ํ๋ ๊ธฐ์ค์ผ๋ก ์กฐํ
5.
Tempate ์์ฑ
a.
templates/blog/post/post_detail.html
์ค์ต ๋ชฉํ
์ ๋ชฉ ์
๋ ฅ โ slug ์๋ ์์ฑ
์ค์ต ์ฝ๋
slug ํ๋ ์ถ๊ฐ
# board/models.py
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
Python
๋ณต์ฌ
๊ด๋ฆฌ์ ์ค์ : ์๋ ์ฌ๋ฌ๊ทธ ์์ฑ
# board/admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
Python
๋ณต์ฌ
URL ์ค์
from django.urls import path
from . import views
urlpatterns = [
path('post/<slug:slug>', views.post_detail, name='post_detail'),
]
Python
๋ณต์ฌ
View ์ค์
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from .models import Post
# Create your views here.
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
return render(request, 'blog/post_detail.html', {'post': post})
Python
๋ณต์ฌ
Template ์์ฑ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>๊ฒ์๊ธ ์กฐํ - {{post.title}}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
<hr>
<table border="1">
<tr>
<th>์์ฑ์</th>
<td>{{ post.user.nickname }}</td>
</tr>
<tr>
<th>์์ฑ์ผ</th>
<td>{{ post.created_at|date:"Y-m-d H:i:s" }}</td>
</tr>
<tr>
<td colspan="2">
<div class="post-content">
{{ post.content|safe }}
</div>
</td>
</tr>
</table>
</body>
</html>
Python
๋ณต์ฌ
ํ๊ธ๋ช ์ ๋ชฉ์ผ๋ก Slug ์๋ ์์ฑํ๊ธฐ
1.
python-slugify ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
2.
slugify ์ slugify() ํจ์ ์ฌ์ฉ
python-slugify ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
pip install python-slugify
Python
๋ณต์ฌ
slugify ์ slugify() ํจ์ ์ฌ์ฉ
๋ชจ๋ธ์ save() ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ, slugify() ์ ์ฉ
# ๋ชจ๋ธ์ save() ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ, slugify() ์ ์ฉ
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title) # ํ๊ธ๋ช
์ ์ ๋ชฉ์ slug๋ก ๋ณํํฉ๋๋ค.
# slugify() ํจ์๋ ๋ฌธ์์ด์ URL-friendlyํ ํ์์ผ๋ก ๋ณํํฉ๋๋ค.
super().save(*args, **kwargs)
Python
๋ณต์ฌ
3. actions โ ์ปค์คํ
๊ด๋ฆฌ์ ์ผ๊ด ์์
๊ฐ๋
์ ํ๋ ๊ฐ์ฒด์ ๋ํด ์ผ๊ด ์ฒ๋ฆฌ ํจ์ ์คํ
์ค์ต ๋ชฉํ
โข
๊ฒ์๊ธ์ ํ ๋ฒ์ ๊ณต๊ฐ ์ํ๋ก ๋ณ๊ฒฝํ๋ ์ก์
๊ตฌํ
์ค์ต ์ฝ๋
# board/models.py
class Post(models.Model):
title = models.CharField(max_length=100)
is_public = models.BooleanField(default=False)
Python
๋ณต์ฌ
# board/admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
actions = ['make_public']
@admin.action(description="์ ํํ ๊ธ์ ๊ณต๊ฐ์ฒ๋ฆฌ")
def make_public(self, request, queryset):
queryset.update(is_public=True)
Python
๋ณต์ฌ
4. formfield_overrides โ ์์ ฏ ์ปค์คํฐ๋ง์ด์ง
๊ฐ๋
๋ชจ๋ธ ํ๋์ ์ฐ๊ฒฐ๋ ํผ ์์ ฏ์ ์ปค์คํฐ๋ง์ด์ง
์ค์ต ๋ชฉํ
โข
TextField๋ฅผ Textarea๋ก ์ค ์ ์ค์
์ค์ต ์ฝ๋
from django.db import models
from django.forms import Textarea
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea(attrs={'rows': 3, 'cols': 60})},
}
Python
๋ณต์ฌ
5. list_display โ ๋ชฉ๋ก ํ๋ ์ค์
๊ฐ๋
๊ด๋ฆฌ์ ๋ชฉ๋ก ํ์ด์ง์์ ๋ณด์ฌ์ค ํ๋ ์ง์
์ค์ต ๋ชฉํ
โข
ID, ์ ๋ชฉ, ์์ฑ์ผ ์ถ๋ ฅ
์ค์ต ์ฝ๋
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'created_at')
Python
๋ณต์ฌ
6. search_fields โ ๊ฒ์ ๊ธฐ๋ฅ ์ถ๊ฐ
๊ฐ๋
๊ฒ์์ฐฝ์ ํตํด ํน์ ํ๋ ๊ฒ์ ๊ฐ๋ฅ
์ค์ต ๋ชฉํ
โข
์ ๋ชฉ ๊ธฐ์ค์ผ๋ก ๊ฒ์ ๊ฐ๋ฅํ๊ฒ ์ค์
์ค์ต ์ฝ๋
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
search_fields = ('title',)
Python
๋ณต์ฌ
7. list_filter โ ํํฐ ๊ธฐ๋ฅ ์ถ๊ฐ
๊ฐ๋
์ฌ์ด๋ ํํฐ๋ฐ๋ก ๋น ๋ฅธ ํํฐ๋ง ์ ๊ณต
์ค์ต ๋ชฉํ
โข
์์ฑ์ผ ๊ธฐ์ค์ผ๋ก ํํฐ ๊ฐ๋ฅ
์ค์ต ์ฝ๋
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_filter = ('created_at',)
Python
๋ณต์ฌ
8. ์ปค์คํ
User ๋ชจ๋ธ ๋ฑ๋ก
์ค์ต ๋ชฉํ
โข
CustomUser ๋ชจ๋ธ์ Admin์ ๋ฑ๋ก
โข
๋ชฉ๋ก์ username, nickname, phone ํ์
์ค์ต ์ฝ๋
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
nickname = models.CharField(max_length=30)
phone = models.CharField(max_length=20)
Python
๋ณต์ฌ
# accounts/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
fieldsets = UserAdmin.fieldsets + (
('์ถ๊ฐ ์ ๋ณด', {'fields': ('nickname', 'phone')}),
)
list_display = ('username', 'nickname', 'phone', 'is_staff')
Python
๋ณต์ฌ
9. Inline ๊ด๊ณ ์ค์ต โ ๋๊ธ ๊ด๋ฆฌ
๊ฐ๋
๋ถ๋ชจ ๋ชจ๋ธ ํ์ด์ง์์ ์์ ๋ชจ๋ธ์ Inline์ผ๋ก ํจ๊ป ๊ด๋ฆฌ
์ค์ต ๋ชฉํ
โข
๊ฒ์๊ธ(Post) ํ์ด์ง์์ ๋๊ธ(Comment) ๊ด๋ฆฌ
์ค์ต ์ฝ๋
# board/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField()
Python
๋ณต์ฌ
# board/admin.py
class CommentInline(admin.TabularInline):
model = Comment
extra = 1
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
inlines = [CommentInline]
Python
๋ณต์ฌ