웹개발

Django QnA-50 07.31

best_spear_man 2023. 7. 31. 16:16

0-1. Django가 무엇인지 설명하세요.

Django는 python 기반 풀-스택 웹 프레임워크로, '마감기한이 있는 완벽주의자를 위한 웹 프레임워크'이라는 모토를 가진 웹 프레임워크입니다. fully-loaded framework로서 다양한 기능들을 제공하여 빠르게 개발이 가능합니다.

0-2. Django를 백엔드 스택으로 선정한 이유는 무엇입니까?

웹 개발을 입문하는 입장에서 Django와 같이 기본 기능이 다양하게 제공되는 프레임워크를 사용해 기본기를 익히고 빠르게 생산성을 갖출 수 있기 때문입니다.

1. Django에는 어떤 장점이 있습니까?

Django는 파이썬기반 웹 프레임워크이므로 파이썬에서 제공되는 강력한 라이브러리들, 특히 데이터처리나 시각화를 위한 라이브러리를 사용하여 서비스 개발 가능합니다.

또한 fully loaded 한 프레임워크로서 웹개발에 필요한 다양한 도구들 -관리자페이지, 메일 보내기, form, 사용자 인증 등- 을 내장하여 직접 커스텀 할 필요 없이 라이브러리를 통해 개발하여 개발속도와 생산성에서 장점이 있습니다.

또한 이렇게 미리 제공된 기능들이 보안성을 유지하도록 제공되므로 비교적 쉽게 보안조치가 가능합니다.

MVT Pattern을 사용하여 코드 가독성을 높이고 유지보수가 용이합니다.
강력한 ORM 기능이 제공되며

많은 사용자 수와 방대한 커뮤니티를 가집니다.

2. Django가 다른 Python 웹 프레임워크와 비교되는 특징이 있다면 무엇입니까?

Flask나 fastAPI와 달리 Django는 fully loaded한 full-stack web framework입니다. 필수적인 기능만 가지는 flask와 달리 Django는 다양한 기능들이 사전에 제공되어 이를 활용하여 비교적 쉽고 빠르게 실제 동작하는 서비스를 만들 수 있습니다. 예를들어 Django는 관리자 권한을 가진 사용자가 데이터와 사용자 정보를 편리하게 다룰 수 있는 admin page 기능이 기본적으로 제공됩니다.

하나의 프로젝트에 하나의 application만 가지는 flask와 달리 하나의 프로젝트의 여러개의 application을 만들수 있으며 또한 Django는 ORM이 자체적으로 지원되어 관계형 DB를 쉽게 사용할 수 있습니다.

비교적 최근 프레임워크인 fastAPI 등 보다 더 다양한 서드파티 라이브러리들이 제공됩니다.

필요에 따라 Django Template Language를 이용해, 파이썬 문법에 따라 직접 클라이언트측에 보여줄 템플릿(HTML)을 렌더링 할 수 있습니다.

3. Django Template Engine은 무엇이고 어떤 기능을 제공합니까?

템플릿 엔진은 템플릿 양식과 데이터에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어 또는 소프트웨어 구성요소를 말합니다.

Django Template Engine은 백엔드에서 제공한 데이터를 프론트에서 효율적으로 사용할 수 있도록 django에서 기본적으로 지원하는 템플릿 엔진입니다.

django template language를 사용하여 template(html파일)을 마치 파이썬을 사용하는 것처럼 for문이나 if문 등을 사용하여 렌더링 할 수 있게 하며 함수 사용, 주석 사용,csrf token 추가 등등 다양한 기능을 제공합니다.

4. Django를 통해 CRUD를 구현하는 방법에 대해서 HTTP Method와 함께 설명하시오

Django는 MVT구조를 지닙니다. Model은 데이터 정의, Views는 요청 처리, Template는 사용자에게 보여지는 템플릿을 처리합니다.

따라서 CRUD를 구현하기 위해서는 URL에서 API url을 지정하고 여기에 View를 연결하여 view에서 model을 불러와 처리하고 저장하는 로직을 실행해야합니다.

이때 view는 함수 기반(FBV)으로 작성되거나, 클래스 기반(CBV)으로 작성될 수 있습니다. CBV는 상속과 재사용이 많이 필요할 경우 사용하는 것이 좋으며, FBV는 이미 정의된 범용적인 클래스기반 뷰를 이용해 작성하기 어렵거나 비교적 단순하고 작은 프로젝트일때 사용합니다.

from django.views.generic import View

# 함수 기반 뷰의 기본 형태 (FBV)
def dumb_view(request):
    if request.method =="GET":  # http method에 따라 if문으로 구분
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('FBV_GET')
    elif request.method == "POST":
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('FBV_POST')

# 클래스 기반 뷰의 기본 형태 (CBV)
class DumbView(View):
    def get(self, request, *args, **kwargs): # 각 html 메소드 마다 메소드 필요
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('CBV_GET')
    def post(self, request, *args, **kwargs):
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('CBV_POST')

http method는 클라이언트와 서버 사이에 이루어지는 요청과 응답 데이터를 전송하는 방식을 지정합니다.

서버가 수행해야 할 동작을 지정하는 요청을 보내는 방법입니다.

이를 이용하면 같은 API url을 이용하면서도 method에 따라 CRUD 동작 중 여러개를 수행할 수 있습니다.

일반적으로 새 데이터를 생성할때는 POST, 조회할 때는 GET, 수정할때는 PUT(완전한 데이터를 받아 수정) 혹은 PATCH(일부 필드값만 받아서 수정), 삭제할 때는 DELETE를 사용합니다.

목록 조회(R)와 새 데이터 생성(C)에는 데이터를 구분할 id가 필요없으므로 다음과 같은 url을 사용할 수 있습니다.

/api/collection/

개별 조회(R), 수정(U), 삭제(D)는 데이터를 구분할 id가 필요하므로 다음과 같은 url을 사용할 수 있습니다.

/api/collection/<int:collection_id>/

목록 조회(R)시에는 다음과 같이 model을 통해 데이터를 불러올 수 있습니다.

collections=CollectionModel.objects.all()

개별 조회(R), 수정(U), 삭제(D)시에는 다음과 같이 model을 통해 데이터를 불러올 수 있습니다.

def collectionDetailView(request,collection_id):
    try:
        collections=CollectionModel.objects.get(id=collection_id)
    except:
        return HttpResponse(status=404)

새 데이터 생성(C)을 할 때는 다음과 같이 model을 통해 저장할 수 있습니다.

collection=CollectionModel.objects.create(name = "collection1")
collection.color= "RED"
collection.save()

전체 예시:

# collection/models.py
from django.db import models

class Collection(models.Model):
    COLORS=(("BLU","Blue"),("RED","Red"),("BLK","Black"))
    name = models.CharField(max_length=100)
    color = models.CharField(choices=COLORS,max_length=3)
# collection/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('collection/', views.collection_view, name='item'),
    path('collection/<int:collection_id>/', views.collection_detail_view, name='item_detail'),
]
# collection/views.py
from django.http import JsonResponse
from .models import Collection

def collection_view(request):
    if request.method == 'GET':
        collections = Collection.objects.all()
        return JsonResponse({'collections': list(collections.values())}, safe=False)
    elif request.method == 'POST':
        data = request.POST
        collection = Collection.objects.create(
            name=data['name'],
            color=data['color']
        )
        return JsonResponse(status=201)

def collection_detail_view(request, collection_id):
    try:
        collection=CollectionModel.objects.get(id=collection_id)
    except:
        return JsonResponse(status=404)
    if request.method == 'GET':
        return JsonResponse({'collection': model_to_dict(collection)},status=200)
    elif request.method == 'PUT':
        data = request.POST
        collection.name = data['name']
        collection.color = data['color']
        collection.save()
        return JsonResponse(status=200)
    elif request.method == 'DELETE':
        collection.delete()
        return JsonResponse(status=204)

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

FK: 일대다(one to many) 관계를 나타냅니다. 예를 들어 작성자와 게시글의 관계와 같습니다. 작성자는 0~N개의 게시글을 가질 수 있으나 게시글은 단 하나의 작성자만 가집니다. 참조는 하나의 레코드(객체)를 반환합니다. 역참조는 QuerySet을 반환합니다.

class User(AbstractUser):
    """사용자 모델"""
    email = models.EmailField(
        max_length=255,
        unique=True,
    )
    username = models.CharField(
        max_length=23,
        unique=True,
    )
    password = models.CharField(max_length=256)


class Article(models.Model):

    """게시글 모델"""
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
    )

ForeignKey는 최소 두 가지 인자를 필요로 합니다. 첫 번째는 관계를 맺을 다른 모델 클래스, 두 번째는 연결된 객체가 삭제될 때의 동작을 정의합니다(on_delete).

식별관계와 비식별 관계로 나뉘며 비식별관계는 부모데이터가 없어도 데이터가 성립할 수 있습니다.

OneToOne: 일대일관계를 나타냅니다. 예를 들어 식당과 매장위치의 관계와 같습니다. 하나의 매장위치엔 하나의 식당만이 존재하고 마찬가지로 식당도 하나의 매장위치만 가집니다. 참조는 하나의 레코드(객체)를 반환합니다. 역참조는 하나의 레코드(객체)를 반환합니다.

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

    def __str__(self):
        return f"{self.name} the place"


class Restaurant(models.Model):
    place = models.OneToOneField(
        Place,
        on_delete=models.CASCADE
    )

일대일 관계를 나타내는 것 이외엔 ForeignKey와 유사합니다.

ManyToMany: 다대다 관계를 나타냅니다. 예를 들어 피자메뉴와 토핑종류의 관계와 같습니다. 피자는 여러가지 토핑을 올릴 수 있고 토핑도 여러가지 피자에 올라갈 수 있습니다. 참조는 QuerySet을 반환합니다. 역참조는 QuerySet을 반환합니다.

class Topping(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()


class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(
        Topping,related_name="pizza"
    )

위 두 경우와 달리 별도의 연결 테이블을 사용하여 두 모델 사이의 관계를 저장합니다. 두 테이블 사이에 각 테이블과 일대다 관계로 연결된 중간테이블을 형성하여 표현됩니다.

셋 모두 related_name을 지정하여 역참조를 할 수 있습니다.(미지정시 클래스이름(소문자)_set)

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

1. ManyToManyField 이용하기
class Topping(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()


class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(
        Topping,related_name="pizza"
    )

위와 같이 정의하면 자동적으로 중간테이블을 형성하여 다대다관계를 만들 수 있습니다.

2. 중개테이블 직접 정의하여 이용하기
class Topping(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()


class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings=models.ManyToManyField(
        Topping,
        related_name="pizza",
        through="PizzaTopping",
        through_fields=("pizza", "topping"), # (소스모델-pizza, 타겟모델-topping) 순서로 명시해준다
    )

class PizzaTopping(models.Model):
    pizza=models.ForeignKey(Pizza, on_delete=models.CASCADE, relatedname="toppings")
    topping=models.ForeignKey(Topping, on_delete=models.CASCADE, relatedname="pizzas")
    reason_of_use=models.CharField(max_length=30)

through 인자를 사용하여 직접 중간테이블을 만들고 지정할 수 있습니다. 이 방식은 중간테이블에 새로운 필드를 지정하여 추가적인 기능을 만들 수 있습니다.
이때 중개테이블에 다대다 관계를 위한 ForeignKey 이외에 소스모델이나 타겟모델의 다른 ForeignKey가 존재할 경우(예시: 그룹-사용자,초대자) through_fields를 지정하여야합니다.

둘 모두 공통적으로 add와 remove를 이용하여 관리할 수 있습니다.

if request.user in article.like.all():
    article.like.remove(request.user)
else:
    article.like.add(request.user)
article.save()

through를 사용할 경우 add 등의 동작에 through_defaults를 지정하여 추가된 필드들의 값을 지정한다.

potato_pizza=Pizza.objects.create(name="포테토피자")
potato=Topping.objects.create(name="감자",description="맛있다.")
potato_pizza.toppings.add(potato, through_defaults={'reason_of_use': '감자피자에 감자를 안넣으면 뭘 넣게?'})

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

Django의 MVT 패턴에서 View는 요청에 대한 동작을 처리하는 부분으로, 이 view를 함수기반(function-based)으로 작성하느냐, 클래스기반(class-based)으로 작성하느냐에 따라 FBV, CBV라고 부릅니다.

from django.views.generic import View

# 함수 기반 뷰의 기본 형태 (FBV)
def dumb_view(request):
    if request.method =="GET":  # http method에 따라 if문으로 구분
        # 프레젠테이션 로직 시작
        # ...
        return HttpResponse('FBV_GET')
    elif request.method == "POST":
        # 프레젠테이션 로직 시작
        # ...
        return HttpResponse('FBV_POST')

# 클래스 기반 뷰의 기본 형태 (CBV)
class DumbView(View):
    def get(self, request, *args, **kwargs): # 각 html 메소드 마다 메소드 필요
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('CBV_GET')
    def post(self, request, *args, **kwargs):
        # 비즈니스 로직 시작
        # ...
        return HttpResponse('CBV_POST')

FBV는 method의 구분을 if문 등으로 처리해야하지만, CBVsms 각 html method 마다 클래스 내부에 python method를 지정해주면 됩니다.

  • CBV는 재사용성과 확장성이 좋고 generic view를 상속해서 사용하면 다양한 view를 빠르고 손쉽게 만들 수 있습니다. 클래스이므로 다중상속이 가능하여 MixIn(여러 클래스 메서드 재사용을 하기 위해 인스턴스 속성을 정의하지 않고 __init__ 생성자를 호출할 필요가 없는, 추가적인 메소드만 정의하는 작은 클래스)패턴등을 사용할 수도 있습니다. 다만, 복잡한 상속관계로 인해 코드를 알아보기 어려워질 수 도 있습니다.
  • FBV는 작성하기도 편하고 읽기에도 어렵지 않습니다. 그러나 재사용성이 CBV에 비해 좋지 않습니다.

CBV는 상속과 재사용이 많이 필요할 경우 사용하는 것이 좋으며, FBV는 이미 정의된 범용적인 클래스기반 뷰를 이용해 작성하기 어렵거나 비교적 단순하고 작은 프로젝트일때 사용할 수 있습니다.

프로젝트 경험: CBV를 이용하여 django restful framework에서 제공하는 ListAPIView를 이용해 쉽고 빠르게 페이지네이션이 적용된 글 목록 불러오기 view를 만들 수 있었습니다.

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

테스트란, 시험할 소프트웨어에 테스트 케이스를 주어 실행시킨 후 시스템의 동작이 예상한 대로 실행되는지 확인하는 것입니다. "예상한 대로 실행되는지"에는 예외처리또한 포함됩니다. 따라서 하나의 API에 대해서도 여러개의 테스트케이스를 추가해 반복적으로 테스트를 진행해야할 수 있습니다. 이외에도 여러 코드가 서로의 동작에 영향을 주는 경우, 테스트는 더욱 번거로워지며 휴먼 에러가 발생할 확률이 증가합니다.

그러나 결국 테스트의 내용은 항상 정해져 있을 수 밖에 없으므로, 순서도로 표현할 수 있으며, 이는 코드로 표현될 수 있습니다. 따라서 테스트 코드를 작성하여 테스트를 자동화 하면, 코드의 리팩토링 등을 진행하면서 여러번 테스트를 거칠 일이 있더라도 개발자는 테스트 실행만 하면 되므로 생산성이 크게 증가하고 휴먼 에러를 줄일 수 있습니다.

또한 오류를 빠르게 발견할 수 있으며, 문서화의 역할도 겸할 수 있습니다.

프로젝트 경험: 프로젝트 초기에 회원가입등의 api를 테스트 하기위한 테스트코드를 먼저 작성하고 api개발을 진행하여 원활하고 빠르게 개발이 가능했습니다.

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

unittest에서 TestCase클래스의 메소드인 setup은, 각 test method가 시작 될 때 마다 실행되며, instance method입니다. setupclass는 해당 TestCase 객체가 생성될 때 단 한 번 실행되며, class method입니다.

프로젝트 경험: 사용자 인증관련 기능에 대한 test code를 작성할 때, db에 데이터를 저장하는 회원가입이 선행되어야 하는 경우, setupclass(setUpTestData)로 회원가입을 재연하였습니다.

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

CSRF란, Cross Site Request Forgery의 약자로, 한글 뜻으로는 사이트간 요청 위조를 뜻합니다.

CSRF는 웹 보안 취약점의 일종이며, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등) 을 특정 웹사이트에 요청하게 하는 공격입니다.

CSRF 공격이 성립하기 위해선 다음의 조건이 필요합니다.

  1. 사용자는 보안이 취약한 서버로부터 이미 로그인되어 있는 상태
  2. 쿠키 기반의 서버 세션 정보를 획득할 수 있음
  3. 공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있음

위 조건이 만족 된 경우, 서버에 로그인(세션인증방식) 되어있는 사용자가 피싱 사이트를 이용하여 사용자의 권한으로 사용자가 의도하지 않은 요청이 서버로 전송될 수 있습니다.

Template Engine을 사용할 때, 발생하는 CSRF Error는 CSRF 방어 기능 때문입니다. 템플릿을 사용할 때, 올바르게 CSRF 토큰을 포함하지 않은 폼을 제출하면 해당 오류가 발생하게 됩니다.

해결방법은 다음과 같습니다.

  1. {% csrf_token %} 템플릿 태그 사용: Django 템플릿 폼을 사용하는 곳에서 반드시 CSRF 토큰을 포함해야 합니다. 폼 내부에 {% csrf_token %} 템플릿 태그를 추가하여 CSRF 토큰이 자동으로 삽입되도록 합니다.
  2. <form method="post"> {% csrf_token %} ... </form>
  3. @csrf_exempt 데코레이터 사용(주의): CSRF 토큰 검증을 생략하고 싶은 특정 뷰에 @csrf_exempt 데코레이터를 사용할 수 있습니다. 이 방법은 보안에 취약하므로 신중하게 사용해야 합니다.

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

queryset은 Database에서 전달받은 객체들의 모음(list)으로,DB 참조 결과 여러행의 데이터를 조회할 때 반환됩니다. 즉 다대다 관계의 참조나 외래키관계의 역참조시에도 queryset이 반환됩니다.

object는 하나의 행(데이터)를 조회할 때 반환됩니다.

<모델명>.objects.filter() 혹은 <모델명>.objects.all() 등의 결과로 queryset이 반환되며, <모델명>.objects.get()의 결과로 object가 반환되거나 에러가 발생합니다.

쿼리셋은 lazy loading 특성을 지녀, 내부의 object 값을 실제로 필요로 하기 전까지 DB에 쿼리를 실행하지 않는다는 특성을 가지고 있습니다.

다음과 같은 경우 ORM이 실제 DB에 쿼리를 보냅니다.

  1. 슬라이싱(Slicing)
  2. Pickling/Caching
  3. __repr__()
  4. len()
  5. list()
  6. bool()
  7. 실제 값 사용

쿼리셋은 또한 chaining method를 통해 여러 메소드를 중첩해 복잡한 쿼리문을 만들어 사용 가능합니다.

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

아래와 같은 모델이 존재할 때

class Person(models.Model)
    name = models.CharField(max_length=10)

class Car(models.Model)
    owner = models.ForeignKey(Person,on_delete=models.CASCADE)
    name = models.CharField(max_length=20)    

사람과 차는 1:N 관계이며 차는 Person을 인자로 가지는 ForeignKey를 속성으로 가집니다. 이때 Car -> Person으로 참조하는 것을 정참조, 반대의 경우를 역참조 라고합니다.

car = Car.objects.get(pk=1)

car.owner.name

정참조의 경우는 위의 코드처럼 아주 간단하게 속성값을 참조함으로서 참조 할 수 있습니다.

역참조는 Foreign Key, ManyToManyField등의 속성이 없는 객체에서 관계된 모델을 참조하는 경우를 말합니다.

person = Person.objects.get(name='홍길동')

person.car.name # 불가능
person_car = person.car_set.all()

위의 코드처럼 set manager(모델 클래스명(소문자)_set)를 사용하여 참조하는 방법이 있고

class Person(models.Model)
    name = models.CharField(max_length=10)

class Car(models.Model)
    owner = models.ForeignKey(Person,on_delete=models.CASCADE,related_name='cars')
    name = models.CharField(max_length=20)    
person = Person.objects.get(name='홍길동')
person_cars = person.cars.all()

Foreign Key 속성에 related_name을 인자로 지정해주면 related_name을 이용하여 역참조를 할 수 있습니다.
여러 속성에서 같은 모델을 Foriegn Key로 가지고 있을 경우 set manager를 이용해 역참조할 때에 어떤 속성에 대한 참조인지 찾을 수 없는 에러가 발생하므로 related_name 설정을 통해 각 필드의 이름을 구분하여 참조할 수 있도록 합니다.

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

response body에 요청에 대한 상세한 응답 내용을 보내지 않고도 클라이언트가 요청에 대한 응답상태를 알게하기 위함입니다. 상태 코드를 같이 보냄으로써, 요청이 정상처리되었는지, 오류가 있는지 클라이언트가 알 수 있게됩니다. 또한 프론트엔드 엔지니어는 상태 코드에 따라 분기를 나눌 수 있습니다. body에 구체적인 결과를 message로 실어 보낼 경우, 보안 문제가 발생할 수 있습니다.

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

실제로 레코드를 삭제하면, 나중에 그 데이터에 접근할 수 없게 됩니다. 삭제하지 않고 is_active와 같은 상태를 설정하여 데이터의 조회, 사용, 로그인만 제한해두는 방식으로 삭제를 구현하면, 추후에 삭제한 데이터를 요구했을 때도 접근이 가능해 안정성을 향상시킬 수 있습니다. 따라서 일정 기한을 정해두고 그 기한이 지나면 실제로 삭제하는 방식으로 구현할 수 있습니다.

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

RESTFUL이란 REST의 원리를 따르는 시스템을 의미합니다.REST란 Representational State Transfer의 줄임말로,자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미합니다.

즉 다음의 조건을 가집니다.

  1. HTTP URI를 통해 자원(Resource)을 명시
  2. HTTP Method(POST, GET, PUT, DELETE, PATCH 등)를 통해 자원(URI)에 대한 CRUD Operation을 적용

REST의 주요한 목표:

  • 구성 요소 상호작용의 규모 확장성
  • 인터페이스의 범용성
  • 구성 요소의 독립적인 배포
  • 중간적 구성요소를 이용해 응답 지연 감소, 보안을 강화, 레거시 시스템을 인캡슐레이션.

REST API의 설계 규칙을 올바르게 지킨 시스템을 RESTful하다 말할 수 있습니다.

REST 아키텍처를 구현하는 웹 서비스를 RESTful 웹 서비스라고 합니다. RESTful API라는 용어는 일반적으로 RESTful 웹 API를 나타냅니다. 하지만 REST API와 RESTful API라는 용어는 같은 의미로 사용할 수 있습니다.

REST 아키텍쳐의 원칙으로는 다음과 같은 것들이 있습니다.

균일한 인터페이스

서버가 표준 형식으로 정보를 전송함을 나타냅니다. 형식이 지정된 리소스를 REST에서 표현이라고 부릅니다. 이 형식은 서버 애플리케이션에 있는 리소스의 내부 표현과 다를 수 있습니다. 예를 들어, 서버는 데이터를 텍스트로 저장하되, HTML 표현 형식으로 전송할 수 있습니다.

균일한 인터페이스에는 4가지 아키텍처 제약 조건이 있습니다.

  1. 요청은 리소스를 식별해야 합니다. 이를 위해 균일한 리소스 식별자를 사용합니다.
  2. 클라이언트는 원하는 경우 리소스를 수정하거나 삭제하기에 충분한 정보를 리소스 표현에서 가지고 있습니다. 서버는 리소스를 자세히 설명하는 메타데이터를 전송하여 이 조건을 충족합니다.
  3. 클라이언트는 표현을 추가로 처리하는 방법에 대한 정보를 수신합니다. 이를 위해 서버는 클라이언트가 리소스를 적절하게 사용할 수 있는 방법에 대한 메타데이터가 포함된 명확한 메시지를 전송합니다.
  4. 클라이언트는 작업을 완료하는 데 필요한 다른 모든 관련 리소스에 대한 정보를 수신합니다. 이를 위해 서버는 클라이언트가 더 많은 리소스를 동적으로 검색할 수 있도록 표현에 하이퍼링크를 넣어 전송합니다.
무상태

서버가 이전의 모든 요청과 독립적으로 모든 클라이언트 요청을 완료하는 통신 방법을 나타냅니다. 이 REST API 설계 제약 조건은 서버가 매번 요청을 완전히 이해해서 이행할 수 있음을 의미합니다.

계층화 시스템

클라이언트 요청을 이행하기 위해 함께 작동하는 보안, 애플리케이션 및 비즈니스 로직과 같은 여러 계층으로 여러 서버에서 실행되도록 RESTful 웹 서비스를 설계할 수 있습니다. 이러한 계층은 클라이언트에 보이지 않는 상태로 유지됩니다.

캐시 가능성

RESTful 웹 서비스는 서버 응답 시간을 개선하기 위해 클라이언트 또는 중개자에 일부 응답을 저장하는 프로세스인 캐싱을 지원합니다. RESTful 웹 서비스는 캐시 가능 또는 캐시 불가능으로 정의되는 API 응답을 사용하여 캐싱을 제어합니다.

온디맨드 코드

REST 아키텍처 스타일에서 서버는 소프트웨어 프로그래밍 코드를 클라이언트에 전송하여 클라이언트 기능을 일시적으로 확장하거나 사용자 지정할 수 있습니다.

이외의 API 설계 원칙은 다음과 같습니다.

  1. 슬래시 구분자(/ )는 계층 관계를 나타내는데 사용한다.(http://restapi.example.com/animal/cats): URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라져야 한다.
  2. 하이픈(-)은 URI 가독성을 높이는데 사용, 밑줄(_)은 URI에 사용하지 않는다.
  3. URI 경로에 대문자 사용은 피하도록 한다.
  4. 파일확장자는 URI에 포함하지 않는다: REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다.
  5. 리소스 간에는 연관 관계가 있는 경우: /리소스명/리소스 ID/관계가 있는 다른 리소스명

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

RESTful API를 구축하는 것은 HTTP 요청 처리, 응답 구조화, 데이터 직렬화, 인증, 권한 관리 등의 복잡한 작업을 처리해야합니다. DRF는 RESTful API 구축을 더 쉽게하는 강력하고 유연한 도구 상자입니다. DRF를 사용하지 않는 것에 비해 다음과 같은 장점을 지닙니다.

  • 쉬운 직렬화 : DRF는 Django와 ORM 모델과 호환되는 강력한 직렬화 기능인 serializer를 제공합니다. 복잡한 데이터 유형을 Python 데이터 유형으로 변환하여 JSON 또는 XML로 쉽게 렌더링 할 수 있습니다.
  • Browsable API : 개발자는 웹 브라우저에서 API uri로 접속해서 API 작동 방식을 테스트하고 디버그하고 파악하기 쉽습니다.
  • 인증과 권한 : DRF는 토큰 기반 인증, 세션 기반 인증 등 다양한 방법을 기본으로 지원합니다.
  • Throttling과 Versioning : DRF는 요청 제한을 위한 내장된 지원을 제공하여 API 남용이나 과부하를 방지하는 데 유용합니다. 또한 버전 관리를 지원하여 기존 클라이언트를 망가뜨리지 않고 API를 변경할 수 있습니다.
  • 자세한 문서 : DRF는 포괄적이고 명확하며 예시가 친절히 제공되는 좋은 공식 문서가 있습니다.
  • 커뮤니티와 생태계 : 거대한Django 커뮤니티의 혜택을 받습니다.

실제 프로젝트 진행 시, serializer를 이용한 간편한 직렬화와 serializer field를 이용해 같은 데이터도 다양한 형태로 표현하여 응답할 수 있게 만들 수 있었습니다.

17. Serializer를 통해서 JSON형식으로 데이터를 반환하는 이유는 무엇인가요?

JSON이란 경량의 데이터 교환 형식으로 프로그래밍 언어가 아닌, 데이터 포맷입니다.

자바스크립트 (Javascript)에서 객체를 만들 때 사용하는 표현식을 의미하며 Ajax로 서버와 통신하며 데이터를 주고 받을 때 데이터 교환을 쉽게 하기 위해 JSON을 사용합니다.

JSON (JavaScript Object Notation)의 장점은

  1. 내용이 함축적으로 최소한의 정보만을 가지고 있어 XML 에 비해 용량이 줄어들고 그만큼 전송이 빠릅니다.
  2. 언어에 독립적이며, 사용하기가 쉽습니다. JS, python, java등 여러 언어로 구성된 소프트웨어간 통신에 용이합니다.

form과 비교하자면, form은 HTML form 을 생성하는데, Serializer 는 결과물이 json 입니다. 따라서 Django에서 템플릿 엔진을 이용해 프론트 엔드 페이지를 직접 렌더링하지 않을 것이라면, serializer를 이용하여 json 형태의 데이터를 전송하는 것이 좋습니다.

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

Django의 User Model은 username, email, password, 권한, 관리자 여부 등 많은 필드를 기본으로 가지고 있으나 하지만 커스텀에 한계가 있습니다. 또한, 로그인 시 username을 id로 하여 로그인 해야 합니다.

Custom User Model을 사용하면 BaseUserManager등을 이용하여 UserManager를 새로 정의해 커스텀도 자유롭게 할 수 있고, username 필드 외에 다른 필드로 로그인하게끔 변경도 가능합니다.