본문 바로가기

회고록(TIL&WIL)

WIL 2022.06.20 DRF/ venv환경 구성, 모델링옵션, REST API, POSTMAN, ORM

DRF(Django Rest Framework)

환경 구성

Python, VSCode, Postman, django-rest-framework

$ python -m venv venv    # venv 현재 경로에 설치(프로젝트 폴더 생성 후 해야함)

$ venv\Scripts\activate  # 입력 시 (venv)c: ... > 형태로 바뀜

$ pip install django

$ pip install djangorestframework

requierments.txt 패키지 관리

$ pip freeze > requirements.txt  # 현재 패키지들 텍스트 파일로 저장(패키지 추가할때마다 해줘야함)

$ pip install -r requirements.txt # 텍스트 파일에 저장된 패키지들 install

프로젝트 구조 생성

$ django-admin startproject DRF_study

$ python manage.py startapp user

기본 세팅 - INSTALLED_APP 추가 작성, REST_FRAMEWORK 복붙

# settings.py
INSTALLED_APP = [
    ...,
    'rest_framework',
    'user',
]

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [ # 기본적인 view 접근 권한 지정
        'rest_framework.permissions.AllowAny'
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [ # session 혹은 token을 인증 할 클래스 설정
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication'
    ],
    'DEFAULT_PARSER_CLASSES': [ # request.data 속성에 액세스 할 때 사용되는 파서 지정
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ]
}

DB 모델링 **OPTIONS

  • fk에서 사용되는 on_delete에는 여러 속성들이 있으며, 상황에 맞게 사용해야 한다.
    • CASCADE : FK로 참조하는 레코드가 삭제 될 경우 해당 레코드를 삭제한다.
    • SET_NULL : FK 필드의 값을 Null로 변경해준다. null=True가 정의되어 있어야 사용 가능하다.
    • PROTECT : 해당 레코드가 삭제되지 않도록 보호해준다.
    • SET_DEFAULT : FK 필드의 값을 default로 변경해준다. default=””가 정의되어 있어야 사용 가능하다.
    • SET() : FK 필드의 값을 SET에 설정된 함수를 통해 원하는 값으로 변경할 수 있다.
    • DO_NOTHING : 아무런 동작을 하지 않는다. 참조 관계의 무결성이 손상될 수 있기 때문에 권장하지 않는다.
  • DateField와 DateTimeField는 default 값을 여러 형태로 지정할 수 있다.
    • default = $date : 지정한 값을 기본 값으로 설정한다.
    • auto_now_add = True : 레코드가 생성될 때의 date를 기준으로 값을 지정한다.
    • auto_now = True : 레코드가 save()될 때마다 갱신된다.

REST API

-> 두 컴퓨터 시스템이 인터넷을 통해 정보를 안전하게 교환하기 위해 사용하는 인터페이스입니다.

http method 종류 - get, post, put, delete

FBV : Function Base View

# user/views.py
def user_view(request):
    if request.method == "GET":
    ...

CBV : Class Base View -

반드시 첫째줄에 있는 APIView를 import 받아와야한다!

클래스 생성 시 APIView상속받아 클래스를 만들면 get, post, put, delete 메서드가 정의 되어있어

해당 메서드를 오버라이딩해서 사용해야 http method 요청에따라 코드를 실행 할 수 있도록 할 수 있다.

# user/views.py
from rest_framework.view import APIView
from rest_framework import permissions

class UserView(APIView):
    permission_classes = [permissions.AllowAny] # 누구나 view 조회 가능
    def get(self, request):
        return Response({'message': 'get method!!'})
        
    def post(self, request):
        return Response({'message': 'post method!!'})

    def put(self, request):
        return Response({'message': 'put method!!'})

    def delete(self, request):
        return Response({'message': 'delete method!!'})

POSTMAN

 

collection 을 만들고 각각의 요청들을 생성 및 저장해두고 여러가지 설정 하여 요청을 보내보며 테스트 가능함

요청 보낼 http mehtod 지정 후 보낼 url 그리고 Body에 raw > JSON 데이터로 작성해서 Send 눌리면 Request 보내짐

이대로 보내게되면 django CSRF_middleware에서 걸린다

csrf_token 에러 발생시 Test 부분에 아래 코드 추가하고 Headers에 X-CSRFToken 직접 적어서 보내주면된다.

var xsrfCookie = postman.getResponseCookie("csrftoken");
postman.setGlobalVariable('csrftoken', xsrfCookie.value);


자주 사용 되는 ORM

objects.get은 1개의 object만 리턴되기때문에 없을 경우 DoesNotExist Exception이 발생되고

여러개면 MultipleObjectsReturned Exception이 발생된다!

# objects.get에서 객체가 존재하지 않을 경우 DoesNotExist Exception 발생
# objects.get에서 결과 값이 여러개의 객체를 가져 올 경우 MultipleObjectsReturned Exception 발생
try:
    Model.objects.get(id=obj_id)
except Model.DoesNotExist:
    # some event
    return Response("존재하지 않는 오브젝트입니다.")
except MultipleObjectsReturned:
    # some event
    return Response("여러개의 오브젝트가 리턴되었습니다.")

order_by(기준이 되는 레코드) 기본 오름차순

Model.objects.all().order_by("join_date") 

# -join_date처럼 "-"를 붙이면 역순으로 정렬(내림차순)
Model.objects.all().order_by("-join_date")

# .order_by("?")사용시 무작위 셔플
Model.objects.all().order_by("?")

여러가지 값 추출 방법

# queryset에서 첫번째 object를 가져옴. all()[0]과 동일
Model.objects.all().first()

# queryset에서 해당하는 값만 빼서 가져옴
Model.objects.all().exclude(user=user)

# 지정된 행의 레코드 값이 중복 될 경우 제거
result = Model.objects.filter(user=user).values('취미').distinct()

# queryset으로 object를 return하는게 아닌 list안의 dict 형태로 return
Model.objects.filter(user=user).values()

# 값들을 리스트하나에 담아 return flat을 줄 경우 하나에 다 담음
Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>


# Foriegn key관계, OneToOne 관계들 끼리에서 DB 성능 상승을 위해 사용하면 좋은 코드
class City: ...
class Person: hometown = ForeignKey(City,...
class Book: author = ForeignKey(Person,...
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.


# ManyToMany 관계들 끼리에서 DB 성능 상승을 위해 사용하면 좋은 코드
>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
이것의 문제는 요청할 때마다 Pizza.__str__()에서 self.toppings.all()데이터베이스를 쿼리해야 하므로
Pizza 의 모든Pizza.objects.all() 항목에 대해 Toppings 테이블에서 쿼리를 실행한다는 것입니다.

다음 을 사용하여 쿼리를 2개로 줄일 수 있습니다 prefetch_related.
>>> Pizza.objects.all().prefetch_related('toppings')


# 입력한 object가 존재 할 경우 해당 object를 가져오고, 존재하지 않을 경우 새로 생성
object, created = Model.objects.get_or_create(
    field1="value1",
    field2="value2",
)

if created: 
    # created event
else: 
    # already exist event