2022년 08월 08일 공개 , 2022년 08월 07일 수정
이 글에서는 Django 4.1에 추가된 기능과 바뀐 점을 알아보려 합니다. Django 4.1 release notes를 참고하였습니다.
Django는 3년 마다 LTS를 위해 메이저 버전을 하나씩 올리고, 8개월마다 마이너 버전을 올립니다. 현재 LTS 버전은 3.2.x입니다. 이번에 출시한 4.1은 LTS 버전은 아닙니다.

파이썬 호환성
Django 4.1은 파이썬 3.8과 3.9, 3.10을 지원합니다. 각 버전의 마지막 릴리스를 사용하기를 권장합니다.
44BITS 소식과 클라우드 뉴스를 전해드립니다. 지금 5,000명 이상의 구독자와 함께 하고 있습니다 📮
새 기능
클래스 기반 뷰에 적용할 수 있는 비동기 핸들러
Django 3.1부터 비동기 뷰가 도입됐지만 함수 기반 뷰에서만 사용할 수 있었는데요. 4.1부터는 클래스 기반 뷰에도 사용할 수 있습니다.
클래스 기반 뷰에 적용하는 비동기 핸들러에 대한 자세한 내용은 Asynchronous class-based views 문서를 참고하세요.
비동기식 ORM 인터페이스
비동기 처리용 ORM 인터페이스를 지원합니다. 기존 ORM 메서드 앞에 a를 붙은 형태의 메서드를 사용하면 됩니다. 이를테면, create 대신 acreate, first 대신 afirst 처럼요.
새 쿼리셋을 반환하는 메서드들은 별도의 인터페이스를 만들지 않았습니다. filter나 exclude, annotate 등은 비동기 코드에서 그대로 사용해도 됩니다.
하지만, 데이터베이스 연산은 아직 동기 방식으로 처리됩니다. 새 인터페이스는 기존 연산에 sync_to_async()를 감싸두었을 뿐이고요. SQL 컴파일러와 데이터베이스 드라이버에 이르기까지 비동기 지원 작업을 열심히 진행 중이라고 합니다.
그럼 비동기 ORM 인터페이스를 사용할 필요가 없을까요? 비동기 코드나 비동기 뷰에서 동기식 ORM 인터페이스를 호출하면 SynchronousOnlyOperation 오류가 발생하니, 이때 비동기식 ORM 인터페이스를 사용하면 되겠습니다. 게다가 미리 비동기식 인터페이스를 사용해두면, 추후 데이터베이스 연산이 비동기 방식으로 처리되었을 때 급하게 코드를 수정하지 않아도 되겠고요. 그리고 트랜잭션 역시 비동기 처리를 지원하지 않습니다. 트랜잭션을 사용해야 한다면 해당 코드를 분리한 다음 sync_to_async 함수로 감싸서 호출해야 합니다.
비동기식 ORM 인터페이스에 대한 자세한 내용은 Asynchronous queries 문서를 참고하세요.
모델 제약 조건을 유효성 검증 과정에 검사
Check와 unique, exclusion 같은 데이터베이스 제약 조건을 모델 유효성 검증 과정에서 검사합니다. 만약 검사에 실패하면 ValidationError 예외가 발생합니다.
Django 4.0까지는 모델 유효성 과정에 검사하지 않았고, 데이터베이스에 저장할 때 IntegrityError 예외를 발생시켰습니다.
접근성이 향상된 폼 렌더링
스크린 리더 같은 장치를 사용하는 사용자들에게도 접근하기 편한 폼을 만들고자 <div> 기반의 폼 템플릿을 제공합니다. Django 5.0에서는 새 폼 템플릿을 기본으로 사용하지만 아직은 그렇지 않으므로, 이를 적용하고 싶다면 FORM_RENDERER 설정 값을 다음처럼 정의하세요.
CSRF_COOKIE_MASKED 설정
CsrfViewMiddleware 는 더이상 CSRF 쿠키를 마스킹하지 않습니다. 만약 Django 4.1 이전 버전을 Django 4.1로 업그레이드하고 있다면 호환성을 위해 CSRF_COOKIE_MASKED를 True로 설정하고, 업그레이드가 끝난 후 CSRF_COOKIE_MASKED 설정을 지우기 바랍니다.
Django 5.0에서 CSRF_COOKIE_MASKED 설정은 사라질 예정입니다.
자잘한 변경
관리자 화면(django.contrib.admin)
- 다크 모드용 CSS를 별도로 정의할 수 있습니다. django/contrib/admin/static/admin/css/dark_mode.css 파일을 사용하세요.
- 관리자 화면의 커스텀 필터에 __in 룩업 사용
FieldListFilter를 정의할 때 __in 룩업을 사용할 수 있습니다. 다음과 같이 expected_parameters 메서드를 오버라이드하면 됩니다.
자세한 내용은 ModelAdmin List Filters 문서의 해당 부분을 참고하세요.
PBKDF2 해시 반복 횟수
PBKDF2 해시의 반복 횟수가 320,000회에서 390,000회로 증가했습니다.
사용자 속성이 원격 백엔드와 싱크
RemoteUserBackend.configure_user() 메서드를 사용하면 LDAP 같은 원격 백엔드의 사용자 속성과 동기화할 수 있습니다.
사이트맵에 <lastmod> 추가
사이트맵 생성시 기본으로 <lastmod> 타임스탬프 값을 추가합니다. get_latest_lastmod()를 사용합니다.
폼
- form_template_name을 설정하면 프로젝트 전체에 폼 템플릿을 적용할 수 있습니다. Form.template_name 을 설정하면 폼마다 별도의 폼 템플릿을 적용할 수 있습니다. (폼셋도 비슷합니다.)
- legend_tag()를 사용하여 라디오 버튼과 체크박스의 <legend>를 제대로 표현할 수 있습니다.
관리 명령어
- 마이그레이션 실행시 --prune 옵션을 추가하면, 더이상 존재하지 않는 마이그레이션들을 django_migrations 테이블에서 삭제합니다.
- 만약 black이 설치돼 있다면 startproject, startapp, optimizemigration, makemigrations, squashmigrations 실행시 black으로 포매팅한 파일을 만듭니다.
- optimizemigration 명령어를 사용하여 해당 마이그레이션 파일을 최적화할 수 있습니다. (마이그레이션용 함수는 수동으로 처리해야 합니다.)
마이그레이션
- 새로 추가된 RenameIndex를 사용하여 인덱스 이름을 바꿀 수 있습니다.
- Meta.indexes를 수정하면 RenameIndex를 생성합니다. (이전에는 RemoveIndex와 AddIndex를 함께 생성했습니다.)
- Meta.index_together를 수정하면 RenamIndex를 생성합니다. (이전에는 AlterIndexTogether와 AddIndex를 함께 생성했습니다.)
모델
- CONN_HEALTH_CHECKS를 사용하여 데이터베이스 연결 가능 여부를 미리 확인할 수 있습니다.
- QuerySet.bulk_create() 실행시 고유값 검증에 실패하면 값을 추가하는 대신 업데이트할 수 있습니다.
- QuerySet.iterator()는 연관 객체를 prefetching할 수 있습니다. (chunk_size가 지정된 경우에만 작동합니다.)
- PostgreSQL을 사용하는 경우 AutoField, BigAutoField, SmallAutoField는 시퀀스 컬럼 대신 identity 컬럼을 생성합니다.
요청과 응답
- HttpResponse.set_cookie()의 max_age 전달인자로 timedelta 객체를 전달받을 수 있습니다.
보안
- SECRET_KEY_FALLBACKS를 설정하여 목록 내의 비밀키를 번갈아가며 사용할 수 있습니다.
테스트
- DiscoverRunner가 macOS, Windows 등의 시스템에서 병렬 테스트를 지원합니다.
하위 호환되지 않는 기능
django.contrib.gis
- GDAL 2.1 지원을 중단합니다.
- PostGIS 2.4 지원을 중단합니다.
데이터베이스
- PostgreSQL 10 지원을 중단합니다.
- MariaDB 10.2 지원을 중단합니다.
중단 예정인 기능
GET 기반의 로그아웃
내장 로그아웃 뷰가 GET 방식에서 POST 방식으로 바뀌었습니다.
기타
- django.contrib.sessions.serializers.PickleSerializer은 원격 코드 실행 위협이 있으므로 지원을 중단할 예정입니다.
- chunk_size를 지정하지 않고 QuerySet.iterator()를 호출하는 방식은 지원을 중단할 예정입니다.
- 연관 모델 필터링시 저장하지 않은 모델 인스턴스를 지정하는 방식은 지원을 중단할 예정입니다. Django 5.0에서는 예외를 일으킵니다.
- datetime.timezone.utc를 가리키던 django.utils.timezone.utc는 지원 중단 예정입니다. datetime.timezone.utc만 사용하세요.
- django.contrib.auth.hashers.CryptPasswordHasher는 지원 중단 예정입니다.
- 표 기반의 템플릿인 "django/forms/default.html" 파일과 "django/forms/formsets/default.html" 파일은 지원 중단 예정입니다.
삭제된 기능
- TestCase.setUpTestData()에서 깊은 복사(copy.deepcopy())를 지원하지 않는 객체를 사용할 수 없습니다.
- django.core.validators.EmailValidator에서 whitelist와 domain_whitelist가 삭제됐습니다.
- default_app_config가 삭제됐습니다.
- django.core.cache.backends.memcached.MemcachedCache가 삭제됐습니다.
마치며
요약은 여기까지입니다. 개인적으론 중요하지 않아 보여서 적지 않은 내용이 여러분에겐 더 중요할 수도 있으니, Django 4.1 공식 릴리스 노트를 한 번 살펴보시길 추천합니다.