안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

회사 프로젝트 작업 일지

[오픈갤러리] Django 서버 정리 작업 ⑤ - 자주 사용되는 코드 정리 (datetime, timezone 등)

피그브라더 2021. 5. 28. 13:30

목차
⦁ datetime, timezone 코드 정리
⦁ 문자열 formatting 방식 통일
⦁ return render() 정리

 

▎datetime, timezone 코드 정리

Python에서 날짜 및 시각을 표현하고 싶을 때는 보통 datetime 모듈을 사용한다. datetime 모듈에서는 date, time, datetime 등의 클래스가 제공되며 각각 날짜, 시각, 날짜 및 시각을 표현하는 데 사용된다. 또한 Django에서도 날짜 및 시각과 관련이 있는 timezone이라는 모듈을 제공한다. 오픈갤러리 프로젝트에서도 이러한 두 종류의 모듈(datetime, timezone)을 이용하여 날짜 및 시각과 관련된 코드들을 작성하고 있었다.

 

단, Django의 설정 중 USE_TZ 변수의 값이 True로 설정되어 있는 경우에는 datetime 모듈을 사용할 때 주의해야 한다. Naive 객체가 아닌 Aware 객체를 사용해야 하기 때문이다. 물론 Naive 객체를 사용해도 Django가 알아서 Aware 객체로 변환시켜주는 경우가 있기 때문에 큰 문제는 발생하지 않을 수 있지만, 매번 워닝을 보는 것도 피로하고 DST 등의 까다로운 문제를 맞닥뜨리지 않으려면 마음 편하게 Aware 객체만 사용하는 것이 좋다. (참고)

 

또한 Aware 객체를 사용하는 경우에도 한국 시간이 필요한 경우라면 timezone 모듈을 이용하여 적절히 시간대를 변경해주는 것이 필요하다. 예를 들어 timezone.now()는 현재의 날짜 및 시각을 반환하지만 시간대가 UTC이다. 따라서 한국 시간대로 변경하려면 timezone.localtime() 함수를 사용해야 한다.

 

그래서 이번 작업을 통해 오픈갤러리 프로젝트에서 작성되어 있는 날짜 및 시각 관련 코드들 중 올바르지 않게 작성된 것들을 모두 찾아 수정해주기로 하였다. Naive 객체를 사용하는 경우라면 Aware 객체를 사용하도록 고치고, Aware 객체를 사용하는 경우 중에서도 한국 시간이 필요한 경우라면 적절히 시간대를 변경해주도록 고치는 등의 작업을 진행했다.

 

코드 수정의 예시를 보면 대략 다음과 같다. 기본적으로는 Naive 객체 대신 Aware 객체를 사용하도록 통일한 것을 볼 수 있다. 단, Aware 객체의 시간대를 바꾸는 코드의 경우에는 그 코드의 맥락을 먼저 파악해야 했다. 맥락에 따라 한국 시간으로 바꿔야 할 수도, 아닐 수도 있기 때문이다.

# Naive -> Aware (UTC)
model_instance.datetime_field = datetime.now()  # AS-IS
model_instance.datetime_field = timezone.now()  # TO-BE

# Naive -> Aware (UTC)
model_instance.datetime_field = datetime.strptime(request.POST['datetime_field'], '%Y-%m-%d %H:%M')  # AS-IS
model_instance.datetime_field = timezone.make_aware(
    datetime.strptime(request.POST['datetime_field'], '%Y-%m-%d %H:%M')
)  # TO-BE

# Naive -> Aware (UTC)
SomeModel.objects.filter(datetime_field__gte=datetime.now())  # AS-IS
SomeModel.objects.filter(datetime_field__gte=timezone.now())  # TO-BE

# Naive -> Aware (UTC) -> Aware (Asia/Seoul)
now = datetime.now()  # AS-IS
now = timezone.localtime(timezone.now())  # TO-BE

# Naive -> Aware (UTC) -> Aware (Asia/Seoul)
today = datetime.now().date()  # AS-IS
today = timezone.localtime(timezone.now()).date()  # TO-BE

# Naive -> Aware (UTC) -> Aware (Asia/Seoul)
year = datetime.now().year  # AS-IS
year = timezone.localtime(timezone.now()).year  # TO-BE

 


▎문자열 formatting 방식 통일

Python 문자열에 formatting 하는 방법은 크게 두 가지가 있다. 하나는 %s를 사용하는 방식이고, 다른 하나는 format() 메소드를 사용하는 방식이다. 오픈갤러리 프로젝트의 경우 두 방식을 혼용하여 사용하고 있었는데, 코드의 일관성 확보를 위해 format() 메소드를 사용하는 방식으로 통일하기로 하였다. format() 메소드를 사용하는 것이 훨씬 더 가독성 측면에서 좋다고 판단하였기 때문이다.

'My name is %s. And my height is %s.' % (name, height)  # AS-IS
'My name is {}. And my height is {}.'.format(name, height)  # TO-BE

 

또한 format() 메소드를 사용할 때도 {0} 혹은 {1}과 같이 중괄호 안에 인덱스를 적는 방식을 최대한 피하는 것으로 합의하였다. 즉, 같은 인덱스가 여러 번 쓰이는 경우(동일한 값을 여러 위치에 삽입할 때)를 제외하고는 중괄호 안에 인덱스를 적지 않는 방향으로 통일하였다.

'My name is {0}. And my height is {1}.'.format(name, height)  # AS-IS
'My name is {}. And my height is {}.'.format(name, height)  # TO-BE

# DON'T CHANGE
'[{0}] My name is {0}. And my height is {1}.'.format(name, height)

 


▎return render() 정리

Django 뷰가 렌더링을 할 때 사용하는 템플릿(HTML 파일)의 이름을 굳이 변수로 두지 않고 상수로 전달하도록 통일하였으며, 템플릿에게 전달하는 Context 또한 비어 있는 경우에는 빈 딕셔너리를 상수로 전달하도록 통일하였다.

# AS-IS
def sample_view(request):
    template_name = 'pages/sample.html'
    context = {}
    return render(request, template_name, context)

# TO-BE
def sample_view(request):
    return render(request, 'pages/sample.html', {})