A ship in harbor is safe, but that is not what ships are built for.

개발일지/기술 면접 대비

2023.01.05 TIL(Django Q&A 정리)

플리피나리 2023. 1. 6. 11:10
반응형

16. Django의 기본 기능을 사용하는 것과 JWT를 사용하여 로그인 기능을 구현하는 것에는 어떤 차이점이 있습니까?

1. Django의 기본 기능을 이용한 로그인

  • 세션 방식
  • 기본 세팅을 통해 내장함수를 이용한 간단한 로그인 구현
  • 논쟁의 여지가 있지만 세션로그인은 쿠키라는 접근 가능한 곳에 저장한다는 점에서 안정성이 떨어짐
  • 이에 대한 대안으로 세션 쿠키에 접근을 차단

 

2. JWT를 이용한 로그인

  • JWT(JSON Web Token)를 이용한 토큰 방식
  • 로컬스토리지에 저장
  • settings.py에 jwt 토큰을 이용한 인증을 하겠다는 설정 필요
REST_FRAMEWORK = {
	'DEFAULT_AUTHENTICATION_CLASSES': (
    	'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}
  • Django에서 제공하는 기본적인 auth에 관련된 내장함수를 이용
  • 특정 url로 들어오는 id, password를 가진 요청을 받아 DB에 일치하는 값이 있다면 jwt 토큰을 생성해 보냄
# simple JWT의 라우터를 위한 urls.py
from rest_framework_simplejwt.views import (
	TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
	path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
  • jwt는 payload에 담을 값들이나 exp_date 같은 세세한 설정은 pyjwt(jwt를 쉽게 생성해줄 수 있는 파이썬 라이브러리)를 통한 설정이나 simple_jwt을 사용해 settings.py에 jwt에 대해 설정
from rest_framework import serializers
from users.models import User

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class UserSerializer(serializers.ModelSerializer):
	...
        
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)

        # Add custom claims
        token['email'] = user.email  # 사용자 이메일을 보이게 할 거임
        # ...

        return token

 

from datetime import timedelta
...

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': False,
    'BLACKLIST_AFTER_ROTATION': False,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

 

17. 데이터 테이블 간의 관계를 나타내는 FK, OneToOne, ManyToMany 필드에 대해서 설명하시오

  • FK 필드 : 해당 필드가 다른 테이블과 관계가 있을 때 다른 테이블의 내용을 불러오고 이용할 수 있다.
  • OnetoOne 필드 : 1:1 대응 관계 테이블로, 한 유저가 하나의 프로필 정보를 같는 관계 등을 뜻한다.
  • ManytoMany 필드 : A모델이 B모델을 여러개 가질 수 있고, B모델도 A모델을 여러개 가질 수 있는 관계 -> 게시글과 태그 관계... 게시글은 여러 태그를 가질 수 있고, 특정 태그도 여러 게시글들에 붙을 수 있다.

 

18. Django에서 ManyToMany필드를 만드는 방법에 대해서 설명하시오

Django에서 model을 생성할 때 필드값에 특정 테이블과 ManytoMany 관계임을 설정한다.

class Actor(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    date_of_birth = models.DateField()

    class Meta:
        db_table = 'actors'

class Movie(models.Model):
    title = models.CharField(max_length=45)
    release_date = models.DateField()
    running_time = models.IntegerField()
    actors = models.ManyToManyField(Actor)

    class Meta:
        db_table = 'movies'

 

19. FBV와 CBV는 각각 무엇이며, 어떤 차이가 있습니까?

  • FBV : 함수 기반 뷰(Function-Base-View)
  • CBV : 클래스 기반 뷰(Class-Base-View)

각각의 살펴보면 다음과 같다.

1) FBV

함수를 사용하는 뷰로 심플하고, 가독성이 좋다. 또한 데코레이터 사용이 명료하다. 하지만 확장 or 재사용이 어렵다는 단점이 있다. 간단한 뷰 로직 코드는 다음과 같다.

# url.py
urlpatterns = [
	path('', views.index, name='index'),
]
# views.py
@api_view(['GET', 'POST'])
def index(request):
	if request.method == 'POST':
    	return HttpResponse("Post method")
    else:
    	return HttpResponse("Get method")

 

2) CBV

클래스를 사용하는 뷰로 상속, Mixin 등 여러가지 객체 관련 기능들을 이용하기 좋다. 또한 확장 or 재사용이 용이하다. HTTP 메서드가 클래스 안에서 나누어 처리가 된다. 단점은 가독성이 떨어지고, 코드 이해를 위해 여러 곳을 보아야 한다는 것이다. 간단한 뷰 로직 코드는 다음과 같다.

# urls.py
urlpatterns = [
	path('', views.IndexView.as_view(), name='index'),
]
# views.py
from django.views import View

class ContactView(View):
	def post(self, request):
    	return HttpResponse("Post method")
    def get(self, request):
    	return HttpResponse("Get method")

 

두 방법 모두 같은 기능을 하는 View이다. 즉, 상속 or 재사용이 많이 필요한 프로젝트의 경우 CBV, 그렇지 않은 경우 FBV를 사용한다.

 

표로 정리하면 다음과 같다.

  장점 단점
FBV
  • 편하게 구현가능
  • 매우 읽기 쉬움
  • 데코레이터 사용이 명료함
  • 확장 / 재사용이 힘듬
CBV
  • 확장에 용의(재사용)
  • 다중 상속 Mixin등 사용 가능
  • HTTP Method가 클래스 안에서 나누어 처리
  • 강력한 Generic Class View 가 있음
  • 읽기 어려움(코드 흐름이 암시적)
  • 상속되고 믹스되면서 코드 이해를 위해 찾아다녀야함
  • 데코레이터 사용시 별로도 import 하거나 Method 생성

 

20. 테스트코드를 작성하는 이유는 무엇이며 어떤 장점이 있습니까?

테스트 코드 : 소프트웨어의 제품/서비스의 품질을 확인하거나 소프트웨어의 버그를 찾을 때 작성하는 코드

테스트 코드를 작성하는 이유 : 제품이 예상하는 대로 동작하는지 확인하기 위해

테스트 코드의 장점

1) 작성한 코드가 의도한 대로 작동하는지 일일이 기능을 실행해보지 않고, 코드 동작으로 빠르게 검증 가능

2) 여러가지 기능에 대한 테스트 코드를 미리 작성해 결함을 사전에 발견 가능

3) CI를 통해 주기적으로 테스트 코드 유효성을 확인해 안정적인 추가 빌드 가능

 

21. 테스트코드에서 setup 함수와 setupclass의 차이는 무엇입니까?

  • setup 함수 : 테스트가 실행될 때마다 호출되며 테스트에 공통 데이터가 아닌 각각 필요한 데이터를 넣을 수 있다는 장점이 있다. -> 테스트 중 내용이 변경될 수 있는 객체를 이곳에서 생성
  • setupclass : 모든 테스트 함수들을 아울러 데이터를 한번만 설정한다. @classmethod라는 데코레이터 함수를 감싸며 메소드 인자로 cls를 넘겨 사용한다. 한꺼번에 테스트에 필요한 데이터들을 정의하고 한 곳에서 관리할 수 있다는 장점이 있다. -> 테스트 method가 실행되면서 수정되거나 변경되지 않을 객체들을 이곳에서 생성

 

22. Template Engine을 사용할 때, 발생하는 CSRF Error가 무엇이고 어떻게 해결합니까?

CSRF Error : 사이트 간 요청 위조(Cross Site Request Forgery) 보안 정책으로 인해 일어난 에러

에러 해결방법

1) settings.py에서 MIDDLEWARE 부분의 csrf 부분을 주석처리하기 -> csrf 유효성 검사를 아예 해제하겠다는 이야기이기 때문에 보안상 찝찝하다...

2) @csrf_exempt 데코레이터를 사용해 views.py에 원하는 view에서 csrf가 적용되지 않도록 한다. -> 마찬가지로 아예 csrf 유효성을 검사하지 않는다는 이야기...

3) post 양식을 사용하는 템플릿에서 <form> 태그 안에 {%csrf_token%} 사용하기 -> Django form 안에 항목으로 추가되어 랜덤으로 토큰키를 생성해 송신 시 그 값을 확인하는 방법

 

CSRF란 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의도와 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하는 공격을 의미하며, 이미 사용자가 접속한 상황에서 요청값을 조작하여 사용자가 원하지 않는 action을 보내는 등 악용되기도 한다. 요청을 받는 서버에서는 이러한 공격을 막기 위해 CSRF Token을 통해 체크하는데, Token값이 없거나 유효하지 않다면 403 Forbidden 응답을 하게 된다. 이때 post 요청에 한해 CsrfViewMiddleware을 통해 확인하게 된다.

 

동작 과정을 정리하면 다음과 같다.

  1. 사용자가 해당 페이지에 접속하면 Django에서 자동으로 csrf_token을 클라이언트로 보내어 cookie에 저장한다.
  2. 사용자가 form을 모두 입력한 후 제출 버튼을 클릭한다.
  3. form과 cookie의 csrf_token을 함께 post로 전송한다.
  4. 유효한 요청이면 요청을 처리하고 유효하지 않거나 검증 오류 시 403 Forbidden Response를 반환한다.

 

23. Django ORM에서 queryset과 object의 차이점에 대해서 설명하시오

  • Queryset(쿼리셋) : DB에서 전달받은 객체(object)들의 모음 -> all, filter, exclude 등을 통해 가져온 값, 리스트처럼 보이지만 리스트가 아니다....(주의할 것)
# 전체 데이터 조회
In : Drink.objects.all()
Out: <QuerySet [<Drink: 나이트로 바닐라 크림>, <Drink: 나이트로 쇼콜라 클라우드>, <Drink: 망고 패션 후르츠 블렌디드>, <Drink: 딸기 요거트 블렌디드>, <Drink: 블랙 티 레모네이드>, <Drink: 쿨라임 피지오>, <Drink: 말차 초콜릿 라떼>, <Drink: 라임패션티>]>

# category_id가 1인 데이터만 조회
In : Drink.objects.filter(category_id=1)
Out: <QuerySet [<Drink: 나이트로 바닐라 크림>, <Drink: 나이트로 쇼콜라 클라우드>]>
  • Object(객체) : 내가 설정한 모델의 클래스 한 단위 -> get, first 등으로 가져온 값
# get은 주로 pk컬럼을 통해 조회, 결과가 2개 이상이면 에러
In : Drink.objects.get(id=1)
Out: <Drink: 나이트로 바닐라 크림>

 

24. Django ORM에서 정참조와 역참조에 대해서 설명하시오

정참조 : 해당 객체가 다른 객체의 ForeignKey를 가지고 있거나 1대1 관계로 있는 상황에서 참조를 하는 경우

역참조 : 다른 객체가 자신을 ForeignKey로 가지고 있거나 N:N 관계인 상황, 해당 객체를 참조하고 있는 다른 객체를 참조하려고 하는 경우

 

개념을 다시 정리하면,

이러한 관계가 있을 때, 영화에서 배우 정보를 참조하는 것이 정참조(이때 영화 모델에서 배우 필드를 외래키로 설정했을 것), 반대로 배우가 출연한 영화 정보를 참조하는 것을 역참조라고 한다.

+ 내용을 검색해보니 select_related와 prefetch_related에 대한 이야기도 함께 나왔는데 나중에 정리해볼 것

 

25. Response 결과와 함께 status code를 반환하는 이유는 무엇입니까?

HTTP Status code란 HTTP 요청이 성공했는지 실패했는지를 서버에서 알려주는 코드를 말한다. response에 어떤 데이터가 담겨있는지, 그리고 어떤 요청에 대한 response인지 프론트에서는 알 방법이 없다. 따라서 양방향 소통(프론트 -> 백, 백 -> 프론트)이 원활하기 위해 status_code 반환이 필요하다. 예를 들어 status code 200 반환을 프론트에서 확인했다면 해당 요청이 성공적으로 완료되었다는 메세지 전달 기능을 하며, 프론트에 다음 작업을 이어 나가도 좋다는 신호의 목적으로 사용된다.

 

26. 회원탈퇴, 게시글 삭제와 같은 기능을 구현할 때 실제 레코드를 삭제합니까? 그렇지 않다면 그 이유는 무엇입니까?

삭제하기 보다 유저의 기능을 정지시킨다. 유저가 활동했던 레코드들이 그 이유가 된다. 웹서비스의 특성상 유저테이블은 다른 테이블과의 연관성이 많기 때문에 유저의 정보를 삭제한다면 연관된 모든 테이블이 삭제되거나 혹은 연관된 부분에서 유저만 빠져서 에러를 일으킬 수도 있기 때문에 유저의 기능을 정지시키는 쪽을 선호한다.

 

27. RESTful API는 무엇을 의미합니까?

REST란 Http 통신에서 특정 자원에 대한 요청을 리소스와 메소드로 표현해 특정한 형태로 응답하는 하나의 아키텍쳐를 말한다. 즉, DB(특정 자원)에 대한 CRUD(메소드 -> POST, GET, PUT, DELETE)를 통해 JSON형식의 데이터를 응답하는 아키텍쳐라는 말이다. 

RESTfult API란 REST 기반으로 서비스 API를 구현한 것으로, REST는 HTTP 표준을 기반으로 구현하므로 HTTP를 지원하는 프로그램 언어로 클라이언트, 서버를 구현할 수 있다. 또한 URI, URL에 직관적인 표현을 담아 어떤 기능을 하는 API인지 유추가 가능하고, 기존의 SOAP 같은 규약보다 자유롭고 비교적 가벼워 많이 사용되고 있다.

+ SOAP : Simple Object Access Protocol로 일반적으로 널리 알려진 HTTP, HTTPS, SMTP 등을 통해 XML 기반의 메시지를 네트워크 상에서 교환하는 프로토콜

 

28. DRF를 사용해 API를 개발할 경우 어떤 장점이 있습니까?

DRF는 기존 장고 기능에 serializer라는 클래스를 더해 데이터를 JSON 형태로 변화시키고 반대로 JSON 형태의 데이터를 클래스 형태로 쉽게 변화시켜 더 쉽고 빠른 개발을 가능하게 한다. 또한 프로젝트 자체가 무거워진다는 단점을 DRF에서 제공하는 다양한 툴을 이용해 더 가볍게 바꾸어 해결할 수 있다.

 

29. Django 와 DRF를 통한 개발의 차이점은 어떤 것이 있습니까?

Django는 서버와 클라이언트에 HTML, CSS, JS를 주고 받는다. 반면 DRF는 서버와 클라이언트 사이에 JSON 형식의 데이터만 상태를 표시하며 주고받는다. 이는 MTV 형태의 단점으로 꼽히는데 모델에서 데이터를 가져오고 그 데이터를 또 template에 보내주는 양방향 통신 역할을 view가 모두 담당하고 있기 때문에 코드의 가독성이 떨어진다. 반면 DRF는 시리얼라이저를 통해 view의 무게를 줄이고, 프론트와 백의 경계를 구분하는데 도움을 줄 수 있다.

 

30. Django User 모델과 DRF Custom User 모델의 차이는 무엇입니까?

기존 Django User 모델도 내가 필요로 하는 필드를 추가할 수 있지만, django에서 지정한 기본적인 필드들이 있기 때문에불필요한 필드가 많을 수 있다. 기존 Django User 모델은 (username, first_name, last_name, email, password, groups, user_permissions, is_staff, is_active, is_superuser, last_login, date_joined) 필드들을 제공한다. 반면 DRF Custom User 모델의 경우 BaseUserManager, AbstractBaseUser 클래스를 상속받아 새롭게 구현이 가능하면 자유도가 높다.

반응형