본문 바로가기
Programing/django

auto_now VS auto_now_add

by Tomining 2016. 8. 19.
Django Model field 중에 DateField 가 있습니다.
웹에서 CRUD 작업을 하다보면 보통 생성일자와 수정일자 정보를 DB 스키마에 만들어서 저장하게 됩니다.

생성일자 - 최초 등록시에만 저장, 갱신되지 않는 정보
최종수정일자 - 수정시 갱신

보통 위처럼 사용하게 될 것입니다.
이를 지원하기 위해서 DataField 에는 auto_now 와 auto_now_add 속성이 존재합니다.

Django 공신문서에 보면 아래와 같이 설명하고 있습니다.


요약해 보면 아래와 같습니다.

  • 수정일자 : auto_now=True 사용
    auto_now=True 는 django model 이 save 될 때마다 현재날짜(date.today()) 로 갱신됩니다.
    주로 최종수정일자 field option 으로 주로 사용됩니다. 
  • 생성일자 : auto_now_add=True 사용
    auto_now_add=True 는 django model 이 최초 저장(insert) 시에만 현재날짜(date.today()) 를 적용합니다.

여기서 auto_now_add 의 경우는 이슈가 있습니다.

모델 객체를 생성 후 저장(save) 를 하게되면 null 로 저장될 수 있습니다.

예를 들어 아래와 같이 코드가 작성되어 있다고 가정해 봅시다.
class User(models.Model):
    class Meta:
        db_table = 'user_mstr'

    id = models.DecimalField(primary_key=True)
    name = models.CharField(max_length=100)
    create_date = models.DateField(auto_now_add=True)
    modify_date = models.DateField(auto_now=True)
user = User()
user.id = id
user.name = name

user.save(force_update=True)
# 수행쿼리
UPDATE user_mstr
SET id=id, name=name, create_date = null, modify_date = SYSDATE
WHERE id=id

위 처럼 null 로 저장될 수 있습니다.
그 이유가 궁금하여 django model 의 DateField 코드를 확인해 보았습니다.

def pre_save(self, model_instance, add):
    if self.auto_now or (self.auto_now_add and add):
        value = datetime.date.today()
        setattr(model_instance, self.attname, value)
        return value
    else:
        return super(DateField, self).pre_save(model_instance, add)

auto_now=True 인 경우는 date.today() 로 현재일시를 세팅하는 것을 확인할 수 있습니다.
auto_now_add=True 의 경우는 add 라는 파라메터와 함께 확인하고 있는데, 이는 insert 인 경우만 add=True 로 넘어오게 됩니다.
즉, insert 시에만 현재날짜로 갱신됨을 의미합니다.

그렇다면 update 할 때, 왜 null 로 저장될까요?
이는 else 구문에 의해서 그렇습니다. else 구문의 의미는 model_instance 의 속성값을 그대로 반환하도록 되어 있습니다.
위 예제 쿼리에서 User() 객체 생성 후 create_date 속성을 설정하지 않았기 때문에 None 이 저정되고 이 부분이 null 로 설정되는 것입니다.
(auto_now나 auto_now_add 를 설정하면 blank=True 가 자동으로 설정됩니다. 코드에서 확인 가능)

따라서 null 로 갱신되는 이슈를 해결하기 위해서는 create_date 값을 model 값에 세팅해 주어야 합니다.
수동으로 세팅해 주는 방법이 있긴 하지만 개인적으로 DB 조회를 통해서 가져오는 방법이 깔끔한 방법인 것 같습니다.
user = User.objects.get(id=id) # DB 조회, create_date 값 존재
user.name = name

user.save(force_update=True)

위처럼 하면 create_date 컬럼에 null 이 아닌 기존 값을 저장할 수 있습니다.(갱신 안되는 효과)

위 방법 외에도 update 시에 update_fields 속성에 필드값을 지정해 주어 create_date 컬럼이 update 쿼리에서 제외되도록 할 수도 있습니다.
이는 명시적으로 컬럼을 지정해 주어야 한다는 단점이 있긴 하나 DB select 를 한 번 하지 않아도 된다는 장점이 있습니다.


참고

'Programing > django' 카테고리의 다른 글

Django Model Aggregate  (0) 2016.08.19
Django 기초 스터디 자료  (0) 2016.04.04