1. 기본원리
- 기본원리는 threading → Local로 개별 쓰레드가 user를 물고와서 Middleware를 통해 Model를 업데이트 해주는 방식
https://solutionschecker.com/questions/django-populate-user-id-when-saving-a-model/
2. Django Crum library
Django crum에서 get_current_user()를 처리하기 전에, 앞선 미들웨어인 AuthenticationMiddleWare에서 Request.user를 불러오는데, 여기서 get_user() 메서드 쪽을 보면 세팅에서 지정한 User를 참고하여 불러오는 것을 확인할 수 있다. 이렇게 구해진 user 정보가 django crum의 middleware로 전달된다.
MIDDLEWARE = [
...
"django.contrib.auth.middleware.AuthenticationMiddleware",
...
"crum.CurrentRequestUserMiddleware",
]
- requirements.txt에 django-crum==0.7.9 넣어주기
python, django 버전마다 업데이트 및 테스트 관리 중이다.
https://pypi.org/project/django-crum/
라이브러리를 사용할 때는 버전에 따라 Spec이 계속 변할 수 있는 위험에 대해서 잘 파악하고 사용하여야 한다. python 및 Django 버전에 따라 업데이트 및 테스트가 잘 되고 있는지 봄과 동시에, 버전의 main 주 숫자가 1.x.x 이상이 되어야 안정적인 라이브러리일 것이라고 기대할 수 있다.
3. BaseModel에 추가해주기
레거시 코드가 공통으로 기본모델을 참조하여 기본 BaseModel에 created_by, modified_by를 추가할 수 없는 상황이였다. 대신 새로운 모델에서는 이를 사용할 수 있도록 RequestUserModel 객체를 따로 만들고 save 메서드를 override 하였다.
class RequestUserModel(models.Model):
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
null=True,
blank=True,
editable=False,
related_name="%(class)s_created_by",
default=None,
db_column="created_by",
on_delete=django.db.models.deletion.DO_NOTHING,
)
modified_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
null=True,
editable=False,
related_name="%(class)s_modified_by",
default=None,
db_column="modified_by",
on_delete=django.db.models.deletion.DO_NOTHING,
)
class Meta:
abstract = True
def save(self, *args, **kwargs):
user = get_current_user()
if user.is_anonymous:
self.created_by = None
self.modified_by = None
if user and not user.pk:
user = None
if not self.pk:
self.created_by = user
self.modified_by = user
super(RequestUserModel, self).save(*args, **kwargs)
배운점
3-1. related_name, %(class)s_
related_name은 N인 모델에서 1인 모델로 역참조를 할 때 참조할 이름값을 의미한다. 정의하지 않으면 기본적으로 set_{model이름}으로 지정된다. 그러나 위 예시의 경우 created_by, modified_by 둘다 user 모델을 참고하므로 related_name을 따로 지정해주어 구분해주어야만 migration 및 orm에서의 조회가 가능해진다. 그리고 realted_name의 앞에 %(class)s를 추가하여 model 마다 역참조 시에 구분이 되도록 해야한다. 예를 들어 issue:user = 1:N, comment:user=1:N 인 경우 user에 related_name=’created_by’로 정의해놓으면 user.created_by는 issue의 created_by인지, comment의 created_by인지 알 수가 없다.
참조 : https://velog.io/@brighten_the_way/Django와-Reverse-relations과-Relatedname
참조 : %(class)s_관련 (여기서 s는 역참조로 1:N에서 N을 가리키는 의미적 단어이다)
https://velog.io/@lack12/Django-ForeignKey와-relatedname
만약 역참조(1 → N)을 허용하지 않을려면 **related_name = ‘+’**로 지정해주면 된다.
참조 : https://stackoverflow.com/questions/19555760/django-use-of-related-name
3-2. settings.AUTH_USER_MODEL
settings에 AUTH_USER_MODEL 값을 정의해주면 커스터마이징된 user 모델을 사용할 수 있다.
3-3. db_column
Django는 기본적으로 ForeignKey 값의 이름 뒤에 '_id'를 붙여준다. 이렇게 하지 않고 깔끔한 이름을 지정하고 싶을 때 사용하는 속성값이다.
3-4. (참고) django.contrib.auth -> get_user_model()
get_user_model()로 AuthenticationMiddleware에서 불러오는 request.user 정보를 얻어올 수 있다.
3-5. user.is_anonymous(), user.is_authenticated()
접속 중인 유저가 로그인한 상태인지 판단하는 메서드
'Programming-[Backend] > Django' 카테고리의 다른 글
[TIL] Django ORM values, annotate, Subquery, OuterRef, JSONField, Type Cast 부분 적용 (2) | 2022.09.30 |
---|---|
[TIL] 부모 Serializer field 값 제거 (0) | 2022.09.29 |
[TIL] Django ModelSerializer의 field, validate()의 data (0) | 2022.09.21 |
[TIL] 파이썬 리턴타입 힌트로 속성 탐색, unittest.mock의 @patch (0) | 2022.09.14 |
[TIL] get_serializer()와 serializer.save()의 instance, get_object_or_404 (0) | 2022.09.14 |