이 글에서는 Django 3.1에 추가된 기능과 바뀐 점을 알아보려 합니다. Django 3.1 release notes를 참고하였습니다.

Django는 3년 마다 LTS를 위해 메이저 버전을 하나씩 올리고, 8개월마다 마이너 버전을 올립니다. 이번에 출시한 3.1은 마이너 업데이트입니다.

Django 릴리스, 공식 사이트: https://www.djangoproject.com/download/

파이썬 호환성

Django 3.1은 파이썬 3.6, 3.7, 3.8을 지원합니다. (파이썬 3.5를 지원하는 버전은 Django 2.2.x입니다.)

새 기능

비동기 뷰와 미들웨어

지난 3.0에서 비동기로 작동하는 애플리케이션을 지원하는 기능이 추가되었는데요. 여기에 이어서 비동기 뷰와 미들웨어도 지원합니다. 함수형 뷰라면 다음과 같이 async 키워드만 붙여주면 됩니다.

import time
import asyncio

from django.utils import timezone 

async def what_time(request):
    before = time.perf_counter()
    asyncio.sleep(10)
    elapsed = time.perf_counter() - before
    result = {
        "message": f"Executed in {elapsed} seconds.",
    }
    return JsonResponse(result)

클래스형 뷰에서는 __call__() 메서드를 정의하라고 하는데, 아직 사용예를 찾지 못해서 추후 코드를 작성해보겠습니다.

모든 데이터베이스에서 JSONField 사용 가능

이전에는 PostgreSQL에서만 사용할 수 있던 JSONField를 모든 데이터베이스에서 사용할 수 있습니다. 따라서 django.contrib.postgres.fields.JSONField는 향후 사라질 계획입니다.

DEFAULT_HASHING_ALGORITHM

쿠키나 토큰, 사용자 세션 등을 인코딩할 때 사용하던 기본 해시 알고리즘을 지정할 수 있습니다. sha1sha256을 선택할 수 있으며, 기본 값은 sha256입니다. 만약 Django 3.1로 이전하고 있는 프로젝트라면, 3.1로 모두 이전하기 전까지는 sha1로 지정해야 합니다. 이 설정은 Django 4.0에서 SHA-1 알고리즘 지원과 함께 사라질 예정입니다.

그 외 자잘한 변경들

  • 관리자 화면(django.contrib.admin)
    • list_filterEmptyFieldListFilter를 사용하면, 빈 값이나 null로 필터링할 수 있습니다.
    • 여러 모델을 왔다갔다 할 수 있는 내비게이션이 넓은 해상도에서 나타납니다. (없애고 싶다면 AdminSite.enable_nav_sidebar 값을 False로 지정하면 됩니다.
  • 인증(django.contrib.auth)
    • PASSWORD_RESET_TIMEOUT 설정을 변경하면, 비밀번호 초기화 링크의 유효 시간을 지정할 수 있습니다. PASSWORD_RESET_TIMEOUT_DAYS 설정을 사용하고 있었다면 바꾸길 권합니다. PASSWORD_RESET_TIMEOUT_DAYS 설정은 Django 4.0에서 사라질 예정입니다.
  • django.contrib.contenttypes
    • remove_stale_contenttypes 명령어에 --include-stale-apps 옵션을 사용하면 INSTALLED_APPS에 있었다가 사라진 콘텐트 타입을 지울 수 있습니다.
  • django.contrib.gis
    • relate 룩업을 MariaDB에서도 지원합니다.
    • PostGIS 3와 GDAL 3을 지원합니다.
  • django.contrib.humanize
    • intword 템플릿 필터에서 음수도 지원합니다. 예를 들어 -12000000-1.2 million이라고 표시됩니다.
  • django.contrib.postgres
    • get_FOO_display()ArrayFieldRangeField 를 지원합니다.
    • rangefield.lower_incrangefield.lower_inf, rangefield.upper_inc , rangefield.upper_inf 를 사용하면 RangeField에 대해 경계 값 포함 여부로 룩업 쿼리를 작성할 수 있습니다. (inc는 [], inf는 ()를 의미합니다.)
    • RangeFieldcontained_by 룩업을 SmallAutoField, AutoField, BigAutoField, SmallIntegerField, DecimalField에서도 사용할 수 있습니다.
    • PostgreSQL 11 버전 이상에 추가된 websearch 검색 타입을 SearchQuery에 사용할 수 있습니다.
    • SearchHeadline 을 사용하면 검색 결과에서 일치하는 부분을 하이라이트할 수 있습니다. (원하는 태그나 기호를 일치하는 부분 앞뒤에 추가하는 방식입니다.)
    • search 룩업을 쿼리 표현식에 사용할 수 있습니다.
  • django.contrib.sessions
    • SESSION_COOKIE_SAMESITE 설정에 None을 지정하면, same-site 요청이든 cross-site 요청이든 세션 쿠키를 보냅니다.
  • django.contrib.staticfiles
    • STATICFILES_DIRS 설정에 pathlib.Path 객체를 사용할 수 있습니다.
  • CSRF
    • CSRF_COOKIE_SAMESITE 설정에 None을 지정하면, same-site 요청이든 cross-site 요청이든 CSRF 쿠키를 보냅니다.
  • 파일 저장소
    • FileFieldImageFieldstorage에 호출 가능한 값을 지정할 수 있습니다. (즉, 런타임에 사용할 저장소를 선택할 수 있습니다.)
  • 관리 명령어
    • check 명령어의 --database 옵션에 특정 데이터베이스의 이름을 지정할 수 있습니다.
    • migrate 명령어에 --check 옵션을 사용하면 적용되지 않은 마이그레이션이 있을 경우 0이 아닌 종료 값을 출력합니다.
    • CommandErrorreturncode를 지정할 수 있습니다.
    • dbshell 명령어를 사용할 때 -- 기호 뒤에 커맨드 라인 옵션을 추가할 수 있습니다. (예를 들어 ./manage.py dbshell -- -c 'select current_user')
  • 모델
    • ExtractIsoWeekDay 함수를 사용하면 ISO-8601 표준에 따른 주(week) 번호를 추출할 수 있습니다. 또한 iso_week_day 룩업으로 같은 값을 쿼리할 수 있습니다.
    • on_delete에 사용할 수 있는 RESTRICT 옵션이 추가되었습니다.
    • CheckConstraintcheck 값으로 불린 표현식을 지정할 수 있습니다.
    • datetimes() 쿼리셋 메서드에 is_dst를 사용하면, (일광 절약 시간에 적용받는 지역에서) 존재하지 않거나 모호한 시간에 대해 pytz가 예외를 일으키거나 일으키지 않게 할 수 있습니다.
    • F 표현식에서 bitxor() 메서드를 사용하면 비트 단위의 XOR 연산을 수행할 수 있습니다.
  • 요청과 응답
    • ALLOWED_HOSTS 가 빈 값이고 DEBUG=True로 지정되어 있다면, localhost의 서브 도메인도 허용됩니다. (예를 들어 my.localhost 등)
    • 새로 추가된 HttpRequest.accepts() 메서드를 사용하면 특정한 MIME 타입인지 여부를 확인할 수 있습니다.
  • 보안
    • SECURE_REFERRER_POLICY 설정의 기본 값은 same-origin으로 바뀌었습니다. 이전처럼 작동하게 하려면 None으로 설정하세요.
  • 템플릿
    • transblocktranstranslateblocktranslate로 이름이 바뀌었습니다.
    • include 태그가 템플릿 목록을 지원합니다.
  • 테스트
    • 테스트 데이터베이스 설정에 새로 추가된 MIGRATE 옵션을 False로 지정하면, 테스트용 데이터베이스를 생성할 때 마이그레이션을 실행하지 않습니다.
    • test 명령어에 --buffer 옵션을 추가하면, 성공한 테스트에 대해서는 출력을 하지 않습니다. ## 하위 호환이 중단된 기능
  • 데이터베이스
    • 데이터베이스 연결시 timezone의 기본 값이 UTC로 설정됩니다. USE_TZ=True라면 TIME_ZONE 값으로 설정됩니다. (이전에는 None이었습니다.)
  • MariaDB 10.1에 대한 지원을 중단합니다.
  • 관리자 화면에서 인터넷 익스플로러를 지원하지 않습니다.
  • AbstractUserfirst_name 필드의 max_length 값이 150으로 늘어납니다.
  • 기타
    • cachemake_template_fragment_key()로 생성된 캐시 키가 이전 버전과 달라집니다. 따라서 Django 3.1로 업그레이드한 이후의 첫 요청에 대해서는, 이전에 캐시된 템플릿 조각이라도 캐시 미스가 발생합니다.
    • django.utils.decorators.classproperty()를 퍼블릭 프로퍼티로 바꾸고, django.utils.functional.classproperty() 로 옮겼습니다.
    • 반올림하여 0이 되는 음수는 floatformat 템플릿 태그를 사용해도 0을 출력합니다.
    • Meta.orderingMeta.unique_together를 튜플에서 리스트로 바꾸었습니다.
    • dumpdata에서 사용하는 JSON/YAML 시리얼라이저가 기본으로 유니코드를 사용합니다. 이전처럼 작동하게 하려면 ensure_ascii=True(JSON)나 allow_unicode=False(YAML)을 사용하세요.
    • 자동 리로딩 서버는 Django 번역 파일의 수정 사항을 추적하지 않습니다.

중단 예정인 기능(화살표 뒤의 기능을 사용하길 권합니다)

  • django.contrib.postgres.fields.JSONField -> models.JSONField
  • django.contrib.postgres.forms.JSONField -> forms.JSONField
  • PASSWORD_RESET_TIMEOUT_DAYS -> PASSWORD_RESET_TIMEOUT
  • django-admin.py -> django-admin
  • HttpRequest.is_ajax()는 jQuery의 AJAX 호출에 의존적이고 최근에는 자바스크립트의 Fetch API를 선호하는 경향이 있습니다. 상황에 따라 직접 AJAX인지 검사하는 함수를 구현하거나 HttpRequest.accepts() 메서드를 사용하세요.
  • CookieStorage 와 세션의 인코딩 포맷이 바뀝니다. 이전 형태의 인코딩 포맷은 Django 4.0 이전까지만 지원합니다.
  • url 설정시 TemplateView에 직접 kwargs를 적는 방식도 중단될 예정입니다.
  • NullBooleanField -> BooleanField(null=True)
  • django.urls.re_path()의 다른 이름인 django.conf.urls.url()은 사라질 예정입니다.
  • {% ifequal %} 템플릿 태그 -> {% if %}

삭제된 기능

  • django.utils.timezone.FixedOffset
  • django.core.paginator.QuerySetPaginator
  • 모델의 Meta.ordering은 더이상 group by 쿼리에 영향을 주지 않습니다.
  • django.contrib.postgres.fields.FloatRangeFielddjango.contrib.postgres.forms.FloatRangeField
  • FILE_CHARSET 설정
  • django.contrib.staticfiles.storage.CachedStaticFilesStorage

요약은 여기까지입니다. 개인적으론 중요하지 않아 보여서 적지 않은 내용이 여러분에겐 더 중요할 수도 있으니, Django 3.1 공식 릴리스 노트를 꼼꼼히 살펴보시는 건 어떨까요?