본문 바로가기

PYTHON

20240422 ~ 20240426 10주차 정리

Python Django REST Framework

보여지는 부분은 처리하지 않고 오직 로직에 집중하는 형태
→ 요청에 대해 처리한 결과 데이터를 응답하는 형태
    
Django REST Framework (DRF)를 이용하는 방법
→ Django에 DRF라고 하는 패키지를 살짝 얹은 것(확장)
    
DRF == RESTful API를 Django로 구축하기 위한 확장 프레임워크

------------------------------

★★★★★<순서>

★ 가상환경 생성
python -m venv venv

★ 가상환경 활성화
(Window) activate 폴더로 이동(cd 명령어) -> 해당 폴더 경로에서 activate 입력

pip install --upgrade pip

pip install django==4.2 (4.2는 2024년 기준 LTS 버전. 각 연도에 맞는 LTS 버전을 입력)

pip install django-extensions (기본 Django Shell 보다 더 많은 기능이 있는 shell plus를 제공)

pip install ipython (기본 Python Shell 에 여러 기능(자동 완성, 색상 강조 등)을 제공)

pip install pillow (이미지 처리를 위한 패키지)

pip install django-seed (DB row 데이터 자동 생성을 위한 패키지)

pip install psycopg2 (django-seed에서 사용하는 패키지)

pip install djangorestframework (DRF(Django Rest Framework) 패키지)

pip freeze > requirements.txt

----- ----- -----
★★★★★ Django Project

django-admin startproject <프로젝트명> -> '프로젝트명' 이름을 가진 폴더를 생성하며 프로젝트 시작
django-admin startproject <프로젝트명> . -> '프로젝트명' 이름으로 현재 폴더에서 프로젝트 시작

프로젝트 폴더로 이동 (manage.py 가 있는 폴더)

-> django-extensions 앱 등록 진행
(앱 등록 시 django 기본 앱 -> Third-party 앱 -> 로컬 앱 순으로 작성)
INSTALLED_APPS = [] -> 여기에 "django_extensions", 추가 (trailing comma 주의)
-> 여기에 "django_seed", 추가 (trailing comma 주의)
-> 여기에 "rest_framework", 추가 (trailing comma 주의)

python manage.py runserver -> 로컬 서버 실행

[주요 사용]
★ settings.py
★ urls.py

----- ----- -----
★★★★★ Django App

프로젝트 > 앱. 프로젝트는 앱을 다수 포함할 수 있음
앱은 하나의 기능 단위를 가지는 모듈
앱은 생성 -> 등록의 과정을 거침

python manage.py startapp <앱 이름> - -> '앱 이름' 이름으로 된 앱 생성

프로젝트 폴더의 settings.py -> INSTALLED_APPS 리스트 안에 앱 이름 작성 -> 앱 등록 완료 (trailing comma 주의)

+ app 폴더 안에 templates 폴더 생성 시 구조를 Templates Namespace를 지켜서 구조를 잡으면 좋다. (<app 이름>/templates/<app 이름>)
자세한 건 Templates Namespace 항목 참고

[주요 사용]
★ models.py
★ views.py
+ urls.py (직접 생성)
+ serializers.py (직접 생성)

☆ 파이참 로컬 앱 import error(빨간 줄) 해결
https://devlog.jwgo.kr/2019/05/30/unresolved-reference-error-in-pycharm/

----- ----- -----

★ URL Dispatcher

★ 트레일링 슬래시(Trailing slash): URL 뒤에 붙는 슬래시

★ Variable Routing
- URL 일부를 변수로 지정하여, 해당 부분에 들어온 값을 view로 넘겨줌
- view에서 변수를 받아서 그 부분에 맞게 처리

path("A/<str:B>", views.func), -> urls.py 에서 다음과 같이 추가
def func(request, B): -> views.py 에서 B를 인자로 받아 수행

★ Multiple Apps

각 앱마다 urls.py 생성 가능
각 앱마다 각 앱 폴더의 views를 import 하여 urlpatterns 작성 가능
프로젝트 폴더의 urls.py에서 각 앱 폴더의 urls.py를 포함하는 과정을 진행하고 싶다면

from django.urls import path, include -> include 추가

urlpatterns = [
    path("/<app 이름>", include("<app 이름>.urls")) -> '/<app 이름>' 형태의 url 패턴이 발견될 경우, 해당 앱의 urls.py에서 처리하도록 넘김
]

각 앱 폴더의 urls.py에서는, 프로젝트 폴더의 urls.py에서 처리한 앞 부분('/<app 이름>')을 제외한 뒷 부분만을 명시하여 처리하도록 함.

(예시)
urlpatterns = [
    path("", views.func1),
    path("<str:username>/", views.func2),
]

★ Naming URL Patterns

- 어떠한 URL을 작성할 때 직접 하드코딩 하지 않고 각각의 URL에 ‘이름’을 붙임
- view와 template에서 특정 경로에 대한 의존성을 제거

urlpatterns = [
    path("", views.func1, name='A'), -> 해당 path를 'A' 라는 이름으로 명명
]

이후 templates 안의 html 파일들에서 "{% url 'A' %}" 형태로 작성하여 해당 url 사용 가능

★★ URL Namespace

서로 다른 앱의 urls.py에서 URL naming을 했는데, 그 name이 서로 같은 경우
template에서 해당 name의 url을 작성하면 어떤 url로 이동하는가?
-> 프로젝트 폴더 안의 settings.py에서 INSTALLED_APPS 에 작성한 앱 중 가장 먼저 작성한 앱의 url로 이동함.

이런 상황을 방지하기 위해
① 서로 다른 url naming을 할 수 있지만
② URL Namespace 를 사용하여 같은 url naming을 사용할 수 있다.

- 사용법
각 앱의 urls.py 에서

app_name = <app name A> -> app_name = <원하는 이름> 형태로 지정. 보통은 app의 이름으로 하는 것이 좋음

각 template 에서

{% url <app name A>:<url_name A> %} -> app_name:url_name 형태로 작성 (ex: articles:write, articles:delete 등)

★ 주의: URL Namespace를 사용할 경우 해당 앱의 template에서 naming된 url로 작성한 모든 부분을 app_name:url_name 형태로 수정해야 함!

----- ----- -----

DB Setting

★ 각 app 폴더 안의 models.py에서 아래와 같이 작성

from django.db import models

class <Table 이름>(models.Model): -> <Table 이름> 의 이름을 가진, models.Model 클래스를 상속받은 자식 클래스 정의
    <Field 이름> = models.<Field 타입>(<Option>=) -> field 명을 <Field 이름>으로 정의, 해당 field의 타입을 <Field 타입>으로 정의, 해당 Field의 옵션을 '<Option>=' 형태의 parameter로 지정

★ models.py에서 작성한 내용을 DB에 반영하는 과정(Migrate)

python manage.py makemigrations -> models.py에서 변경한 내용을 토대로 migration 생성 ★★★★★

python manage.py migrate -> migration 내용을 DB에 반영 ★★★★★

★ 생성일시, 수정일시 내부적으로 자동 데이터 반영

models.py에서

create_dt = models.DateTimeField(auto_now_add=True) -> row가 생성될 때 자동으로 'row가 추가된 일시'로 반영
update_dt = models.DateTimeField(auto_now=True) -> row가 수정될 때 자동으로 'row가 수정된 일시'로 반영

해당 내용으로 migration 생성하려고 할 시
-> 안내 문구 출력됨. (옵션 1: 기존 데이터 행들에 입력한 default 값을 추가함 / 옵션 2: 취소하고 default 값을 models.py에서 설정)
-> 1번 선택 후 문구 출력 -> 엔터를 바로 누르면 현재 시간으로 반영, 그렇지 않고 원하는 시간대를 입력하고 반영할 수도 있음


★ Django Seed: DB row 데이터 자동 생성
Github : https://github.com/Brobin/django-seed

- cmd 창

python manage.py seed <App 이름> --number=<생성할 row 수> -> 해당 앱의 DB Table에 임의의 데이터 생성
ex) python manage.py seed articles --number=30

------------------------------

★ HTTP와 URL 구조

HTTP Message

① 요청(Request)
- 클라이언트가 서버로 전달해서 서버의 어떤 행동(action)이 일어나게 하는 것을 의미합니다.

② 응답(Response)
- 요청에 대한 서버의 답변

Http Message의 구조

- 1 line
- 시작(Start Line): 실행되어야할 요청, 요청에 대한 성공 또는 실패
- HTTP Header: 요청에 대한 설명, 본문에 대한 설명
- 빈줄(Blank Line): 메타 정보의 끝을 알림
- HTTP Body: 요청과 관련된 내용, 응답과 관련된 문서

요청(Request) 응답(Response)
Start Line Method, Traget, HTTP Version HTTP Version,  Status Code, Status Message
Headers   요청에 필요한 여러가지 메타 정보 응답에 대한 열가지 메타 정보
Body       요청에 필요한 여러가지 데이터 요청을 처리한 여러가지 데이터

★ HTTP Request Methods

정의: 요청 자원에 대한 행위
https://developer.mozilla.org/ko/docs/Web/HTTP/Methods

★ HTTP Status Code

정의: HTTP 요청에 대해 성공 여부를 나타내는 코드값
https://developer.mozilla.org/ko/docs/Web/HTTP/Status

크게 5개의 그룹으로 분류(etc.: http.cat, http.dog)

1XX : Informational Response

2XX : Successful Response
- 200 OK: 성공. 에러없이 요청이 성공.
- 201 Created: 요청이 성공했고 새로운 데이터가 만들어짐.
- 202 Accepted: 요청은 정상적이나 아직 처리가 완료되지 않음.
- 204 No Content: 요청은 성공적으로 처리했으나 전송할 데이터(Response Body)가 없음.

3XX : Redirection Message

4XX : Client Error Response
- 400 Bad Request: 클라이언트의 요청이 잘못되었음. 서버는 해당 요청을 처리하지 않음.
- 401 Unauthorized: 클라이언트가 인증이 되지 않았거나 인증정보가 유효하지 않음.
- 403 Forbidden: 서버에서 요청을 이해했으나 금지된 요청. 요청에 대한 자원이 있으나 수행할 권한이 없음.
- 404 Not Found: 요청한 자원을 찾을 수 없음.

5XX : Server Error Response
- 500 Internal Server Error: 요청에 대해 서버가 수행하지 못하는 상황. 서버가 동작하지 않는다는 포괄적인 의미가 내포됨.
- 503 Service Unavailable: 서버가 요청을 처리할 준비가 되지 않았음. 서버가 다운되었거나 일시적으로 중단된 상태.


URL

URI (Uniform Resource Identifier)
- 통합 자원 식별자
- 인터넷의 자원을 식별할 수 있는 유일한 문자열
(일반적으로 URN을 사용하는 비중이 낮기때문에 URI와 URL을 같은 의미로 사용)

① URL(Uniform Resource Locator)

- 통합 자원 위치(Location)
- 웹상에 자원이 어디 있는지 나타내기 위한 문자열. 어디에서 어떻게 리소스를 가져와야 하는지 나타내는 문자열  
- 웹 주소, 링크

② URN(Uniform Resource Name)

- 통합 자원 이름(Name)
- 위치에 독립적인 자원을 위한 유일한 이름 역할. 리소스를 특정하는 이름.
- ISBN(국제표준도서번호)


https://www.aidenlim.dev:80/path/to/resource/?key=value#docs

① https://
- Scheme(Protocol)
- 브라우저가 사용하는 프로토콜
- http, https, ftp, file, …
        
② http://www.aidenlim.dev
- Host(Domain name)
- 요청을 처리하는 웹 서버
- IP 주소를 바로 사용할 수 있지만 도메인 이름을 받아서 사용하는 것이 일반적
        
③ :80
- Port
- 리소스에 접근할 때 사용되는 일종의 문(게이트)
- HTTP: 80 / HTTPS: 443이 표준 포트
        
④ /path/to/resource/
- Path
- 웹 서버에서의 리소스 경로
- 웹 초기에는 실제 물리적인 위치를 나타냈으나 현재는 추상화된 형태를 표현
        
⑤ ?key=value
- Query(Identifier)
- 웹 서버에 제공하는 추가적인 변수
- `&`로 구분되는 Key=Value 형태의 데이터
        
⑥ #docs
- Fragment(Anchor)
- 해당 자원 안에서의 특정 위치 (북마크)
- HTML 문서의 특정 부분을 보여주기 위한 방법

------------------------------

RESTful API와 JSON


API (Application Programming Interface): 애플리케이션과 프로그래밍적으로 소통하는 방법

ex)
CLI (Command Line Interface): 명령줄로 소통하는 방법
GUI (Graphic User Interface): 그래픽으로 유저와 소통하는 방법

- 요청뿐만 아니라 응답까지 전체적인 것을 포함한 구조
- '기계 - 인간' 뿐만 아니라 '소프트웨어 - 소프트웨어' 간에도 수많은 소통이 존재함

★ REST (Representational State Transfer)

웹에 대한 소프트웨어 설계 방법론
→ 2000년 로이 필딩의 논문(https://ics.uci.edu/~fielding/pubs/dissertation/top.htm)으로 처음 소개되어 널리 적용

API를 만들기 위한 개념이 아닌 RESTful API로 사용하는 것


★★★ RESTful API

- 애플리케이션간 소통하는 방법에 REST적인 표현을 더한 것. REST 원리를 따라 설계한 API

특징
① 결과를 보지 않고 요청 형식만 보더라도 추론 가능

ex)
POST /articles/ → 새로운 article 생성
GET /articles/ → article 목록 조회
GET /articles/1 → 1번 article 조회
DELETE /articles/1/ → 1번 article 삭제
    
② 핵심 규칙
- 자원: URI로 표현
- 행위: HTTP Method로 표현
- 표현: 자원과 행위를 통해 표현되는 결과물로 일반적으로 JSON 형식, URI는 동사가 아닌 명사의 나열로 사용
ⓐ POST /articles/create/ (X)
ⓑ POST /articles/ (O)
            
- 따르지 않더라도 로직과 동작에는 아무런 이상이 없으나, 이 규칙을 따를 때 얻는 이득이 크다
- 일반적으로 'GET', 'POST', 'PUT', 'DELETE' + 'PATCH'를 사용


★ JSON (JavaScript Object Notation)
- JS 표기법을 따른 일종의 데이터를 담는 형식. XML, CSV, YAML 등의 형식도 있지만 JSON을 일반적으로 사용
- 사람이 읽기 쉽고 프로그래밍으로 파싱(분석)하기 용이

특징
- Key - Value 형식
- '.json' 파일 확장자
- 문자는 쌍따옴표로 묶여야하며 true, false, 숫자 등을 사용할 수 있음

------------------------------

★★ Response와 Serializer


★ Django Seed: DB row 데이터 자동 생성
Github : https://github.com/Brobin/django-seed

- cmd 창

python manage.py seed <App 이름> --number=<생성할 row 수> -> 해당 앱의 DB Table에 임의의 데이터 생성
ex) python manage.py seed articles --number=30

- views.py

from django.http import JsonResponse -> 필요한 모듈 import
from .models import <model A> -> serialize할 앱의 model(DB Table)

rows = <model A>.objects.all() -> 데이터 가져오기
json_res = []

for row in rows:
    json_res.append(
        {
            "<A>": row.<column A>, -> JSON에 담을 row 데이터 지정
            ...
        }
    )

return JsonResponse(json_res, safe=False) -> JsonResponse를 리턴. safe 파라미터 인자 값으로 False
dict 타입이 아닌 객체를 직렬화(Serialization)하기 위해 False로 설정


★ Serialization (직렬화)

정의: 객체 또는 데이터 구조를 저장, 전송을 위해 다른 포맷으로 변경하는 것
데이터의 구조는 유지하면서 추후 재구성이 가능한 포맷으로 변환

- Python 객체 형태인 Queryset 혹은 Model의 Instance를 직렬화를 통해 JSON, XML, YAML 등의 전송 가능한 형태로 변환
- ★ Django도 내부적으로 다른 데이터 포맷으로 쉽게 직렬화 할 수 있는 기능을 제공

- views.py

from django.core import serializers
from django.http import HttpResponse -> 필요한 모듈 import
from .models import <model A> -> serialize할 앱의 model(DB Table)

rows = <model A>.objects.all() -> 데이터 가져오기
json_res_data = serializers.serialize("json", rows) -> JSON으로 보낼 데이터 serialize(직렬화)
return HttpResponse(json_res_data, content_type="application/json") -> HTTP response 형태로 리턴. content_type 파라미터 인자 값으로 "application/json"


Django는 내부적으로 serializer를 제공하지만 모델 구조에 한정된 구조

- 직렬화된 데이터의 구조를 변경하거나 새로운 필드를 구성하는 것에 많은 추가 작업이 필요
- 유연한 API를 위한 기능이라기보다 모델 구조로 저장되어있는 데이터를 export 하는 용도

따라서 모델에 종속적이지 않고 유연하지만 사용하기 편한 Serializer가 필요하다
-> ★ Django Rest Framework

------------------------------

★★ Django REST Framework Setting


★ serializers.py (각 앱마다 생성)

from rest_framework import serializers -> 필요한 모듈 import
from .models import <model A> -> serialize할 앱의 model(DB Table)

class <Serializer A>(serializers.ModelSerializer): -> serializers.ModelSerializer 클래스를 상속받은, <Serializer A> 라는 이름의 class 생성
    class Meta: -> Meta 클래스 override
        model = <model A> -> model 지정
        fields = "__all__" -> ("col A", "col B")와 같은 column을 담은 tuple 형태로 전달해도 되지만, "__all__" 을 통해 모든 column을 전달 
        exclude = ("exclude col A", "exclude col B") -> exclude col A, exclude col B column을 제외한다.

Django의 Form, ModelForm과 유사


views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response -> 필요한 모듈 import. decorator 같은 경우 함수형 view를 사용할 때 반드시 사용
from .serializers import <Serializer A> -> 앱의 ModelSerializer를 상속받은 <Serializer A> 클래스
from .models import <model A> -> serialize할 앱의 model(DB Table)

@api_view(["GET"]) -> 함수형 view 작성시 반드시 해당 데코레이터 사용
def json_drf(request):
    rows = <model A>.objects.all() -> 데이터 가져오기
    serializer = <Serializer A>(rows, many=True) -> serialize
단일 객체(get 또는 get_object_or_404 로 가져온 경우)인 경우 many=False (default) 여도 됨.
    return Response(serializer.data) -> response 리턴


Postman 프로그램

- 개발자가 API를 디자인, 테스트, 문서화, 공유를 할 수 있도록 도와주는 소프트웨어
- API 테스트, 환경 관리, 협업 등을 위한 강력한 기능을 제공하여 보다 효율적인 API 개발 및 테스트 가능

workspace 생성 -> collection 생성 -> request 생성 및 정의 -> 요청을 보낼 주소 입력 후 테스트

------------------------------

DRF Single Model CRUD

① 데이터를 불러온다(조회한다)
② 직렬화(Serialize) 한다
③ 응답(response. JSON) 한다

★ ModelSerializer
- Model의 필드들을 어떻게 직렬화해서 데이터의 포맷을 잡을지가 핵심
- Django Model → ModelForm 사용과 굉장히 유사

★ @api_view()
- 인자가 아무것도 없으면 HTTP 요청 중 'GET' method 만 허용, 이외 요청일경우 '405: Method Not Allowed' 에러 출력
- DRF의 함수형 뷰(FBV)인 경우 필수적으로 작성


★ views.py

from django.shortcuts import get_list_or_404, get_object_or_404

from rest_framework import status -> 상태코드 상수
from rest_framework.decorators import api_view -> 데코레이터
from rest_framework.response import Response -> Response return 위해 필요한 모듈

from .models import <Model A> -> 사용할 모델(DB Table)
from .serializers import <Serializer A> -> 사용할 Custom ModelSerializer


@api_view(["GET", "POST"]) -> 함수형 view 이므로 decorator 필수 작성
def row_list(request):

    # 게시글 목록 조회
    if request.method == "GET": -> method에 따른 분기 처리
        rows = get_list_or_404(<Model A>, is_visible=True) -> row 여러개인 경우
        serializer = <Serializer A>(rows, many=True) -> many=True
        return Response(serializer.data)

    # 게시글 작성
    elif request.method == "POST":
        serializer = <Serializer A>(data=request.data) -> request에 담긴 data 바로 serialize
        if serializer.is_valid(raise_exception=True): -> 유효한 데이터인 경우 아래 코드 실행
raise_exception=True 를 통해 유효하지 않은 데이터인 경우 400 response
(주석 처리한 줄과 같은 역할)
            serializer.save() -> 입력받은 데이터 save (form.save() 와 유사)
            return Response(serializer.data, status=status.HTTP_201_CREATED) -> 지정한 status 코드로 response
status= 로 따로 지정하지 않을 경우 200 response


@api_view(["GET", "DELETE"])
def row_detail(request, pk):

    # 게시글 상세 조회
    if request.method == "GET":
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True) -> row 1개인 경우, 조건은 column을 parameter로 하여 인자로 전달
        serializer = <Serializer A>(row)
        return Response(serializer.data)

    # 게시글 수정
    elif request.method == "PUT":
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True)
        serializer = <Serializer A>(data=request.data, instance=row, partial=True) -> request에 담긴 data 바로 serialize
instance에 수정하려는 row querydict를 인자로 넘겨야 serializer가 수정하려는 row를 serialize 하게 됨
(instance 인자값을 주지 않을 경우 새로운 row를 생성하는 것으로 됨 (게시글 생성과 동일)
partial에 True 인자값을 줄 경우 PUT 요청으로 일부 column에 대한 데이터만 와도 수정 가능
(partial에 인자값을 주지 않을 경우 일부 column 데이터만 요청으로 왔을 때 is_valid 통과를 못하고 400 response)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)

    # 게시글 삭제
    elif request.method == "DELETE":
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True)
        row.is_visible = False -> row 직접 삭제를 하지 않고 is_visible 필드값만 수정
        row.save()
        return Response(status=status.HTTP_204_NO_CONTENT)

------------------------------

★★★ DRF Class Based View

특징

- 특정 Http Method에 대한 처리를 함수로 분리 가능. GET요청에 대한 처리는 'get()', POST 요청에 대한 처리는 'post()'에서 정의
- 클래스를 사용하기 때문에 코드의 재사용성과 유지보수성 향상
- 기본 'APIView' 외에도 여러 편의를 제공하는 다양한 내장 CBV가 존재

종류

ⓐ APIView: DRF CBV의 베이스 클래스

ⓑ GenericAPIView: 일반적인 API 작성을 위한 기능이 포함된 클래스
보통 CRUD 기능이 대부분인 상황을 위해 여러가지 기능이 미리 내장

ⓒ Mixin: 재사용 가능한 여러가지 기능을 담고있는 클래스
여러 클래스를 섞어서 사용하기 위한 클래스

ⓓ ListModelMixin: 리스트 반환 API를 만들기 위해 상속 받는 클래스

ⓔ CreateModelMixin: 새로운 객체를 생성하는 API를 만들기위해 상속 받는 클래스

ⓕ ViewSets: 여러 엔드포인트(endpoint)를 한 번에 관리할 수 있는 클래스
RESTful API에서 반복되는 구조를 더 편리하게 작성할 수 있는 방법을 제공

※ 강의에서는 APIView 를 이용해서 학습, 추후 필요시 하나씩 적용해보는 것을 권장


★ views.py

from django.shortcuts import get_list_or_404, get_object_or_404

from rest_framework import status -> 상태코드 상수
from rest_framework.response import Response -> Response return 위해 필요한 모듈
from rest_framework.views import APIView -> 상속받을 APIView 클래스 (CBV 작성을 위함)

from .models import <Model A> -> 사용할 모델(DB Table)
from .serializers import <Serializer A> -> 사용할 Custom ModelSerializer


class RowListAPIView(APIView):
    def get(self, request):
        rows = get_list_or_404(<Model A>, is_visible=True) -> row 여러개인 경우
        serializer = <Serializer A>(rows, many=True) -> many=True
        return Response(serializer.data)

    def post(self, request):
        serializer = <Serializer A>(data=request.data) -> request에 담긴 data 바로 serialize
        if serializer.is_valid(raise_exception=True): -> 유효한 데이터인 경우 아래 코드 실행
raise_exception=True 를 통해 유효하지 않은 데이터인 경우 400 response
(주석 처리한 줄과 같은 역할)
            serializer.save() -> 입력받은 데이터 save (form.save() 와 유사)
            return Response(serializer.data, status=status.HTTP_201_CREATED) -> 지정한 status 코드로 response
status= 로 따로 지정하지 않을 경우 200 response

class RowDetailAPIView(APIView):
    
    def get_row(self, pk):
        return get_object_or_404(Article, pk=pk, is_visible=True) -> ★ 3번 이상 반복되는 코드일 경우 별도의 함수로 분리하는 것이 좋다 (case by case)

    def get(self, request, pk):
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True) -> row 1개인 경우, 조건은 column을 parameter로 하여 인자로 전달
        serializer = <Serializer A>(row)
        return Response(serializer.data)

    def put(self, request, pk):
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True)
        serializer = <Serializer A>(data=request.data, instance=row, partial=True) -> request에 담긴 data 바로 serialize
instance에 수정하려는 row querydict를 인자로 넘겨야 serializer가 수정하려는 row를 serialize 하게 됨
(instance 인자값을 주지 않을 경우 새로운 row를 생성하는 것으로 됨 (게시글 생성과 동일)
partial에 True 인자값을 줄 경우 PUT 요청으로 일부 column에 대한 데이터만 와도 수정 가능
(partial에 인자값을 주지 않을 경우 일부 column 데이터만 요청으로 왔을 때 is_valid 통과를 못하고 400 response)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        row = get_object_or_404(<Model A>, pk=pk, is_visible=True)
        row.is_visible = False -> row 직접 삭제를 하지 않고 is_visible 필드값만 수정
        row.save()
        return Response(status=status.HTTP_204_NO_CONTENT)


★ urls.py

urlpatterns = [
    path("", views.RowListAPIView.as_view(), name="row_list"), -> CBV로 작성했을 경우 해당 클래스명에 .as_view()로 호출
    path("<int:pk>/", views.RowDetailAPIView.as_view(), name="row_detail"),
]

------------------------------

'PYTHON' 카테고리의 다른 글

[TIL] 20240425 51일차  (1) 2024.04.25
[TIL] 20240424 50일차  (0) 2024.04.24
[TIL] 20240423 49일차  (0) 2024.04.23
[TIL] 20240422 48일차  (0) 2024.04.22
20240408 ~ 20240412 9주차 정리  (0) 2024.04.12