Django - 쿼리 표현식, DB 트랜잭션

|

Two Scoops of Django 7장을 읽고 정리한 내용입니다.
더 좋은 방법이 있거나, 잘못된 부분이 있으면 편하게 의견 주세요. :)

7장 쿼리와 데이터베이스 레이어

7.4 고급 쿼리 도구 이용하기

  • 장고의 ORM은 강력하지만 모든 경우를 완벽하게 처리할 수 있지는 않다.
  • 따라서 장고의 고급 쿼리 도구를 이용하여 데이터베이스를 통한 데이터 가공을 시도할 수 있다.
  • 고급 쿼리도구를 사용하면 파이썬을 통한 데이터 가공보다 성능이 좋고 안전하다.

7.4.1 쿼리 표현식

  • 쿼리 표현식을 꼭 익혀두자. 프로젝트의 안전성과 성능을 대폭 향상시켜 줄 것이다.
  • Query Expressions (공식문서)
  • 나쁜예제
    • 모든 고객 레코드에 대해서 for loop가 돌고있다. => 매우 느리고, 메모리 소모가 크다
    • 경합상황 (race condition)에 직면할 가능성이 크다. => 데이터 분실 우려

      경합상황 : 다중 프로그래밍 시스템이나 다중 처리기 시스템에서 두 명령어가 동시에 같은 기억 장소를 액세스할 때 그들 사이의 경쟁에 의해 수행 결과를 예측할 수 없게 되는 것.

# 절대 따라하지 말 것
from models.customers import Customer

customers = []
for customer in Customer.objects.iterator():
  if customer.scoops_ordered> customer.store_visits:
    customers.append(customer)
  • 수정 후
    • 쿼리표현식을 통해서 코드들이 서로 경합을 펼치는 상황을 피할 수 있다.
from django.db.models import F
from models.customers import Customer

customers = Customer.objects.filter(scoops_ordered__gt=F('store_visits'))
  • 위 코드 쿼리표현식 중 F() expressions의 기능
    • 파이썬이 아닌 데이터베이스 자체 내애서 해당 조건을 비교하는 기능을 가진다.
    • 경합조건을 피할 수 있다.Avoiding race conditions using F
    • 위 코드에서 내부적으로 다음과 같은 SQL문을 생성한다.
SELECT * from customers_customer where scoops_ordered > store_visits

스크린샷 2017-07-25 오후 4.49.31 출처 - school of web

7.4.2 데이터베이스 함수들

  • 장고 1.8 부터 일반적인 데이터베이스 함수를 이용할 수 있다.
  • UPPER(), LOWER(), COALESCE(), CONCAT(), LENGTH(), SUBSTR()
  • 저자가 가장 좋아하는 기능이다. 왜냐하면
    • 쉽고 간결하다.
    • 성능이 굉장히 향상된다. (파이썬으로 데이터 처리속도 < 데이터베이스 내에서 데이터 처리속도)
    • 데이터베이스 함수는 장고 ORM의 쿼리 표현식이기도 하다.
  • Database Functions (공식문서)

7.5 필수 불가결한 상황이 아니라면 로우 SQL은 지양하자

  • ORM은 생산성이 높다.
  • ORM은 단순 쿼리를 만들어 내는 것에 더해서 모델에 대한 접근, 업데이트를 할 때 유효성 검사와 보안을 제공한다.
  • 로우 SQL을 사용하면 앱의 이식성이 떨어질 수 있고, 다른 종류의 DB로 마이그레이션이 어려울 수 있다.
  • 그럼 언제 로우 SQL을 사용하나요? => SQL을 직접 이용함으로써 코드가 월등히 간결해지고, 단축되는 경우에만 사용하자.

7.6 필요에 따라 인덱스를 이용하자

  • 모델의 필드 옵션으로 db_index를 추가하면 해당 필드에 대해서 Database index가 생성된다.
  • 처음에는 인덱스 없이 시작하고 필요에 따라서 하나하나 추가하는 것을 추천한다.
    • 인덱스가 빈번하게 이용될 때 (쿼리의 10~25% 사이) => 생성된 SQL 문에서 WHERE 절과 ORDER_BY 절을 세심하게 살펴보기
    • 인덱싱을 통해서 성능이 향상되는지 테스트 가능할 때
  • PostgreSQL의 경우 pg_stat_activity 를 통해서 어떤 인덱스가 사용 중인지 확인 가능하다.

7.7 트랜잭션 (Transactions)


스크린샷 2017-07-25 오후 7.40.46

  • Transaction : (명사) 처리, 처리과정

    컴퓨터 과학분야에 트랜잭션은 “쪼개질 수 없는 업무처리의 단위”를 의미

  • 데이터베이스 충돌을 해결하기 위해서 둘 또는 그 이상의 데이터베이스 업데이트를 단일화된 작업 으로 처리하는 기법
  • 하나의 수정작업(update)가 실패하면 트랜젝션 상의 모든 업데이트가 실패 이전 상태로 복구된다.


acid

  • 트랜젝션의 특성 (ACID)
    • 원자성 (Atomic)
    • 일관성 (Consistent)
    • 독립성 (Isolated)
    • 지속성 (Durable)
  • 장고는 1.8 부터 사용하기 쉬운 트랜잭션 메커니즘을 제공

데코레이터(decorator)를 이용한 트랜잭션 예시 (출처)

from django.db import transaction

@transaction.atomic
def transaction_test1(arg1, arg2):
    # start transaction
    a.save()

    b.save()
    # end transaction

with 명령어를 이용한 트랜잭션 예시 (출처)

from django.db import transaction
def transaction_test2(arg1, arg2):

    a.save()    # 항상 save 처리됨, 예외가 발생할 경우 에러 발생

    with transaction.atomic():
        # start transaction
        b.save()
        c.save()
        # end transaction

7.7.1 각각의 HTTP 요청을 트랜잭션으로 처리하라

  • 아래와 같은 설정을 통해서 읽기 데이터를 포함한 모든 요청이 트랜잭션으로 처리되게 할 수 있다.
    • 장점 : 뷰에서의 모든 데이터베이스 쿼리가 보호되는 안정성을 얻을 수 있다.
    • 단점 : 성능 저하를 가져올 수 있다.
  • 쓰기 작업이 많은 프로젝트의 초기 구성에서 데이터베이스 무결성을 유지하는데 효과적인 구성
  • 특정 루틴을 설정에서 제외시키고 싶다면 뷰 함수에서 transaction.non_atomic_requests()로 데코레이팅한다.
  • 의료정보나 금융 정보를 다루는 프로젝트의 경우 트랜잭션 무결성 보다는 이벤트 일관성에 초점을 맞추어 구성하게 된다.
# settings/base.py

DATABASE = {
  'default': {
    #...생략
    'ATOMIC_REQUESTS': True,
  }
}

7.7.2 명시적인 트랜잭션 선언

  • 사이트 성능을 개선하는 방법 중 하나
  • 트랜젝션에서 어떤 뷰와 비지니스 로직이 하나로 엮여 있는지 명시해 주는 것 (개발 시간이 오래 걸림)
  • 대부분의 사이트는 ATOMIC_REQUESTS 설정으로 충분하다.
  • 트랜잭션이 필요한 장고 ORM 구분
  • 독립적인 ORM 메서드 호출은 이미 내부적으로 트랜잭션을 이용하고 있다. 대신 여러 ORM 메서드 들을 뷰나 함수 내에서 호출할 때 트랜잭션을 이용하는게 좋다.
목적 ORM 메서드 트랜잭션을 이용?
데이터 생성 .create(), .bulk_create(), .get_or_create() O
데이터 가져오기 .get(), .filter(), .count(), .iterate(), .exist(), .exclude() 등 X
데이터 수정하기 .update() O
데이터 지우기 .delete() O

7.7.3 django.http.StreamingHttpResponse와 트랜잭션

  • 뷰가 django.http.StreamingHttpResponse를 반환한다면 중간에 트랜잭션 에러를 처리하기는 불가능하다.
  • 이를 해결하려면 아래와 같은 방법이 있다.
    • ‘ATOMIC_REQUESTS’설정을 False 로 설정하고 명시적 트랜잭션 선언을 검토
    • 해당 뷰를 django.db.transaction.non_atomic_requests 데코레이터로 감싸기

7.7.4 MySQL 에서의 트랜잭션

  • MySQL 데이터베이스 타입에 따라서 트랜잭션 지원 여부가 달라진다. (InnoDB - 지원함, MyISAM - 지원안함)
  • 트랜잭션을 지원하지 않는다면, ATOMIC_REQUESTS 설정에 상관없이 항상 오토커밋 모드로 작동한다.

170731-0806_TIL (해커톤, CBV)

|

8월 5-6일 (토-일)

  • 처음으로 무박 2일 해커톤에 참여했다. 4명의 팀원이 21시간 동안 함께 작업했는데, 배운 점도 많았고 느낀 점도 있었다.
  • 팀원 중 한 명이 개인적으로 준비하던 프로젝트에 기능을 추가하는 식으로 진행했다.
  • 개발환경을 맞추고 runserver 하는 데 시간이 한참 걸렸다.
  • 새로운 코드 구조가 익숙하지 않아서 model, view, form 파일이 어디 있는지 몇 번이나 찾아봤다.
  • 다른 사람의 코드를 이해하고 원하는 코드를 추가하기가 것이 쉽지 않다는 것을 알았다.
  • github을 사용해서 여러 명이 함께 협업한 것은 처음이었다. 브랜치에서 작업을 하고 PR을 보내고 머지, 풀 작업을 하면서 각자 따로 작업했던 부분들이 하나로 합쳐지는 신기한 경험을 했다.
  • 그동안 git은 CLI 환경에서 작업했었는데 sourcetree에도 익숙해져야겠다는 생각이 들었다. 특히 conflict가 발생했을 때 좀 더 편하게 확인할 수 있는 것 같다. 생활코딩 sourcetree 강의를 들어봐야지. 그리고 CLI 환경에서도 동일한 작업을 할 수 있도록 같이 연습하고 싶다.
  • pycharm의 디버깅 모드를 처음 사용해봤다. 지금까지는 오류가 발생하면 오류메시지를 참고해서 python shell을 통해서 확인해보거나, template에 값을 출력해보는 식으로 원인을 찾았었다. 이제는 브레이킹 포인트를 걸고 코드를 한 줄씩 실행하면서 값이 어떻게 전달되는지 확인할 수 있게 됐다.
  • pycharm django 개발 환경을 설정을 연습했다. atom보다 설정해야 하는 내용이 많지만 한번 해놓고 나면, 환경변수를 설정하거나 디버깅을 할 때 편리한 것 같다. 까먹기 전에 설정했던 환경들 정리
    • Project Interpreter : 가상환경 추가
    • Languages & Frameworks > django : Django project root, settings, manage script, 환경변수
    • Languages & Frameworks > Python template Languages
    • Run/Debug Configurations : Django Server 추가
  • 유저간 쪽지 교환기능 구현을 위해서 3rd party app을 사용했다. 최신 버전을 설치하려고 github 링크를 사용해서 설치를 하고, 수정을 원하는 부분은 상속 후 코드를 오버라이딩 하는 방식으로 사용했다.
     # pip 설치 (github 주소를 통한 최신버전 설치)
     pip install git+https://github.com/arneb/django-messages.git#egg=django-messages
     # requirements.txt 설정
     -e git+https://github.com/arneb/django-messages.git@b6bd11a767c9a5bf31fec6e1980a28b3734ea432#egg=django_messages
    

8월 3일 (목)


8월 2일 (수)

  • Two Scoops of Django 8장 함수 기반 뷰, 클래스기반뷰 9장 함수 기반 뷰의 모범적인 이용을 읽었다.
  • 두숟갈 스터디에 참여했다.
  • 파이썬 데코레이터에 대해서 강의를 듣고 공부했다.
  • 3개월 전에 못풀었던 데코레이터 퀴즈를 드디어 풀었다!

내일 할 일

  • 스터디 프로젝트 ListView, DetailView 작성하고 PR 보내기
  • django-messagesapp 활용해보기
  • 해커톤 모델링 피드백하기
  • 개인프로젝트 리팩토링 (WishBook 모델 수정, api 코드 수정)
  • test 관련 공부하기

8월 1일 (화)

  • CBV를 활용하여 개인 프로젝트 리팩토링
    • ListView 를 활용하여 책 전체 리스트 뷰를 수정했다.
    • MonthArchiveView를 활용하여 월별 희망도서 신청이력 뷰를 추가했다.

내일 할 일

  • 두숟갈 스터디 참여하기
  • TSD 8, 9장 읽고 공부하기

7월 31일 (월)

  • Django Model Syntax 글을 읽었다.
  • 해커톤을 앞두고 팀원들과 무엇을 구현할지 이야기했다.
    • 개요 : 중고서적 거래 매칭 서비스
    • 주요기능
    • 살래요, 팔래요 게시판 (도서 api 사용)
    • 매칭 거래 발생시 알람기능 (이메일 + 알람 메시지, 텔레그램)
    • 유저간 메시지 교환 기능 (찾아보니 이런게 있는데 어떤건지 먼저 사용해봐야겠다.)
  • CBV 강의를 들었다.

내일 할 일

  • CBV 공부하기 (TSD, 강의)
  • CBV를 활용하여 개인 프로젝트 리팩토링
  • django-messagesapp 활용해보기

Django - ORM, 쿼리셋, 예외처리

|

Two Scoops of Django 7장을 읽고 정리한 내용입니다.
더 좋은 방법이 있거나, 잘못된 부분이 있으면 편하게 의견 주세요. :)

7장 쿼리와 데이터베이스 레이어

  • 장고에서는 여러 종류의 데이터를 데이터베이스 종류와는 독립적인 형태로 객체화 한다. (ORM)
  • 그리고 생성된 객체에는 상호 작용할 수 있는 메서드 세트를 제공한다. (Model Manager)
  • ORM은 훌륭하지만 때때로 예상과 다른 현상이 발생하기도 한다.
  • Django 이용방법을 배운다는 것은 이런 예상과는 다른 현상을 이해해 나가는 과정이라고 할 수 있다.
  • Chapter7 에서는 ORM이 예상과 다르게 동작하는 다양한 경우들을 살펴본다.

ORM, QuerySet

ORM이 뭔가요? (Object Relational Mapping)

  • OOP 언어와 데이터를 다루는 RDBMS 와의 상이한 시스템을 매핑하여, 데이터 관련 OOP 프로그래밍을 쉽게 하도록 도와주는 기술
  • Model Class를 통해서 객체를 만들고 이 객체를 통해서 DB에 접근한다.
  • SQL을 몰라도 데이터를 알고싶다! Django-Models 출처 The Django Book

쿼리셋 (QuerySet)이 뭔가요?

>>> from .models import Book
>>> Book.objects.all() # Book 모델(테이블)의 모든 데이터를 가져오기
<QuerySet [<Book:  제목1>, <Book:  제목2>]>
  • objects : Model Manager, DB와 Django Model 사이의 Query Operation(질의연산) 인터페이스 역할
  • objects를 사용하여 다수의 데이터를 가져오는 함수를 사용할 때 반환되는 객체가 QuerySet

참고자료


7.1 단일 객체에서 get_object_or_404() 이용하기

  • 상세 페이지 view에서는 get() 대신에 get_object_or_404()를 이용하자
  • 왜요? try-except 블록으로 예외처리를 할 필요가 없습니다
  • 단, get_object_or_404()는 뷰에서만 사용하자!
>>> Book.objects.get(title="없는 책")
DoesNotExist: Book matching query does not exist.

>>> from django.shortcuts import get_object_or_404
>>> get_object_or_404(Book, title="없는 책")
Http404: No Book matches the given query.

7.2 예외를 일으킬 수 있는 쿼리를 주의하자

  • get_object_or_404()를 사용하면 예외처리가 필요없다.
  • 하지만, 그외의 경우에는 try-except를 이용한 예외처리가 필요하다. 아래의 예외 처리 팁 몇 가지를 살펴보자.

7.2.1 ObjectDoesNotExist vs DoesNotExist

  • ObjectDoesNotExist : 모든 모델 객체에서 이용 가능 (import 필요)
  • DoesNotExist : 특정 모델에서만 이용 가능
from django.core.exceptions import ObjectDoesNotExist

from flavors.models import flavor
from store.exceptions import OutOfStock

def list_flavor_line_item(sku):
  try:
    return Flavor.objects.get(sku=sku, quantity__gt=0)
  except Flavor.DoesNotExist:
    msg = "{} 재고가 없습니다. ".format(sku)
    raise OutOfStock(msg)

def list_any_line_item(model, sku):
  try:
    return model.objects.get(sku=sku, quantity__gt=0)
  except ObjectDoesNotExist:
    msg = "{} 재고가 없습니다.".format(sku)
    raise OutOfStock(msg)

7.2.2 여러 개의 객체가 반환되었을 때

  • 쿼리가 하나 이상의 객체를 반환할 수 있다면 MultipleObjectsReturned 예외처리를 통해 에러로그를 남기거나 원하는 방향으로 처리할 수 있다.
from flavors.models import Flavor
from store.exceptions import OutOfStock, CorruptedDatabase

def list_flavor_line_item(sku):
  try:
    return Flavor.objects.get(sku=sku, quantity__gt=0)
  except Flavor.DoesNotExist:
    msg = "{} 재고가 없습니다.".format(sku)
    raise OutOfStock(msg)
  except Flavor.MultipleObjectsReturned:
    msg = "여러개의 아이템이 SKU {}를 갖고 있습니다. 고쳐주세요!"
    raise CorruptedDatabase(msg)

7.3 쿼리를 좀 더 명확하게 하기 위해 지연 연산 이용하기

  • ORM을 활용할 때는 코드를 명확하게 작성해야 유지보수가 편해진다.
  • 나쁜예시
# 절대 따라하지 말자!
from django.models import Q

from promos.models import Promo

def fun_function(**kwargs):
  """유효한 아이스크림 프로모션 찾기"""
  # 너무 길게 작성된 쿼리 체인이 화면이나 페이지를 넘겨 버리게 되므로 좋지 않다.
  return Promo.objects.active().filter(Q(name__startswith=name)|Q(description__icontains=name))

Promo 모델 중에서 active 메소드로 리턴된 레코드 중에서 name 값이 name으로 시작하거나, description 값 중에 name이 포함되어 있는 레코드를 모두 가져와줘!

  • 지연연산 (Lazy Evaluation) 을 활용하여 장고 코드를 좀 더 깔끔하게 만들 수 있다.
  • 지연연산?
    • 데이터가 정말로 필요하기 전 까지는 장고가 SQL을 호출하지 않는 특징
    • 따라서 ORM 메소드와 함수를 얼마든지 연결해서 코드를 쓸 수 있다.
    • 한 줄에 길게 쓰는 대신에 여러줄에 나눠서 쓰면 가독성을 엄청나게 향상시키며, 유지보수를 쉽게 해준다.
  • 수정 후
from django.models import Q

from promos.models import Promo

def fun_function(**kwargs):
  """유효한 아이스크림 프로모션 찾기"""
  results = Promo.objects.active()
  results = results.filter(
              Q(name__startswith=name)|
              Q(description__icontains=name)
              )             
  results = results.exclude(status='melted')
  results = results.select_related('flavors')
  return results
  • Promo 모델 중에서 active 메소드로 리턴된 모든 레코드
  • 그 중에서 name 값이 name으로 시작하거나, description 값 중에 name이 포함되어 있는 모든 레코드
  • 그 중에서 status가 ‘melted’인 레코드는 제외
  • Foreign Key 항목인 flavors도 함께 가져와서 리턴

170724-0730_TIL (ORM, 논술, gitflow)

|

7월 30일 (일)

  • 논술 마무리 및 제출
  • 도서관리 프로젝트 모델 추가로 인해서 발생한 오류들을 수정했다.
  • git flow에 대한 글을 읽었다. 여전히 개념이 막연한데 직접 해봐야지 알 것 같다.

7월 29일 (토)

  • 논술문제를 풀었다.
  • 도서관리 프로젝트 모델을 변경했다.
    • 대여이력 관리를 위해서 RentHistory 모델을 추가
    • Book 모델 내 rent_info 필드를 RentHistory 모델과 One To One 관계로 연결 (현재 대여정보)

7월 28일 (금)

  • 논술문제를 풀었다. 사실 블로그라는걸 올해 처음 시작했고, 글쓰는 일은 여전히 나에게 익숙하지 않은 일이다. 시간이 오래 걸렸고 아직도 다 못했다. 내일은 마무리를 하고 밀린 공부를 해야지.
  • 큰 이모가 오셔서 가족들과 외식을 했다.

7월 27일 (목)

  • Django ORM 관련 글을 읽었다. Django에서 쿼리셋 효과적으로 사용하기 과거에 여러번 봤던 글인데, 스터디를 하고나서 다시 읽으니 좀 더 이해가 가는 것 같다.
  • 도서대여 프로젝트를 조금 진행했다. 대여 이력을 남기는 모델을 어떻게 구성해야 할지 고민중이다.
  • 오랜만에 판교에 가서 전 직장 동료들을 만났다.

7월 26일 (수)


7월 25일 (화)

  • 스터디 자료를 만들었다. 모르는 내용이 많아서 공부하느라 시간이 많이 걸렸다. 그래도 잘하고 싶은 ORM 관련 내용이라서 재밌게 준비할 수 있었다.
  • 쿼리 표현식, DB 트랜잭션에 대해서 공부했다.

7월 24일 (월)

  • Two Scoops of Django 7장 쿼리와 데이터베이스 레이어 부분을 읽었다. 고급 쿼리도구, DB 트랜잭션 처리 등 아직 내가 경험으로 필요성을 느끼지 못한 부분들이 많아서 특히 더 어렵다고 느꼈다. 이번 두숟갈 스터디 요약정리 당번이라서 큰일이다. 내일 한번 더 읽고 자료를 찾아보면서 공부해야지
  • 골빈해커 김진중님을 만나고 왔다. 신입 개발자로서 참고가 될 많은 조언을 들을 수 있었다. 무엇보다 처음 연락부터 만남까지 굉장히 정중하셔서 깜짝 놀랐다. 나도 언젠가 저런 시니어가 되고 싶다고 생각했다.(결심..!)
  • 패캠에서 같이 공부했던 진호님께 객체지향의 사실과 오해라는 책을 추천받았다. 워낙 좋다고 강력하게 추천을 하셔서 내용이 궁금해졌다. 읽어봐야지

170717-0723_TIL

|

7월 23일 (일)

  • 알고리즘 문제를 풀었다.
  • 그림으로 개념을 이해하는 알고리즘 해시테이블 부분을 읽었다. 역시나 쉽게 잘 설명되어 있었다. 나 같은 초보자가 읽기에 적합한 책인 것 같다.
  • 블로그에 정리해둔 컴퓨터공학 강의 노트를 다시 읽었다. 읽을 때마다 매번 새롭다…(어려워..!)

7월 22일 (토)

  • 그림으로 개념을 이해하는 알고리즘 퀵정렬 부분을 읽었다. 재귀에 대해서 쉽게 잘 설명되어 있어서 도움이 많이 되었다. 특히 퀵정렬 구현 코드가 지금까지 봤던 코드 중에 가장 짧고 간단해서 마음에 들었다.

  • 생활코딩 자료구조 배열과 리스트 수업을 들었다. 어쩌다보니 정기적으로 반복해서 듣고 있는데 어쩜 이렇게 매번 새로운지.. 그리고 항상 초보자에게 맞춘 적절한 비유와 설명에 감탄을 하게된다.

  • 오랜만에 메모리공간에 대한 강의 노트를 다시 읽어보았다. 파이썬의 private heap 영역 사용에 대한 자료를 찾다보니, C언어는 malloc 함수를 사용해서 필요에 따라 heap 영역에 메모리를 동적으로 할당할 수 있다는 글을 읽었다(우와..) C언어는 Data, Heap, Stack 영역을 모두 사용할 수 있으니 C 언어를 사용하려면 메모리에 대한 이해가 당연히 필요할 수 밖에 없겠다는 생각이 들었다. 반대로 메모리에 대해서 잘 이해하고 싶으면 C언어를 공부하는 것도 좋은 동기부여가 될 수 있겠다. (하지만 현실은..)

    참고 : Heap은 Stack과 함게 프로세스의 대표적인 메모리 처리 공간, 혹은 기법중 하나인데, 예를 들어, 일반적인 로컬 변수는 Stack에, malloc과 같은 동적 할당 메모리는 Heap에서 주로 사용되기도 합니다. 즉, 처음부터 그 크기가 결정되어 계획하에 잡히는 메모리는 주로 Stack이고, 그 크기가 결정되지 않아 계속 커지거나, 변동하거나, 매우 큰 경우에는 동적 할당 메모리, 즉, Heap을 사용하게 됩니다. (출처)

  • 처음 ArrayList, LinkedList를 접했을 때가 생각났다. 파이썬에 List가 있는데 왜 저런 자료구조를 배워야 할까? Array랑 List가 뭐가 다른 걸까? Javascript에서 Array라고 부르는걸 파이썬에서 List라고 부르는 거 아닌가? 당시에 나는 Python과 Javascript만 접해보았기에 ArrayList, LinkedList의 개념과 필요성이 잘 와닿지 않았다. 사실 지금도 상황은 비슷하지만.. 그래도 최근 Java 문법을 공부하면서 조금은 그 필요성에 대해서 공감할 수 있었다.

    Java의 Array를 사용해보니 처음 선언할 때에 크기를 지정해야 하고, 자유롭게 요소를 추가하고 삭제하는 것이 불가능했다. 그래서 collection framework에서 제공하는 ArrayList, LinkedList를 가져다가 사용해야만 했다.(불편해..!) Java 사용자가 느끼는 자료구조에 대한 필요성은 Python 사용자보다 크지 않을까? 선택지가 많은 만큼 각각의 특성을 잘 이해해야만 제대로 활용할 수 있겠다.

    이고잉님의 강의 중에 무언가를 배울 때는 그것이 없을 때 얼마나 불편할 것인지를 생각해 보는 것이 학습의 동력이 될 수 있다 라는 이야기가 있었다. Python에서는 당연하게 가능한 것들이 다른 언어에서는 가능하지 않은 것을 보면서 이 말에 더 공감을 하게 된다. 나중에 여유가 되면 Python 이외의 언어를 배우면서 불편함을 직접 느껴보는 것도 좋겠다. (결론은 파이썬 만세..!)

7월 21일 (금)

  • 알고리즘 문제를 풀었다.
  • 쉘스크립트 자료를 읽었다. (Bash Shell Script) 예전에 pyenv를 처음 설치 했을때 $ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc 같은 명령을 정체도 모르고 입력했었는데 이게 쉘스크립트 중의 하나였구나.
  • 자료가 좀 어려워서 찾아보니 생활코딩 리눅스 카테고리에 쉘 스크립트 소개 강의가 있었다.
    • 쉘스크립트란?
    • 어떤 일을 하고자 사용하는 명령이 여러개일때, 순차적으로 실행되는 명령의 순서(script)를 어딘가에 적어놓고 재사용 할 수 있다면 편리하다.
    • 이처럼 쉘에서 실행되는 명령들을 하나의 파일에 적어두고, 해당 명령의 집합을 한번에 실행하는 방법이 쉘 스크립트이다.
  • 처음 만들어본 쉘 스크립트
    • bak 이라는 폴더가 있는지 확인하고 없으면 폴더를 만든다.
    • log 라는 suffix 를 가진 파일들을 bak 이라는 폴더에 복사한다.
    • chmod +x 파일명 명령을 통해 실행권한 추가
#!/bin/bash
if ! [ -d bak ]; then
        mkdir bak
fi
cp *.log bak

7월 20일 (목)

  • 오늘은 알고리즘 문제 하나를 갖고서 오전 내내 고민을 하면서 보냈다. 재귀는 여전히 나에게 미지의 영역이고, 어떻게든 꾸역꾸역 풀어 냈지만 여전히 풀이가 마음에 들지는 않는다. 평소에 꾸준히 공부 좀 할걸!
  • 오랜만에 패스트캠퍼스 자료구조 수업 선생님을 만나서 치맥을 했다. 3시간 넘게 개발 이야기로 아무말 대잔치를 했는데 재미있고 신기한 경험이었다.
  • 해커톤에 함께 참여할 동생을 만나서 회의는 안하고 꿀팁만 잔뜩 얻었다.
  • Jayjin 님이 3년 전에 쓰신 지식의 곱셈 – 찌랭이, 중수, 짱이라는 글을 격하게 공감하면서 읽었다.

    같은 찌랭이를 만나든, 중수를 만나든, 짱을 만나든 모든 사람에게 배우니 찌랭이는 얼마나 행복한 단계인가.


7월 19일 (수)

  • 8퍼센트 두숟갈 스터디에 참여했다.
    • 데이터베이스 정규화를 다루었는데 아직은 막연한 개념이라 잘 이해하지는 못했다. 그래도 모델 설계를 잘 하기 위해서는 정규화가 필요하다는 것은 알았다. 최근 도서관리 사이트의 모델을 만들 때 모델 1개에 많은 정보를 담으려고 했었다. (1:ㅜㅜ1, 1:N, M:N 관계로 나누면 DB 조회시 중복 쿼리가 많이 발생했었기에..) 하지만 오늘 배운 내용을 적용하면 모델을 나눌 수 있는 여지가 많겠다는 생각을 했다.
    • 정규화 : 관계형 데이터베이스(테이블간에 관계를 맺을 수 있는 상황)에서 중복을 최소화 하기 위해서 데이터를 구조화 하는 작업 (위키, 참고글)
  • 간단한 알고리즘 문제를 풀었다.

7월 18일 (화)

  • 사내 도서관리 사이트 연습 프로젝트를 진행했다. 연습내용
    • 도서 구매신청, 도서 대여 및 반납 기능을 구현했다.
    • Fat models, thin views, stupid template 3가지를 기억하고, view 보다는 model에 로직을 구현하려고 신경쓰고 있다.
      • 대여, 반납, 연체여부를 확인 기능을 Book 모델의 인스턴스 메소드로 추가
      • 월별 도서구매 신청금액 확인 기능을 WishBook 모델의 클래스 메소드로 추가
    • 월별로 도서 구매신청 총액을 구하기 위해서 Django ORM의 aggregate를 활용하는 연습을 할 수 있었다. (엑셀만큼 쉬운) Django Annotation/Aggregation 글이 많은 도움이 되었다.
    • include를 활용해서 중복 코드를 줄일 수 있었다. include 'include/book.html' with type='wish'와 같이 전달하는 context 값에 따라서 조금씩 다르게 화면을 구성할 수 있었다.
    • 도서 대여기능을 넣다 보니까 datetime, timezone 을 활용하게 되었는데, DB에는 timezone Asia/Seoul 에 맞게 저장되지만, django shell에서 확인하면 UTC 기준으로 DateTime 필드정보를 가져오는 문제가 있었다. 아직 원인을 잘 이해하지 못했는데 내일 아래 글을 읽고 천천히 다시 살펴봐야겠다.

내일 할 일

  • UTC timezone 문제 관련 글 읽기
  • 8퍼센트 스터디 참여하기
  • 별점, 한줄평 기능 추가하기

7월 17일 (월)

  • 사내 도서관리 사이트 연습 프로젝트를 진행했다. 연습내용
    • api를 활용한 도서 검색기능, 신규도서 DB 등록기능 구현
  • User 모델 확장에 대한 Django 공식문서를 읽었다. Customizing authentication in Django 목적에 따라서 User 확장방식을 적절하게 선택할 수 있어야겠다고 생각했다.
    • Proxy Model : User 모델에 필드, 인증방식 이외의 추가 정보 (ex. ordering) 적용
    • User Profile 모델 : Default User Model 과 1:1 관계
    • AbstractBaseUser 상속 모델 : Default User Model 오버라이딩, 인증방식 변경, 필드 추가
    • AbstractUser 상속 모델 : Default User Model 오버라이딩, 필드 추가 (User Profile 모델과 목적은 유사, 모델 분리의 여부)