-
Django 에서 일시적으로 auto_now, auto_now_add 를 disable 시키는 법기술/Django 2021. 9. 24. 19:39
종종 엑셀에서 가끔 데이터를 마이그레이션 할 때가 있습니다.
그 때 특정 필드를 마이그레이션 데이터 값으로 채워넣어야하지만 auto_now, auto_now_add 가 설정되어 있다면
저장 시 데이터가 마이그레이션 데이터가 아니라 최신 값의 Datetime 으로 설정됩니다.
그래서 그 때마다 사용할 수 있는 문법이 필요했습니다.
TemporarilyDisableAutoNowAndAutoNowAdd
주어진 모델의 save, bulk_ 메서드를 사용할 때 auto_now, auto_now_add 필드를 비활성화하는 Context Manager 를 생성하기로 했습니다.
매개변수
- Model: auto_now, auto_now_add 를 비활성하고싶은 Django 의 모델을 제공합니다.
- field_names: 여러 개의 auto_now, auto_now_add 필드가 있을 때 그 중 특정 필드만 비활성화 시킵니다. 만약 field_names 가 제공되지 않으면 모든 auto_now, auto_now_add 를 비활성화합니다.
구현
- field_names 가 주어짐에 따라 auto_now, auto_now_add 를 비활성화합니다.
- Context Manager 가 종료되면 비활성화한 auto_now, auto_now_add 를 다시 활성화합니다.
class TemporarilyDisableAutoNowAndAutoNowAdd: def __init__(self, model, field_names: List[str] = None): self.model = model self.field_names = field_names # 나중에 활성화하기위해 비활성화한 필드들을 담아둡니다. self.auto_now_fields = [] self.auto_now_add_fields = [] def _disable_field(self, field: models.Field, field_name: str): """ 주어진 필드의 속성을 비활성화하기 위해 사용하는 메서드 """ # 활성화되어있는 필드만 비활성화 if getattr(field, field_name): setattr(field, field_name, False) getattr(self, f'{field_name}_fields').append(field) def __enter__(self): fields = [] if self.field_names: # field_names 가 주어졌다면 주어진 필드만 비활성화 for field_name in self.field_names: fields.append(self.model._meta.get_field(field_name)) else: # field_names 가 주어지지 않았다면 모든 필드를 비활성화 for field in self.model._meta.local_fields: if field.__class__ in [models.DateField, models.DateTimeField]: fields.append(field) for field in fields: self._disable_field(field, 'auto_now') self._disable_field(field, 'auto_now_add') def __exit__(self, type, value, traceback): for field in self.auto_now_fields: field.auto_now = True for field in self.auto_now_add_fields: field.auto_now_add = True
사용해보기
모든 필드의 auto_now, auto_now_add 비활성화
post = Post.objects.first() post.modified = random_datetime() # auto_now_add 가 True 로 설정된 필드 with TemporarilyDisableAutoNowAndAutoNowAdd(Post): # save 할 때만 TemporarilyDisableAutoNowAndAutoNowAdd 로 감싸주면 됩니다. post.save()
특정 필드의 auto_now, auto_now_add 비활성화
post = Post.objects.first() post.modified = random_datetime() # auto_now_add 가 True 로 설정된 필드 post.timestamp = random_datetime() # auto_now_add 가 True 로 설정된 필드 with TemporarilyDisableAutoNowAndAutoNowAdd(Post, field_names=['modified']): # save 할 때만 TemporarilyDisableAutoNowAndAutoNowAdd 로 감싸주면 됩니다. # 이 때 결과는 modified 는 random_datetime() 값으로 변경되지만 # post.timestamp 는 auto_now_add 가 설정되어있으므로 random_datetime() 값이 아니라 현재 시간이 설정되어있습니다. post.save()
'기술 > Django' 카테고리의 다른 글
django 에서 select_related, prefetch_related 에서 추가적인 ORM 을 사용하기 (0) 2021.09.24 django-filters 를 사용하여 복잡한 환경에서 OrderingFilter 사용하기 (0) 2021.09.24 Django Filters 에서 하나의 Key를 가지고 여러 값 필터하기 ( MultipleFilter ) (0) 2021.09.24 Django 에서 String datetime 을 aware 한 datetime 으로 변경하는 방법 (0) 2021.09.24 Django 에서 Chain 필터 시 추가적인 테이블 JOIN 방지하기 ( + _next_is_sticky ) (0) 2021.09.24 TAG