HTTP Client(Httpie, Chrome, Postman 등)를 사용해서 Server에 요청을 보내고 Django Application 을 통해 요청을 분석(URLconf) 하고 요청을 처리하기 위한 로직(View)을 실행시켜 데이터베이스와 통신(Model) 하여 데이터 작업을 수행하고 요청에 맞는 응답을 보낼 수 있는 Backend API를 구현해봅시다.
1. Server에 HTTP request 할 수 있는 Httpie 설치하기
#Ubuntu
sudo apt install httpie
#Mac
brew install httpie
2. Body에 담아서 보낼 Data 만들기 (httpie는 string type을 기본으로 전송)
{
"menu" : "음료",
"category" : "에스프레소",
"product" : "카페 라떼"
}
3. Http POST 요청 보내는 방법
$ http -v POST 127.0.0.1:8000/product menu='음료' category='에스프레소' product='카페 라떼'
# 또는
$ echo '{ "menu" : "음료", "category" : "에스프레소", "product" : "카페라떼"}' | http -v POST 127.0.0.1:8000/products
- 주인과 강아지를 DB에 등록하고 각각의 리스트를 불러올 수 있는 View를 작성해보자.
- 주인과 강아지는 일대다 관계이다.
한명의 주인은 강아지 여러 마리를 가질 수 있지만, 하나의 강아지는 한명의 주인만 가진다.
# owners.models.py
from django.db import models
class Owner(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
email = models.EmailField(max_length=40)
class Meta:
db_table = 'owners'
class Dog(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
owner = models.ForeignKey("Owner", on_delete=models.CASCADE)
class Meta:
db_table = 'dogs'
Dog class의 owner 필드는 Owner class로 외래키를 설정해주고, 부모 테이블 값이 삭제되면 자식 테이블에도 그 값이 자동 삭제되도록 on_delete=models.CASCADE
옵션을 지정해준다.
주인 owners (부모 테이블)
# owners.views.py
import json
from django.http import JsonResponse
from django.views import View
from owners.models import Owner
class OwnerView(View):
def post(self, request):
try:
data = json.loads(request.body)
Owner.objects.create(
name = data['owner_name'],
email = data['owner_email'],
age = data['owner_age'],
)
return JsonResponse({'message': 'CREATED'}, status=201)
except KeyError:
return JsonResponse({'message' : 'KEY_ERROR'},status=400)
OwnerView로 오는 HTTP POST 요청을 받아들여서 주인의 이름, 이메일, 나이 정보를 DB에 저장한다.
json.loads()
메소드는 JSON 문자열을 파이썬 딕셔너리 형태로 전환시켜준다. 즉, 파이썬 객체를 반환한다.
data
객체는 딕셔너리 타입으로 [key]
로 접근할 수 있으며 get()
메소드도 사용 가능하다.
→ 이때, key가 없다면 KeyError가 일어나고 get()을 사용하면 None만 반환된다.
try, except
문으로 KeyError 상황을 예외처리 해주고 적절한 에러를 반환한다.
class OwnerView(View):
...
def get(self, request):
result = []
owners = Owner.objects.all()
for owner in owners:
dog_list = []
dogs = owner.dog_set.all() # 역참조 활용
for dog in dogs:
dog_info = {
"name" : dog.name,
"age" : dog.age
}
dog_list.append(dog_info)
owner_info = {
"name" : owner.name,
"email" : owner.email,
"age" : owner.age,
"dog_list" : dog_list
}
result.append(owner_info)
return JsonResponse({'result': result}, status=200)
OwnerView로 오는 HTTP GET 요청을 받아들여서 강아지 주인 리스트를 응답한다.
이때 포함하는 정보는 주인의 이름과 이메일, 나이, 강아지 리스트(이름과 나이)이다.
모든 주인에 대하여 아래의 로직을 반복한다.
모든 주인 정보와 각 주인마다 보유한 강아지 정보가 필요하다.
각 주인마다 보유한 강아지 정보를 알기 위해 dogs 테이블로 접근한다.
-> owners 테이블에서 접근하려면 역참조 (외래키는 dogs 테이블에 있으니까)
해당 강아지가 여러 마리일 수 있으니 for문으로 순회하고 배열에 담는다.
해당 주인의 정보와 강아지 리스트를 최종 result 배열에 담는다.
# owners.views.py
class OwnerView(View):
...
class DogView(View):
def post(self, request):
data = json.loads(request.body)
# 에러핸들링
if not Owner.objects.filter(id=data['owner_id']).exists():
return JsonResponse({'MESSAGE': "Owner Does Not Exist"}, status=404)
Dog.objects.create(
name = data['dog_name'],
age = data['dog_age'],
owner_id = data.owner.id # 정참조 활용
)
return JsonResponse({'MESSAGE': 'CREATED'}, status=201)
def get(self, request):
result = []
dogs = Dog.objects.all()
for dog in dogs:
dog_info = {
"name" : dog.name,
"age" : dog.age,
"owner_name": dog.owner.name # 정참조 활용
}
result.append(dog_info)
return JsonResponse({'result': result}, status=200)
POST 요청으로 강아지 등록시 이름, 나이, 주인id가 필요하다.
GET 요청으로 강아지 리스트를 요청하면 dogs table에서 FK를 이용해 정참조로 주인 이름을 포함시킨다.
if문과 exitsts()
메소드를 이용해 요청된 데이터의 주인id가 없으면 에러 메시지를 반환한다.
# owners.urls.py
from django.urls import path
from owners.views import OwnerView, DogView
urlpatterns = [
path('/owner', OwnerView.as_view()),
path('/dog', DogView.as_view())
]
urls.py
파일을 작성한다.# project.urls.py
from django.urls import path, include
urlpatterns = [
path('owners', include("owners.urls")),
]
프로젝트 폴더의 urls.py
에서 연결하고자 하는 View를 바라보게 해준다.
여기선 url 참조를 위해 include
함수를 이용한다.
HTTP 요청시 localhost/owners/owner(or dog) 주소로 보낸다.