Django를 쓰기 시작하며 남긴 몇 가지 메모
안녕하세요! 제가 정말 좋아하는 것 중 하나는 한 번도 써 본 적 없지만 20년 넘게 존재해 온 ‘오래되고 지루한 기술(Old Boring Technology)’을 새로 배우기 시작하는 거예요. 앞으로 마주할 모든 문제가 이미 수천 번 해결되어 있어서 그냥 편하게 일을 처리할 수 있을 때 기분이 정말 좋거든요.
Rails나 Django, Laravel 같은 인기 있는 웹 프레임워크를 배워 보면 좋겠다고 오랫동안 생각해 왔는데, 실제로 해 보지는 못했어요. 그런데 몇 달 전에 웹사이트를 만들려고 Django를 배우기 시작했고, 지금까지 꽤 마음에 들고 있어서 간단한 메모를 몇 가지 적어 보려고 해요!
Rails보다 마법이 덜해요
2020년에 Rails를 배워 보려고 잠시 시도한 적이 있는데, 멋지긴 했고 정말 Rails를 좋아하고 싶었지만(Ruby 커뮤니티는 정말 좋아요!), Rails 프로젝트를 몇 달 동안 방치했다가 돌아오면 뭘 어떻게 해야 하는지 기억하기가 어렵다는 걸 느꼈어요. 예를 들어 routes.rb에 resources :topics라고 쓰여 있어도, 그 한 줄만으로는 topics 라우트가 어디에 설정되어 있는지 알 수 없고 컨벤션을 기억하거나 찾아봐야 하거든요.
저에게는 프로젝트를 몇 달, 몇 년씩 방치했다가 다시 돌아와도 괜찮다는 게 정말 중요해요(제 프로젝트는 전부 그렇게 굴러가거든요!). Django는 훨씬 명시적이라서 저에게는 더 쉽게 느껴져요.
제 작은 Django 프로젝트에서는 설정 파일을 제외하면 주요 파일이 딱 5개 있는 느낌이에요. urls.py, models.py, views.py, admin.py, 그리고 tests.py죠. 다른 무언가(예를 들어 HTML 템플릿)가 어디 있는지 알고 싶으면 보통 이 파일들 중 하나에서 명시적으로 참조되고 있어서 찾기가 쉬워요.
내장 어드민
이번 프로젝트에서는 데이터베이스에 있는 데이터를 직접 수정하거나 조회할 수 있는 어드민 인터페이스가 필요했어요. Django에는 정말 멋진 내장 어드민이 있고, 약간의 코드만으로 커스터마이즈할 수 있어요.
예를 들어 제 어드민 클래스 중 하나의 일부인데요, 리스트 뷰에 어떤 필드를 보여줄지, 어떤 필드로 검색할지, 기본 정렬 순서는 어떻게 할지를 설정해요.
@admin.register(Zine)
class ZineAdmin(admin.ModelAdmin):
list_display = ["name", "publication_date", "free", "slug", "image_preview"]
search_fields = ["name", "slug"]
readonly_fields = ["image_preview"]
ordering = ["-publication_date"]ORM이 있으니 재미있어요
예전에는 “ORM? 누가 필요해? 그냥 SQL 직접 쓰면 되지!” 하는 태도였어요. 그런데 지금까지 Django의 ORM이 꽤 마음에 들고, Django가 JOIN을 __로 표현하는 방식이 멋지다고 생각해요. 예를 들면 이렇게요:
Zine.objects
.exclude(product__order__email_hash=email_hash)이 쿼리에는 zines, zine_products, products, order_products, orders 이렇게 5개의 테이블이 관련되어 있어요. 이걸 동작하게 하려고 제가 한 일은 Django에게 “orders”와 “products”를 연결하는 ManyToManyField가 있고, “zines”와 “products”를 연결하는 또 다른 ManyToManyField가 있다고 알려준 것뿐이에요. 그러면 Django가 zines, orders, products를 어떻게 연결해야 하는지 알게 되죠.
물론 저도 그 쿼리를 직접 쓸 수는 있어요. 하지만 product__order__email_hash라고 쓰는 게 타이핑도 훨씬 적고 훨씬 읽기 쉬우며, 솔직히 그 조인 말고도 몇 가지 더 해야 하는 쿼리를 직접 구성하려면 시간이 좀 걸릴 것 같아요.
ORM이 생성하는 쿼리 성능에 대해서는 전혀 걱정하지 않고 있어서, 지금은 ORM이 꽤 신나요. 물론 언젠가는 답답한 점도 찾게 되겠죠.
자동 마이그레이션!
ORM의 또 다른 멋진 점은 마이그레이션이에요!
models.py에서 필드를 추가하거나 삭제하거나 변경하면, Django가 migrations/0006_delete_imageblob.py 같은 마이그레이션 스크립트를 자동으로 만들어 줘요.
원하면 그 스크립트를 직접 수정할 수도 있겠지만, 지금까지는 생성된 스크립트를 그대로 실행하기만 했는데 아주 잘 되고 있어요. 정말 마법 같아요.
어떻게 동작하게 할지 고민하면서 데이터 모델을 꽤 자주 바꾸고 있는 지금, 마이그레이션을 쉽게 할 수 있다는 게 저에게 정말 중요하다는 걸 깨닫고 있어요.
문서가 좋아요
저는 문서를 절대 읽지 않는 나쁜 습관이 있었는데, 지금까지 읽어 본 Django 문서들은 정말 즐겁게 보고 있어요. 이건 우연이 아니에요. Jacob Kaplan-Moss가 PyCon 2011에서 한 발표에서 Django의 문서 문화에 대해 이야기했거든요.
예를 들어 모델 소개에서는 ORM을 사용할 때 설정하고 싶을 만한 가장 중요한 공통 필드들을 정리해 줘요.
SQLite 사용하기
Postgres를 운영해 보려다 무슨 일이 일어나고 있는지 이해할 수 없었던 안 좋은 경험 이후로, 작은 웹사이트들은 전부 SQLite로 운영하기로 했어요. 훨씬 잘 되고 있고, 그냥 VACUUM INTO를 실행한 뒤 생성된 단일 파일을 복사하는 것만으로 백업할 수 있다는 점이 정말 마음에 들어요.
Django에서 프로덕션용으로 SQLite를 쓰는 방법은 이 가이드를 따라 하고 있어요.
하루에 많아 봐야 수백 번 정도 쓰기가 발생할 것 같아서 괜찮을 거라고 생각해요. 쓰기 횟수가 훨씬 많으면서도 잘 동작하고 있는 Mess with DNS보다도 훨씬 적거든요(물론 그쪽은 쓰기가 3개의 서로 다른 SQLite 데이터베이스에 분산되어 있긴 해요).
내장 이메일 (그리고 그 외 기능들)
Django는 정말 “배터리 포함(batteries-included)”이라는 느낌이 들어서 좋아요. CSRF 보호가 필요하든, Content-Security-Policy가 필요하든, 이메일을 보내고 싶든, 모든 게 이미 들어 있거든요!
예를 들어 개발 모드에서는 Django가 보내는 이메일을 실제 사람들에게 진짜 메일이 발송되지 않도록 파일로 저장하고 싶었는데, 설정 몇 줄이면 됐어요.
settings/dev.py에 이렇게 넣었고요:
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "emails"그리고 프로덕션 이메일은 settings/production.py에 이렇게 설정했어요.
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.whatever.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "xxxx"
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_API_KEY')덕분에 다른 기본적인 웹사이트 기능이 필요하더라도 Django에 이미 쉬운 방법이 내장되어 있을 거라는 느낌이 들었어요.
settings 파일은 아직도 부담스러워요
아직도 settings.py 파일은 좀 부담스러워요. Django의 설정 시스템은 파일 안에 전역 변수들을 잔뜩 설정하는 방식으로 동작하는데, 변수 이름에 오타를 내면 어떡하지? 어떻게 알 수 있지? 만약 WSGI_APPLICATION 대신 WSGI_APPLICATOIN = "config.wsgi.application"이라고 쓰면 어떡하지? 하는 생각이 들어서 좀 스트레스예요.
아마 Python 언어 서버가 오타를 알려 주는 데 익숙해져서, 이제 언어 서버 지원에 의지할 수 없으니 좀 혼란스럽게 느껴지는 것 같아요.
일단 여기까지예요!
예전에 프로젝트에 진짜 웹 프레임워크를 제대로 써 본 적이 없어서(지금 제 웹사이트 대부분은 단일 Go 바이너리 아니면 정적 사이트예요), 앞으로 어떻게 될지 기대돼요!
아직 배울 게 많이 남았어요. Django의 폼 검증 도구나 인증 시스템은 아직 제대로 파보지도 못했거든요.
ORM에 기회를 줘 보라고 설득해 준 Marco Rogers에게 고마움을 전해요.
(아직 Mastodon 댓글 시스템을 실험 중이에요! Mastodon에서 댓글 보기! 여러분이 가장 좋아하는 Django 기능을 알려 주세요!)
글을 무작위로 읽기