Http client(Httpie, Chrome, Postman 등)를 사용해서 직접 client의 입장이 되어보자. 여기서 사용할 Httpie는 백엔드가 프론트의 입장이 되어서 직접 만든 API를 직접 호출해볼 수 있게 해주는 프로그램이다.
#Ubuntu
sudo apt install httpie
#Mac
brew install httpie
httpie 는 string type 을 기본으로 전송한다. 자세한 httpie 사용법은 여기를 참고하자.
{
"menu" : "음료",
"category" : "콜드브루",
"product" : "맛있는 콜드브루"
}
http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루'
product='맛있는 콜드브루'
앞서 application을 생성하고 디렉토리 안에 models.py 파일이 생성된 것을 보았을 것이다. 그 models 파일을 작성해보자.
아래 코드 예시는 이전 포스팅에서 만든 westarbucks 프로젝트를 사용한다.

#products/models.py
from django.db import models
class Menu(models.Model):
name = models.CharField(max_length=20)
class Meta:
db_table = 'menus'
class Category(models.Model):
name = models.CharField(max_length=20)
menu = models.ForeignKey('Menu', on_delete=models.CASCADE)
class Meta:
db_table = 'categories'
class Product(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
class Meta:
db_table = 'products'
자원(resource)을 생성할 때 Http method 중에 Post를 사용한다. 로그인, 회원가입 등 정보를 요청 할 때도 POST로 요청한다.
#products/views.py
import json #프론트로부터 받은 json을 백에서 사용할 수 있는 형태로 바꿔준다.
from django.http import JsonResponse #django가 dict를 json으로 변환한다.
from django.views import View #view기능을 사용할 수 있게 한다.
from products.models import Menu, Category, Product
class ProductsView(View): #1번 참조
def post(self, request): #2번 참조
data = json.loads(request.body) #3번 참조
menu_name = data['menu']
category_name = data['category']
product_name = data['product']
menu = Menu.objects.create(name=menu_name) #4번 참조
category = Category.objects.create(
name = category_name,
menu = menu
)
Product.objects.create(
name = product_name, #프론트에서 받은 'category'키의 value값.
category = category
)
return JsonResponse({'message':'created'}, status=201)
class ProductsView(View)
- class 하나가 내가 다룰 resource(자원)라고 생각하면 된다.
- API주소를 설계할 때는 주소 안에 필요한 자원만 넣는다.
- class 이름을 지을 때에는 어떤 자원에 대한 행위를 할 건지 생각하고 class 이름을 짓는다.
- class 안의 함수이름(메서드이름)은 http 메서드 이름과 일치해야한다.
def post(self, request)
- request는 프론트가 주는 request 정보가 들어있다. 이 객체를 인자로 받는다.
data = json.loads(request.body)
- request 안에있는 body라는 속성에 프론트가 보낸 body정보가 들어있다.
- 프론트에서 온 json 형태의 body를 파이썬에 맞게 변환해서 변수 data에 담는다.
menu = Menu.objects.create(name=menu_name)
- menu_name, 즉
data['menu']는 프론트가 준 menu key. key의 이름은 프론트와 백 모두 일치해야한다.
View 를 작성 한 후에는 클라이언트의 요청을 받아 적절한 view 를 맵핑해주는 urls.py 를 작성해야한다. 앱 디렉토리에 파일을 생성하자.
touch urls.py
vi urls.py
# products/urls.py
from django.urls import path
from products.views import ProductsView
urlpatterns = [
path('', ProductsView.as_view()),
]
처음 클라이언트로 부터 요청을 받기 위해서는 manage.py가 위치하는 main urls.py(메인_폴더명/urls.py) 와 연결해줘야 한다.
# westarbucks/urls.py
from django.urls import path, include
urlpatterns = [
path('products', include('products.urls')),
]
이제 httpie(client)로 django server에 요청을 보내보자.
http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루' product='맛있는 콜드브루'
자원(resource)를 읽어 올 때 http method 중에 GET method를 사용한다. 이 때 url만 사용한다.
#products/views.py
import json
from django.http import JsonResponse
from django.views import View
from products.models import Menu, Category, Product
class ProductsView(View):
...
def get(self, request):
products = Product.objects.all() #Product table과 대응되고 있는 모든 데이터를 QuerySet 형태로 가져온다.
results = [] #append용 빈 list
for product in products: #프론트가 필요한 데이터를 만들어 준다.
results.append(
{
#키값 "menu"는 프론트와 이름이 동일해야한다.
#이 값이 변한다고 migration을 할 필요는 없다.
"menu" : product.category.menu.name,
"category" : product.category.name,
"product_name" : product.name
}
)
return JsonResponse({'resutls':results}, status=200)
products = Product.objects.all(): Product table과 대응되고 있는 모든 데이터를 QuerySet 형태로 가져온다.for product in products:: 프론트가 필요한 데이터를 만들어 준다.
product.category.menu.name
product: Product class 로 만들어진 객체들이 들어있다.category: Product class 안의 category 속성을 보면 Category class를 가리킨다.menu: Category class 안의 menu 속성을 보면 Menu class를 가리킨다.name: Menu class 안의 name 속성을 가져온다.
새로운 View 를 작성 한 후에는 클라이언트의 요청을 받아 적절한 view 를 맵핑해주는 urls.py 를 작성해야 한다(만약 동일한 view class 를 사용하고 http method 만 다르다면 동일한 url을 사용하면 된다).
main urls.py는 settings.py와 같은 경로에 있는 부모 urls.py다. 여기서 작성하는 urls.py는 바로 View로 연결하지 않고 자식 urls.py 파일이 있는 앱까지만 연결시켜준다. 즉, 어느 앱으로 연결해야 하는지만 알려준다.
from django.urls import path, include
urlpatterns = [
#어디로 보내야 하는지 주소를 작성하면 된다
path('products', include('products.urls'))
]
이 경우에 유효한 경로는 127.0.0.1:8000/products가 된다. 여기서 127.0.0.1은 자신의 컴퓨터 경로를 가리킨다. 지금은 실습만 하는 단계이므로 경로 문제는 생각하지 말자.
그 다음에는 처음 클라이언트로 부터 요청을 받기 위한 main urls.py와 연결해줘야 한다(위의 설명과 동일하게 이미 연결이 되어 있고, method 만 다르다면 동일한 url 을 사용하면 된다).
Client 에서 요청이 들어오면 처음에 main에 있는 urls.py의 경로를 탐색하고, 이와 일치하면 app에 있는 urls.py의 경로를 탐색한다.
from django.urls import path
from products.views import ProductsView
urlpatterns = [
path('', ProductsView.as_view())
]
이 경우에 유효한 경로는 127.0.0.1:8000/products가 된다. 만약 아래의 코드같이 작성한다면 어떻게 될까?
...
urlpatterns = [
path('/detail', ProductsView.as_view())
]
이 경우에는 127.0.0.1:8000/products/detail가 된다.
$ python manage.py runserver
http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루' product='맛있는 콜드브루'
http -v GET 127.0.0.1:8000/products
