Context Manager의 개념은 여기 <- 에서 확인 하실수 있습니다.
실제로 소스코드에서 쓰는 Context Manager는 TestCase에서 settings 값을 변경하는 TestContextDecorator에 구현이 되어 있습니다.
Testcase.settings→ override_settings→TestContextDecorator
class TestContextDecorator:
"""
A base class that can either be used as a context manager during tests
or as a test function or unittest.TestCase subclass decorator to perform
temporary alterations.
`attr_name`: attribute assigned the return value of enable() if used as
a class decorator.
`kwarg_name`: keyword argument passing the return value of enable() if
used as a function decorator.
"""
def __init__(self, attr_name=None, kwarg_name=None):
self.attr_name = attr_name
self.kwarg_name = kwarg_name
def enable(self):
raise NotImplementedError
def disable(self):
raise NotImplementedError
def __enter__(self):
return self.enable()
def __exit__(self, exc_type, exc_value, traceback):
self.disable()
class override_settings(TestContextDecorator):
# ...
def enable(self):
# ...
# This gets called by __enter__
for key, new_value in self.options.items():
setattr(override, key, new_value)
self.wrapped = settings._wrapped
settings._wrapped = override
for key, new_value in self.options.items():
setting_changed.send(sender=settings._wrapped.__class__,
setting=key, value=new_value, enter=True)
def disable(self):
# ...
# This gets called by __exit__
for key in self.options:
new_value = getattr(settings, key, None)
setting_changed.send(sender=settings._wrapped.__class__,
setting=key, value=new_value, enter=False)
또한 Django의 Transaction의 데코레이터 에서도 사용됩니다.
@transaction.atomic
def do_something():
# this must run in a transaction
# ...
# class Atomic is implemented later
def atomic(using=None, savepoint=True):
# Bare decorator: @atomic -- although the first argument is called
# `using`, it's actually the function being decorated.
if callable(using):
return Atomic(DEFAULT_DB_ALIAS, savepoint)(using)
# Decorator: @atomic(...) or context manager: with atomic(...): ...
else:
return Atomic(using, savepoint)
class Atomic(ContextDecorator):
# There is a lot of complicated corner cases and error handling.
# See the gory details in django/django/db/transaction.py
def __init__(self, using, savepoint):
self.using = using
self.savepoint = savepoint
def __enter__(self):
connection = get_connection(self.using)
# ...
# sid = connection.savepoint()
# connection.savepoint_ids.append(sid)
def __exit__(self, exc_type, exc_value, traceback):
# Skip the gory details
# ...
sid = connection.savepoint_ids.pop()
if sid is not None:
try:
connection.savepoint_commit(sid)
except DatabaseError:
connection.savepoint_rollback(sid)
'DRF & Django' 카테고리의 다른 글
[DRF] Serializers 개념 (0) | 2022.08.08 |
---|---|
[DRF] ORM 중복 제거 (0) | 2022.03.10 |
[DRF] Redis vs RabbitMQ and setting (0) | 2022.02.03 |
[DRF] Redis, Celery 기본 세팅 (1) | 2022.02.01 |