
목표
- Django에서 기본적으로 제공하는 기능을 더 자세하게 알아본다.
- Django 내장 기능을 활용해 효율적으로 개발할 수 있는 방법을 알아본다.
이메일 보내기
- 내장된 이메일 기능을 사용하면 간단하게 이메일 전송 구현 가능
# config/settings.py
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.gmail.com"
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = "이메일 주소"
EMAIL_HOST_PASSWORD = "App Password"
Google App Password 발급
- Google 계정 보안 탭으로 이동 (https://myaccount.google.com/security)
- 2단계 인증(2-Step Verification) 설정
- 앱 비밀번호(또는 App Passwords) 검색
- 앱 생성 후, 비밀번호 복사
Text 이메일 보내기
- 내장된 send_mail() 함수 사용
# utils.py
from django.core.mail import send_mail
from django.conf import settings
def send_str_email(email_to):
send_mail(
'새로운 이메일이 도착했습니다.', # 이메일 제목
'안녕하세요. Django에서 보낸 이메일입니다.', # 이메일 본문
settings.EMAIL_HOST_USER, # 발신 이메일
[email_to], # 수신자 이메일 리스트
)
HTML 이메일 보내기
- templates 디렉토리 생성
# config/settings.py
TEMPLATES = [
{
…,
'DIRS': [
BASE_DIR / 'templates',
],
…,
}
HTML 이메일 보내기
# templates/email.html
Hello!!!
구글로 이동
# utils.py
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
def send_html_email(email_to):
subject = "새로운 이메일이 도착했습니다."
html = render_to_string("email.html")
message = EmailMessage(
subject, html, settings.EMAIL_HOST_USER, [email_to] # 이메일 받을 계정
)
message.content_subtype = "html"
message.send()
Django Commands
- Django에서 특정 작업을 명령어로 실행할 수 있도록 하는 기능
- python manage.py send_email html recipient@example.com
# django_orm/management/commands/send_email.py
from django.core.management.base import BaseCommand, CommandError
from utils import send_str_email, send_html_email
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument("format", type=str)
parser.add_argument("email_to", type=str)
def handle(self, *args, **kwargs):
if kwargs["format"] == "str":
send_str_email(email_to=kwargs["email_to"])
elif kwargs["format"] == "html":
send_html_email(email_to=kwargs["email_to"])
else:
raise CommandError('잘못된 포맷입니다. "str" 또는 "html"만 가능합니다.')
- crom job을 사용할 때 미리 commnads를 만들어 두면 매우 유용하게 쓸 수 있다.
- 파라미터도 정의할 수 있다.

이 패키지 명을 꼭 지켜야함
from django.core.management.base import BaseCommand
from utils import send_str_email, send_html_email
# python manage.py send_email 'html' recipient@example.com
class Command(BaseCommand):
def add_arguments(self, parser): # 명령어에 인자를 추가할 때 사용하는 메서드
parser.add_argument("format", type=str) # str 형식의 format 인자 추가
parser.add_argument("email_to", type=str) # str 형식의 email 인자 추가
def handle(self, *args, **options): # 실제로 명령어가 실행될 때 호출되는 메서드
match options["format"]:
case "str":
send_str_email(email_to=options["email_to"])
case "html":
send_html_email(email_to=options["email_to"])
case _:
raise CommandError("잘못된 포맷입니다. 'str' 또는 'html'만 허용합니다.")
if options["format"] == "str":
send_str_email(email_to=options["email"])
elif options["format"] == "html":
from hands_on.utils import send_html_email
send_html_email(email_to=options["email"])
else:
raise CommandError("잘못된 포맷입니다. 'str' 또는 'html'만 허용합니다.")
- match 를 써서 if문을 깔끔하게 정리할 수 있다.
@click.argument("user", type=click.ModelInstance(User))
def command(user):
print(user.username)
@app.command()
def main(
count: int | None = typer.Argument(None),
file: str = typer.Option("data/movies.json"),
clear: bool = typer.Option(False),
):
...
Cache
- 성능을 향상시키기 위해 요청에 대한 데이터를 저장하고 재사용하는 메커니즘
- 메모리(RAM) 기반 저장소를 사용하여, 매우 빠른 읽기/쓰기 성능

Redis 실행(Docker)
- docker compose up -d
# docker-compose.yml
services:
…
redis:
container_name: django_redis
image: redis:7.4
ports:
- "63790:6379"
volumes:
local_db:
Redis Cache 적용
- pip install redis
- 설정된 redis로 자동으로 cache 저장
# config/settings.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:63790/1', # 기본 1번 DB 사용
}
}
Redis Cache 사용
- Python Dictionary와 같이 {key:value} 형태로 구성
- timeout 지정하면 해당 시간(초)만큼 캐싱(default: 300)
>>> from django.core.cache import cache
>>> alice_data = {"id": 1, "name": "alice", "age": "30"}
>>> cache.set(key="users:1", value=alice_data, timeout=10)
>>> cache.get("users:1")
{"id": 1, "name": "alice", "age": "30"}
>>> cache.get("users:1") # 10초가 지나면, 데이터가 만료되어 None 출력
None
>>> cache.delete("users:1")
True
- cache를 통해서 timeout을 통해 간단하게 데이터 만료 가능
>>> cache.incr("age")
22
>>> cache.incr("age", -1)
21
>>> cache.incr("age", -1)
20
>>> cache.delete("age")
True
>>> cache.get("age")
Redis Cache 활용
# utils.py
from django.core.cache import cache
EMAIL_HTML_CACHE_KEY = "email_html"
def send_html_email(email_to):
if not (html := cache.get(EMAIL_HTML_CACHE_KEY)):
print("Load New Template…")
html = render_to_string("email.html")
cache.set(EMAIL_HTML_CACHE_KEY, html)
subject = "새로운 이메일이 도착했습니다."
message = EmailMessage(
subject, html, settings.EMAIL_HOST_USER, [email_to] # 이메일 받을 계정
)
message.content_subtype = "html"
message.send()
cache_page
- 뷰에서 반환된 전체 응답을 캐싱
- 자주 변경되지 않는 페이지에 유용
from django.views.decorators.cache import cache_page
@cache_page(60) # 1분 동안 캐시
def my_view(request):
return render(request, 'my_template.html')
Django Admin
- Django에 내장되어 있는 관리자 기능
- 간편하게 데이터를 조회/추가/수정/삭제할 수 있고, 데이터 검색 & 필터링 가능
# django_orm/admin.py
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
pass
# django_orm/admin.py
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'email') # 목록에서 표시할 필드
search_fields = ('username',) # 검색 가능한 필드
list_filter = ('social_provider',) # 필터 옵션
- 개발자가 아닌 사람도 데이터에 접근을 해주기 위해서 제공해주는 기능임
Model Inline
- admin에서 관계된 모델의 데이터를 같은 화면에서 관리하는 기능
# django_orm/admin.py
class ProfileInline(admin.StackedInline):
model = Profile
extra = 1 # 기본으로 제공하는 빈 폼의 개수
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'email') # 목록에서 표시할 필드
search_fields = ('username',) # 검색 가능한 필드
list_filter = ('social_provider',) # 필터 옵션
inlines = [ProfileInline]
Admin custom action
- 관리자 화면에서 선택한 객체에 대해 직접 만든 함수를 실행할 수 있는 기능
# django_orm/admin.py
def export_as_csv(modeladmin, request, queryset):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="export.csv"'
writer = csv.writer(response)
field_names = [field.name for field in modeladmin.model._meta.fields]
writer.writerow(field_names)
for obj in queryset:
row = [getattr(obj, field) for field in field_names]
writer.writerow(row)
return response
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
…
actions = [export_as_csv]
'개발 > Django 스터디' 카테고리의 다른 글
| [Django스터디] 6. DRF를 활용한 API 개발 (0) | 2026.02.28 |
|---|---|
| [Django스터디] 4. Django ORM 이해하기 (0) | 2026.01.13 |
| [Django스터디] 3. 회원시스템 (0) | 2026.01.06 |
| [Django스터디] 2. Django 시작하기 (0) | 2025.12.09 |
| [Django스터디] 1. Django 알아보기 & 시작하기 (0) | 2025.12.04 |