2025/11/17 Django - 10

김기훈·2025년 11월 17일

TIL

목록 보기
58/191

오늘 학습 내용

[인스타그램] 세부 기능 구현하기


태그 기능 처리하기

  • 대용량 데이터일 때 검색 성능을 높이기 위해 태그를 사용할 수 있습니다.

@receiver

  • @receiver 데코레이터 는 Django의 시그널 프레임워크와 관련된 기능
    • 시그널을 수신하여 특정 작업을 수행하는 함수(시그널 핸들러)를 정의하는 데 사용
    • 시그널은 Django에서 특정 이벤트가 발생했을 때 자동으로 호출될 수 있는 기능을 제공
  • 주요 개념
    • 신호(signal)
      • Django에서 특정 이벤트가 발생했을 때 이를 알리는 메커니즘
      • ex. 모델 인스턴스가 저장되거나 삭제될 때 신호를 발송 가능
    • 신호 핸들러(signal handler)
      • 신호를 수신하여 처리를 수행하는 함수
      • @receiver 데코레이터를 사용하여 신호 핸들러를 정의
  • 기본 사용법
    • 신호 정의
      • Django는 이미 여러 기본 신호를 제공하며, 신호를 사용하여 특정 작업을 처리 가능
      • 신호는 django.db.models.signals 모듈 또는 django.core.signals 모듈에서 찾음
    • 신호 핸들러 작성
      • 신호를 수신하여 특정 작업을 수행할 함수
      • @receiver 데코레이터를 사용하여 신호를 핸들링하는 함수를 정의
    • 신호 핸들러 등록
      • @receiver 데코레이터를 사용하여 특정 신호를 수신할 핸들러를 등록
  • 신호 종류
    • Django는 여러 가지 기본 신호를 제공, 주요신호는
      • pre_save: 모델 인스턴스가 저장되기 전에 발생
      • post_save: 모델 인스턴스가 저장된 후에 발생
      • pre_delete: 모델 인스턴스가 삭제되기 전에 발생
      • post_delete: 모델 인스턴스가 삭제된 후에 발생
    • 이 외에도 Django는 다양한 신호를 제공하며, 사용자 정의 신호를 만드는 것도 가능
    • 신호는 비즈니스 로직을 모델의 저장, 삭제 등과 같은 특정 이벤트와 분리하여 처리할 수 있게 해줌

실습

  • 라이브러리
    • from django.db.models.signals import post_save
    • from django.dispatch import receiver
    • import re

  • @receiver(post_save, sender=Post)
    • pre_save / post_save
      • post_save: 저장된후에 호출
  • #(\w{1,100})(?=\s|$)
    • #으로 시작하고 텍스트가 1~100글자 뒤에 공백
      • # 뒤에 바로 적어야 하고 띄어쓰기 존재하면 적용 안됨
  • get_or_create
    • 있으면 가져오고 없으면 만들어라
      • 첫 번째는 객체 두번째는 True/False 생성됬는지 여부 출력
  • Tag라는 모델에 posts가 이름이 tags이기 때문에
    • instance.tags.clear() : 중계모델을 다 삭제
      • Tag랑 Post 둘다 외래키로 가지고 있는 중계모델이 존재
    • instance.tags.add(*tags) : 연결

댓글 기능 처리하기

실습 1

  • removeClass('d-none') 대신 toggleClass('d-none') 사용시
    • '댓글작성'을 한번 더 누르면 댓글작성 창이 없어짐(remove는 없애기 불가)

LoginRequiredMixin

  • Django에서 제공하는 믹스인 클래스
    • 사용자가 로그인해야만 특정 뷰에 접근할 수 있도록 제한할 때 사용
    • 이 믹스인은 주로 Django의 클래스기반 뷰(CBV)와 함께 사용
    • 함수 기반 뷰(FBV)에서는 @login_required 데코레이터 를 사용하여 같은 기능을 구현 가능

실습 2

  • Django의 제너릭 뷰를 사용하여 댓글을 생성하는 기능을 구현

  • commit = False

    • 객체는 데이터베이스에 저장되지 않고, 반환된 객체를 수정할 수 있음
  • 아직 댓글 작성 안됨

  • post = Post.objects.get(pk=self.kwargs.get('post_pk'))

    • URL의 post_pk 매개변수에서 Post 객체를 가져와 댓글에 연결
    • 이 방식대로 하면 속도가 느림
  • prefetch_related('comments')

    • 쿼리 횟수가 줄어들어서 DB왕복이 줄어들고 게시글변 개별 쿼리가 한 번에 묶여서 속도 증가
  • 댓글 디자인 다듬기


기능언제 사용?어떻게 동작?조인 발생?
select_relatedForeignKey, OneToOne(1:1, N:1)JOIN 해서 한 번에 가져옴✔ JOIN 발생
prefetch_relatedManyToMany, RelatedManager(1:N), reverse 관계두 번 쿼리하고 파이썬에서 매칭✖ JOIN 없음

예시

  • 원래 방식(prefetch 없는 경우)
    • ex. 게시글 5개를 가져오면 다음 흐름이 발생
      • 게시글 5개 가져오는 쿼리 1번
      • 각 게시글마다 댓글을 가져오기 위해 추가 쿼리 발생
        • 게시글 5개라면 댓글 쿼리도 5번 발생
        • 총 6번 쿼리
  • prefetch_related 적용
    • ex. 게시글 5개를 가져오면 다음 흐름이 발생
      • 게시글 5개를 가져오는 쿼리 1번
      • 이 5개 게시글의 id를 한꺼번에 모아서 WHERE IN 으로 댓글을 한 번에 가져옴
        • 즉, 게시글 쿼리: 1번 / 댓글 전체를 한 번에 가져오는 쿼리: 1번 = 총 2번

reverse와 reverse_lazy의 차이점

  • Django에서 URL을 동적으로 생성하는 두 가지 방법
    • 둘 다 URL을 동적으로 참조할 때 사용, 그 사용 시점과 용도가 약간 다름
    1. 즉시 평가와 지연 평가:
    • reverse: 즉시 평가 
      • reverse 를 호출하면 바로 URL 문자열을 생성하여 반환
    • reverse_lazy: 지연 평가
      • 이 함수는 호출된 즉시 URL을 반환 X, 실제로 URL이 필요할 때까지 평가를 미룸
      • 이는 주로 클래스 기반 뷰(CBV)에서 URL을 정의할 때 유용
    1. 사용 시점:
    • reverse : 함수 기반 뷰(FBV)나 URL이 즉시 필요할 때 사용
      • ex. 뷰 안에서 리디렉션을 할 때 사용
    • reverse_lazy : 클래스 기반 뷰(CBV)에서 속성을 정의할 때 사용
      • 이 시점에서 URL이 즉시 필요하지 않기 때문에 나중에 평가될 수 있음

좋아요 기능 만들기

실습 1

  • 실제 인스타그램 처럼 댓글 / 내용 위치 변경

  • 댓글작성 이라는 버튼을 없애고 말풍선 이모티콘을 누르면 댓글창이 나오도록 변경

@register.simple_tag()

  • 템플릿 태그를 정의할 때 사용, 주로 커스텀 템플릿 태그를 만들 때 사용

    • 템플릿에서 간단한 로직을 실행하고, 그 결과를 출력하고자 할 때 사용

    • 템플릿 코드의 재사용성을 높이는 데 유용

      from django import template
      
      register = template.Library()
      
      @register.simple_tag
      def add(a, b):
          return a + b
          
      # 이 태그는 템플릿에서 `{% add 5 10 %}`와 같이 사용할 수 있으며, 결과는 `15`가 됩니다.

@csrf_exempt

보안에 매우 중요한 보호 기능을 비활성화하는 것이므로, 정말 필요한 경우에만 사용권장.

  • CSRF(Cross-Site Request Forgery) 보호를 비활성화

    • Django는 기본적으로 모든 POST 요청에 대해 CSRF 보호를 적용

    • 그러나 특정 뷰에서 CSRF 검사를 피하고자 할 때 이 데코레이터를 사용

      from django.views.decorators.csrf import csrf_exempt
      
      @csrf_exempt
      def my_view(request):
          # CSRF 검사가 비활성화된 뷰 로직
          return HttpResponse("CSRF 보호가 없습니다.")

실습 2

  • like 모델 만들기 / 마이그레이션 / prefetch 추가
  • 커스텀 템플릿 적용 및 csrf_exempt 사용
  • 좋아요 및 취소도 가능

유저 상세 페이지 만들기

slug

  • slug_field = 'nickname'
    • 슬러그는 URL에서 특정 객체를 식별하는 데 사용되는 문자열
    • URL에서 사용하는 슬러그 필드가 User 모델의 nickname 필드임을 지정
      • 이 경우 사용자의 닉네임이 슬러그로 사용됨
  • slug_url_kwarg = 'slug'
    • URL에서 슬러그 값을 가져오기 위해 사용하는 키워드 인수를 지정
    • ex. URL 패턴에서 <slug:slug>와 같이 정의된 부분이 있다면,
      • 이 슬러그 값이 nickname 필드와 매칭
  • URL 매칭
    • 사용자가 /profile/johndoe/와 같은 URL을 방문하면, slug가 johndoe로 전달됨
      • 이 슬러그는 nickname 필드와 매칭되어 해당 사용자를 찾음

실습 1

  • slug_field = 'nickname' / slug_url_kwarg = 'slug' 입력하지 않으면,

    • pk로 가져옴 pk로 가져오면 url에 nickname를 추가하는 행동 불가
    • nickname로 가져오기 위해서 사용 즉, url을 숫자가 아닌 텍스트로 받기 위함?
      • slug_field = 'nickname': 어떤 컬럼에서 받을지 지정 (unique 필요)
      • slug_url_kwarg = 'slug' : url에서 받음
  • 속도를 높이기 위해서 prefetch_related 사용

  • detail페이지 디자인


팔로우 모델, 기능 만들기

실습 1

  • 나를 팔로우 하는 사람 : 팔로워
    • 내가 팔로우 하는 사람 : 팔로잉
      • User:User = ManyToMany = N:M
  • symmetrical
    • True : A가 친구를 가지게 될 때, B도 친구를 가지게 된다 (A <=> B)
    • False : 한쪽만 일방적인 관계 = 비대칭 (A => B)
  • through_fields=('from_user','to_user') : 내가 팔로우 하고 있는 목록 조회 가능
    • from_user : 나
    • to_user : 내가 참조할 유저
  • 링크 연결
    • 사용자의 이름을 누르면 상세페이지로 가도록 변경
    • 이름이 파란색이 되서 색을 검정색으로 고정 (링크효과는 그대로 유지)

django.contrib.humanize

  • Django의 내장 앱 중 하나, 템플릿에서 숫자, 날짜 등을 보다 인간친화적인 형식으로 표시하는 데 사용

    • 날짜를 "어제"와 같은 형식으로 표시 / 큰 숫자를 천 단위로 쉼표를 넣어 표시 등의 기능 쉽게 구현 가능
  • 사용방법

      1. INSTALLED_APPS에 'django.contrib.humanize'를 추가하여 활성화
      • INSTALLED_APPS = ['django.contrib.humanize', ]
      1. 템플릿에서 humanize 필터를 사용하기 전에 {% load humanize %} 태그를 추가해야 함
      • {% load humanize %}
      1. 사용 가능한 필터
      • intcomma: 숫자에 천 단위로 쉼표를 추가
        • {{ 1234567|intcomma }} <!-- 출력: 1,234,567 -->
      • naturaltime: 시간을 인간 친화적으로 표시
        • {{ some_date|naturaltime }} <!-- 출력: 2 days ago -->
      • ordinal: 숫자를 서수로 변환
        • {{ 3|ordinal }} <!-- 출력: 3rd -->
      • apnumber: 1에서 9까지의 숫자를 영어 단어로 변환
        • {{ 3|apnumber }} <!-- 출력: three -->
      • intword: 큰 숫자를 "Million", "Billion" 등의 단위로 축약하여 표시
        • {{ 1000000|intword }} <!-- 출력: 1 million -->

실습 2

  • 게시글이 1000개를 넘지않아 변화는 없지만 1000개 넘으면 1,000됨

  • 만약 이미 팔로우가 되어 있다면, 팔로우 취소: member/models.py의 UserFollowing를 삭제

  • 안되어 있으면 팔로우 시작: member/models.py의 UserFollowing를 생성

  • unique_together = ('to_user', 'from_user')

    • to_user = 1 / from_user = 2 -> ok
    • to_user = 1 / from_user = 2 한번더 만들면 -> 오류 발생
  • follow 되어 있으면 unfollow나오게 함


새롭게 알게된 내용

  • 주변 테두리 지우기

  • through=UserFollowing 를 사용할 때 UserFollowing이 빨간줄이 그어진다
    • 이유: UserFollowing가 너무 밑에 있어서 그렇다고 UserFollowing를 위로올리면
      • UserFollowing의 User을 읽지 못한다.
    • 해결: UserFollowing를 ''로 묶는다.


어려운 내용(추가 학습 필요)

  • like
    • 커스텀 템플릿

오늘 발생한 문제(발생 했다면)

———————————————————————

profile
안녕하세요.

0개의 댓글