Search
Duplicate

Admin

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
๋ณต์‚ฌ