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