이전 포스팅에서는 django shell
을 이용하여 데이터베이스에 접근하고, 데이터를 추가
, 조회
, 삭제
, 수정
하는 연습을 했습니다.
하지만, 우리가 실제 웹 또는 앱 서비스를 출시하면 사용자들과 의사소통을 해야할 것입니다.
사실을 컴퓨터가 소통하는 방식입니다만, 이해하기 쉽게 작성해보겠습니다.
클라이언트
(사용자, 프론트엔드)에서 http method를 통해 다양한 요청이 서버
에게 전달되고, 알맞은 응답을 해주는 방식을 말합니다.
이제 http 방식을 통해 실제로 데이터베이스의 데이터에 접근하고 처리하는 방법에 대해 연습해보겠습니다.
httpie
를 작업 가상환경-디렉토리를 다루는 터미널에 설치해줍니다.sudo apt intall httpie
이번 포스팅에서 주로 다루는 프로젝트/앱 파일은 다음과 같습니다.
urls.py
views.py
초기 세팅이 완료된 상태에서 진행해야합니다.
사용자의 요청이 어떻게 이루어졌는지 분석하는 단계
클라이언트와 서버가 소통하기 위해서는 요청 방식과 어떤 도메인 주소를 사용했는지 분석을 하는 단계입니다.
우선 클라이언트가 다음과 같이 요청을 해오면,
GET https://127.0.0.1:8000/cofffe
다음과 같은 분석을 할 수 있겠습니다.
GET
이라는 HTTP method를 받았으니, 클라이언트가 무언가 원하는 정보가 있겠구나?coffee
이면 커피에 대한 정보를 원하는 구나?서버는 이런 분석을 통해 다음과 같은 응답을 할 수 있겠습니다.
200 OK {"name" : "아이스 아메리카노"}
그리고 이런 분석을 통해 사용자에게 정보를 제공하기 위해 urls.py
파일을 거치게 됩니다.
urls.py
파일의 구조는 다음과 같습니다.from django.urls import path, include
urlpatterns = [
path('resource', include('resource.urls')),
]
resource
는 클라이언트가 요청하면서 보낸 부분(coffee)과 동일합니다.
도메인 주소의 구성 요소 중 하나로, 우리의 장고 프로젝트에서는 하나하나의 앱 이름
이 되겠네요.
Main 디렉토리의 urls.py
파일에서 resource
부분에 해당하는 앱 디렉토리로 이동을 하여 로직을 처리할 것입니다.
urls.py
파일 구조는 다음과 같습니다.프로젝트 앱 디렉토리 내부에는 ulrs.py
파일이 없으니, 반드시 생성하고 작업을 진행해주어야 합니다.
from django.urls import path
from App디렉토리이름.views import views파일의클래스이름
urlpatterns = [
path('경로', views파일의클래스이름.as_view()),
]
resource
에 해당하는 앱 디렉토리에는 views.py
파일이 있습니다.
"경로"
에 해당하는 주소로 클라이언트가 요청을 한 경우, views파일의클래스이름
중 요청받은 HTTP method와 같은 모듈이 있는지 확인해줍니다. (as_view()
의 역할)
뒷부분에서 자세히 설명하겠지만, App디렉토리이름/urls.py
파일에는 사용자에게 보여지는 정보를 처리하는 방식을 담고 있습니다.
App디렉토리이름/views.py
파일의 class
에 내부의 로직을 통해 사용자에게 보여지는 정보를 처리해줄 것입니다.
요청을 처리하기 위한 로직/모듈이 있으며, 사용자에게 보여지는 정보를 처리하는 단계입니다.
실습 코드만 보기: 여기를 클릭해주세요!
아래 코드는 views.py
파일 중 POST method와 관련된 코드 조각입니다.
코드 내부에서 코드를 하나씩 뜯어보겠습니다.
# 클라이언트에게 받은 JSON 데이터를 처리하기 위해
import json
# JSON으로 데이터를 다시 바꿔 응답하기 위한 모듈
from django.http import JsonResponse
from django.views import View
# model에서 정의한 class들 가져오기
from owners.models import Owenr, Dog
# 클래스 하나마다 다뤄야하는 자원,,, 어떤 자원을 다루는 것인지 명사형으로 작성
class OwnerView(View):
# method 이름은 http 통신 method 이름과 일치시킴 === post
# URLconf에서는 class만 처리 === OwnerList
# http요청에 따라서 method를 처리하기 때문에 http통신과 같은 이름을 사용할 것
def post(self, request): # 필수인자 2개 // request = 클라이언트가 요청한 정보가 들어있음
data = json.loads(request.body) # rq.body의 JSON 형식의 데이터를 dic으로 바꿔 사용하겠다
# 객체 정보를 변수에 저장
# 받아야되는 정보를 받지 않았으면 에러 발생했을 때 찾기 쉬움
# transaction의 개념 >> 장바구니 구현 때 활용
owner_name = data["name"]
owner_email = data["email"]
owner_age = data["age"]
# Owner 테이블에 데이터를 생성하는 코드
# objects는 manage class를 가리키며, 그 클래스 내부의 메서드 중 create를 사용
Owner.objects.create(
name = owner_name,
email = owner_email,
age = owner_age
)
return JsonResponse({'message':'주인 정보가 등록되었습니다.'}, status=201)
# 요청에 대한 응답을 return하는 부분
# {msg : created} >> Response body
# status=201 >> 상태코드
class DogView(View):
def post(self, request):
data = json.loads(request.body)
dog_name = data["name"]
dog_age = data["age"]
owner = data["owner_id"] #Owner.objects.get(name=data["owner"])도 가능
Dog.objects.create(
name = dog_name,
age = dog_age,
owner_id = owner # owner_id 값을 넣어줄 수 있습니다.
)
return JsonResponse({'messasge':'강아지 정보가 등록되었습니다.'}, status=201)
DogList
클래스에서 데이터를 생성하는 내부 모듈 중 owner
변수에 다음과 같이 객체를 담을 수 있는데요:
owner = Owner.dobjects.get(name=data["owner"])
외래키를 참조하는 경우 객체 자체를 넣어주는 코드로서 클라이언트가 id 정보를 줄 수 없는 경우 사용할 수 있습니다.
하지만 id 값을 테이블을 확인하여 직접 확인하여 작성하였기 때문에 위와 같은 코드를 작성할 수 있었습니다.
경우에 따라 필요한 코드를 사용하여 적절한 로직을 작성해주는 것이 올바른 방법이겠죠.
아래 코드는 views.py
파일 중 GET method와 관련된 코드 조각입니다.
코드 내부에서 코드를 하나씩 뜯어보겠습니다.
class OwnerView(View):
def get(self, request) :
owners = Owner.objects.all() # QuerySet 변환 == List와 같은 데이터 타입
results = [] # 가공된 데이터를 넣는 공간 >> reponse 될 때 JSON 형태로 반환
for owner in owners :
# 강아지 정보를 List Comprehension으로 데이터를 받아오는 코드
dog_list = [
{
"이름": dog.name,
"나이": dog.age
} for dog in Dog.objects.filter(owner_id = owner.id)
# owner_id >> Dog테이블이 Owner테이블을 참조하는 외래키
# owner.id >> Dog테이블이 참조하는 Owner 테이블의 id 값
]
results.append(
{
"이름" : owner.name,
"이메일" : owner.email,
"나이" : owner.age,
"강아지" : dog_list
}
)
return JsonResponse({'주인+강아지 리스트': results}, status=200)
# 요청에 대한 응답을 return하는 부분
# {msg : created} >> Response body
# status=200 >> 상태코드
class DogView(View):
def get(self, requeset) :
dogs = Dog.objects.all() # QuerySet 변환 == List와 같은 데이터 타입
results = [] # 가공된 데이터를 넣는 공간 >> reponse 될 때 JSON 형태로 반환
for dog in dogs :
results.append(
{
"이름" : dog.name,
"나이" : dog.age,
"주인 이름" : dog.owner.name # owner를 참조하기 때문에 다음과 같이 작성할 수 있다.
}
)
return JsonResponse({'강아지 정보': results}, status=200)