Project/[Project] React DRF Blog

[Backend] 정리 - 1

bonevillain 2023. 6. 29. 16:38

□ Model 필드 부분 update

포스트 방문 수 측정을 위해 Post 모델의 hits라는 필드를 가지고 있다.

class Post(models.Model):
    ...
    hits = models.BigIntegerField(default=0)
    updated_at = models.DateTimeField(auto_now=True)
    ...

정말 많은 사람들이 방문하고 그랬다면 Redis 서버를 별도로 두어서 카운팅을 하고 스케줄러를 통해 주기적으로 DB에 업데이트해줬을 것이지만 여기서는 그런 주제의 글이 아니기에 패쓰

 

 

단순하게 사람들이 방문하면 +1씩 값을 증가시켜주는데 아래와 같이 그냥 save를 호출할 경우, DB에 전체 필드를 그대로 업데이트하게 된다.

def retrieve(self, request, slug=None):
    post = get_object_or_404(
        Post.public.select_related("author"),
        slug=slug,
    )
    post.hits += 1
    post.save() # 방문수 +1 증가 후 저장
    ...

 

save() 호출 시, 모든 필드를 Update

 

이는 불필요한 자원 소모를 가져오기 때문에 save를 호출할 때, update_fields를 명시해주면 해당 부분만 Update를 하게 된다.

참고로 여기서 updated_at 같은 수정일 관련 필드에서 auto_now가 true인 값을 가질 경우, udpate_fields에 같이 명시를 해주어야한다. 그렇지 않으면 수정일이 업데이트되지 않는다.

def retrieve(self, request, slug=None):
    post = get_object_or_404(
        Post.public.select_related("author"),
        slug=slug,
    )
    post.hits += 1
    post.save(update_fields=["hits", "updated_at"]) # 업데이트할 필드 명시
    ...

 

명시한 필드들만 업데이트되고 있다.

 

 

 

 

□ Model Manager

블로그 글을 작성할 때는 Django Admin에서 하기 때문에 공통적으로 코드 대부분이 발행된 글을 가지고 필터링하고 보여주는 것들이 대부분이다. 다시 말해 is_published 값이 True인 것들만 가지고 리스트를 보여주고 필터링한다.

class Post(models.Model):
    ...
    is_published = models.BooleanField(default=False) # 글 발행 여부
    ...

 

ORM 가지고 매번 Post.objects.filter(is_published=True, ...) 이렇게 치면 너무 귀찮고 실수가 유발할 가능성이 커진다.

예를 들어 아래와 같이 각 상세 페이지에서는 이전, 다음 블로그 글의 제목을 표기해주는데 미발행 글을 고려하지 않으면 해당 글의 제목이 나타날 수 있다.

 

이전, 다음 블로그 글의 제목 표시 예시

 

그래서 아래와 같이 매니저를 하나 만들어줬다. 별도로 명시하지 않으면 is_published 필드가 자동으로 True로 잡히고 혹시라도 누군가 is_published 필드를 False 이용하는 사태가 발생하면 그대로 사용할 수 있게 해주었다.

class PublicPostManager(models.Manager):
    def filter(self, *args, **kwargs):
        if kwargs.get("is_published") == False:
            return super().get_queryset().filter(*args, **kwargs)
        return self.get_queryset().filter(*args, **kwargs)

    def get_queryset(self):
        return super().get_queryset().filter(is_published=True)

 

처음에는 아래와 같이 objects를 오버라이드하여 사용하였었다. 내가 작성한 코드에서는 별문제가 없었으나..

class Post(models.Model):
    ...

    objects = PublicPostManager()

 

근데 역시.. Django는 최대한 그대로 사용하는 것이 좋다는 것이 이런 부분에서 나타나는 것 같다. 이렇게 적용하게 되면 Django Admin의 Post 페이지에서는 is_published 필드가 True인 것만 나타나게 된다.

ID가 1부터 100개까지 차례로 있었으나 is_published 필드가 False인 값은 사라졌다.

 

이에 따라 별도로 커스텀 매니저를 넣어주고 기존 것(objects)도 함께 넣어준다. 기존 것을 안넣어주면 Post.objects는 동작하지 않는다.

class Post(models.Model):
    ...

    objects = models.Manager()
    public = PublicPostManager()

 

'Project > [Project] React DRF Blog' 카테고리의 다른 글

[Frontend] 정리 - 1  (0) 2023.06.29
Intro.  (0) 2023.06.29