본문 바로가기
관리자

Programming-[Backend]/Django

[TIL] Django created_by, modified_by 적용하기 : django crum, settings.AUTH_USER_MODEL 등

728x90
반응형

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()

접속 중인 유저가 로그인한 상태인지 판단하는 메서드

728x90
반응형