Django 4.1 릴리스와 주요 변경 사항
이 글에서는 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을 지원합니다. 각 버전의 마지막 릴리스를 사용하기를 권장합니다.
새 기능
클래스 기반 뷰에 적용할 수 있는 비동기 핸들러
Django 3.1부터 비동기 뷰가 도입됐지만 함수 기반 뷰에서만 사용할 수 있었는데요. 4.1부터는 클래스 기반 뷰에도 사용할 수 있습니다.
class BlogView(View)
async def get(self, request, *args, **kwargs):
await asyncio.sleep(5)
return HttpResponse('This is an async response')
클래스 기반 뷰에 적용하는 비동기 핸들러에 대한 자세한 내용은 Asynchronous class-based views 문서를 참고하세요.
비동기식 ORM 인터페이스
비동기 처리용 ORM 인터페이스를 지원합니다. 기존 ORM 메서드 앞에 a
를 붙은 형태의 메서드를 사용하면 됩니다. 이를테면, create
대신 acreate
, first
대신 afirst
처럼요.
새 쿼리셋을 반환하는 메서드들은 별도의 인터페이스를 만들지 않았습니다. filter
나 exclude
, annotate
등은 비동기 코드에서 그대로 사용해도 됩니다.
async for post in Posts.objects.filter(datetime__year=2022):
= await post.tags.afirst() tag
하지만, 데이터베이스 연산은 아직 동기 방식으로 처리됩니다. 새 인터페이스는 기존 연산에 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
설정 값을 다음처럼 정의하세요.
= "django.forms.renderers.DjangoDivFormRenderer" 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
메서드를 오버라이드하면 됩니다.
class FilterWithCustomSeparator(admin.FieldListFilter):
# custom list separator that should be used to separate values.
= '|'
list_separator
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = '%s__in' % field_path
super().__init__(field, request, params, model, model_admin, field_path)
def expected_parameters(self):
return [self.lookup_kwarg]
자세한 내용은 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 공식 릴리스 노트를 한 번 살펴보시길 추천합니다.