Some notes on starting to use Django

Julia Evans

Django를 처음 사용하며 남긴 몇 가지 메모

원문은 Julia Evans님이 에 게재했습니다. 이 블로그 구독하기

안녕하세요! 제가 가장 좋아하는 것 중 하나는 한 번도 써본 적 없지만 20년 넘게 존재해 온, 이른바 ‘오래되고 지루한 기술(Old Boring Technology)’을 새로 배우기 시작하는 것이다. 앞으로 겪게 될 모든 문제가 이미 수천 번 해결되어 있어서 그냥 편하게 일을 처리할 수 있다는 느낌이 정말 좋다.

Rails나 Django, Laravel 같은 인기 웹 프레임워크를 배워보면 좋겠다고 오랫동안 생각해 왔지만, 좀처럼 실행에 옮기지 못했다. 그러다 몇 달 전 웹사이트를 만들려고 Django를 배우기 시작했는데, 지금까지 꽤 마음에 들고 있다. 간단히 메모를 남겨본다!

Rails보다 마법이 적다

2020년에 Rails 배우기를 시도하며 한동안 시간을 보낸 적이 있는데, 멋지긴 했고 나도 정말 Rails를 좋아하고 싶었지만(루비 커뮤니티는 정말 훌륭하다!), Rails 프로젝트를 몇 달 동안 방치했다가 돌아오면 뭘 어떻게 해야 할지 기억나지 않아 애를 먹었다. 예를 들어 routes.rbresources :topics라고 적혀 있어도, 그것만으로는 topics 라우트가 어디에 설정되어 있는지 알 수 없고 컨벤션을 기억하거나 찾아봐야 하기 때문이다.

프로젝트를 몇 달, 몇 년씩 방치했다가 다시 돌아올 수 있다는 점은 내게 정말 중요하다(내 모든 프로젝트가 그렇게 돌아간다!). Django는 훨씬 더 명시적이라서 내게는 더 쉽게 느껴진다.

내 작은 Django 프로젝트에는(설정 파일 외에) 주요 파일이 다섯 개 정도 있는 느낌이다: 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)

이 쿼리에는 5개의 테이블이 관여한다: zines, zine_products, products, order_products, 그리고 orders. 이걸 동작하게 하려고 나는 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는 Django의 문서 문화에 대해 PyCon 2011 발표를 한 적이 있다.

예를 들어 모델 소개에서는 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 기능을 알려 달라!)

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.

댓글