client에서 server로 HTTP request를 전송할 수 있는 것중 하나인 Httpie
를 설치한다.
brew install httpie
brew install 은 프로그램을 설치하는 것 이므로 경로가 상관 없다. ex) mysql - 어느 가상환경에 설치하든 다 있다.
pip install 은 파이썬으로 작성된 패키지 소프트웨어를 설치하는 것이다. 가상환경 마다 설치가 필요하다 ex) django
까는 도중 에러가 발생했다 : link가 안되어있다!
이럴땐 brew link --overwrite@python=3.9
를 입력한 뒤 다시 brew install httpie
를 해준다.
이전에 연습했던 프로젝트에서 진행하겠다.
runserver를 한 상태에서 아래 코드를 입력해본다.
http -v POST 127.0.0.1:8000/products menu='음료' category='콜드브루' product:='{"name":"맛있는 콜드브루", "price":5400}'
다음과 같은 에러가 뜬다
Not Found: /product
[25/Jan/2021 15:31:27] "POST /product HTTP/1.1" 404 1966
이런 에러가 뜨는 이유는 요청을 받아 줄 서버가 없기 때문!!!
404 : Not Found
요청된 URI 가 존재하지 않는다는 의미
따라서 이번 학습은 해당 요청을 받아서 상품을 생성하는 application을 만드는 것이다.
class Menu(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table='menu'
class Category(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table='categories'
class Product(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=1000)
category = models.ForeignKey('Category', on_delete=models.CASCADE, null=True)
is_new = models.BooleanField(default=False)
def __str__(self):
return f'{self.name}'
class Meta:
db_table='products'
class Nutrition(models.Model):
fat_g = models.DecimalField(max_digits=4, decimal_places=1, null=True)
calories_kcal = models.DecimalField(max_digits=4, decimal_places=1, null=True)
caffeine_mg = models.DecimalField(max_digits=4, decimal_places=1, null=True)
product = models.OneToOneField('Product', on_delete=models.CASCADE, null=True)
def __str__(self):
return f'{self.product}'
class Meta:
db_table='nutritions'
프로젝트 연습을 하면서 admin에 의해 자동으로 생성되는 기능들을 사용하지 않기 위해
app/settings.py 에서
- IP 허용 : ALLOWED_HOST = ['*']
- INSTALLED_APPS 에서 다음 두개 주석처리
- django.contrib.admin
- djang.contrib.auth- MIDDLEWARE 에서 다음 두개 주석처리
- django.middleware.csrf.CsrfViewMiddleware
- django.contrib.auth.middleware.AuthenticationMiddleware
app/urls.py 에서
- urlpatterns = [ ] 괄호 안 내용 지움
을 설정해주었었다. 위 설정을 적용한 채로 runserver 뒤 http를 요청하면 200OK가 뜬다..
data를 create 하는것은 프론트로부터 받은 요청을 백에서 받아 database에 저장/수정 하는 것이다! 프론트의 관점으로 http 의 문법이 지칭되기 때문에 이런 경우 POST
하는 것이다. 따라서 create 할때에는 views.py 에서 post메소드를 사용한다.
resource(자원)을 생성할 때, post Method
를 사용한다!! (http method 중의 하나 / get과 반대 의미)
로그인, 회원가입 등 중요한 정보들도 POST method로 데이터를 request의 body에 담아서 client에서 server로 요청한다.
또한 models.py에서는 class를 만들고 그 속에 attribute(속성)을 넣었는데, views.py에서는 class를 만들고 그 안에 메소드(클래스 속의 함수 지칭), 그리고 그 메소드 안에 사용될 변수들을 생성해준다.
// vi products/views.py
// 원래 상태
from django.shortcuts import render
여기에 코드를 추가해 준다.
import json
from django.http import JsonResponse
from django.views import View
from products.models import Menu, Category, Product
class ProductsView(View):
def post(self, request):
data = json.loads(request.body)
menu = Menu.objects.create(name=data['menu'])
category = Category.objects.create(
name=data['category'],
menu=menu
)
product = Product.objects.create(
name=data['product']['name'],
category=category
)
return JsonResponse({'MESSAGE':'SUCCESS'}, status=201)
JSON ?
각 언어마다 지칭이 다르다! ex) 파이썬의 딕셔너리가 자바스크립트에서는 객체라고 불리운다..
때문에통신을 할때 언어별로 지칭이 다르더라도 약속된 형식으로 일하기로 약속
했는데 그것이 JSON 이며, text 형식으로 작동한다.! (통신을 할 때 key와 value로 이뤄져 있고 다 text 이다.. 사람이 알아볼수 없는 언어임)
따라서 이걸 사람이 알아볼 수 있도록 JSON 폼 데이터를 Python 객체로 읽게 하는 것이json.loads()
이다.
// vi wedia/urls.py
//원래 상태
from django.urls import path
urlpatterns = [
]
다음의 코드를 추가한다.
from django.urls import path, include
urlpatterns = [
path('products', include('products.urls'))
]
include도 함께 import 해주기!!!
app dir에는 원래 urls.py가 없다! 그래서 그냥 만들어 준다
새로 urls.py 만드는 법
- touch urls.py
touch
는 파일을 새로 만들거나 수정하는 명령어이다.- vi urls.py
vi
로 urls.py 안에 들어감과 동시에 존재하지 않았던 파일이라면 새로 만든다. 저장하면 파일이 새로 저장되는 격!
//in products/urls.py
from django.urls import path
from products.views import ProductsView
urlpatterns = [
path('', ProductsView.as_view())
]
http -v POST 127.0.0.1:8000/products menu='음료' category='콜드브루' product:='{"name":"맛있는 콜드브루", "price":5400}'
결과
[25/Jan/2021 16:17:09] "POST /products HTTP/1.1" 500 82761
😃 ................ 왜...그러는거야 대체..................
에러 위에를 보니 다음과 같은 문구가 있다
TypeError: Category() got an unexpected keyword argument 'menu'
카테고리에 메뉴가 연결이 안되있다고?? 엇;; 얼른 products/models.py 에 FK로 연결시켜 줬다;;
👏👏👏👏👏👏👏 박수짝짝
프론트의 관점에서 Read 하는것은 서버에 저장되어 있는 정보를 얻어오는 것이다! 때문에 이때 사용되는 것은 GET
메소드 이다.
get 메소드
- in django : table의 row를 불러온다!
- in http : 프론트가 백으로부터 데이터를 갖고 올 때
+) http의 post 메소드 : 프론트에서 백으로 데이터를 보낼 때 / 그 데이터가 db에서 등록/수정 되는 것.
// vi products/views.py
class ProductsView(View):
def get(self, request):
products = Product.objects.all()
results = []
for product in products:
results.append(
{
"menu":product.category.menu.name,
"category":product.category.name,
"product" :product.name
}
)
return JsonResponse({'results':results}, status=200)
아까 Create 를 위해 작성했던 class 에 get 메소드만 추가한다
공백 간격 주의... 탭 or space 둘중 하나만!!!!! 섞어쓰면 에러뜸
TabError: inconsistent use of tabs and spaces in indentation
위 파일 작성 후 runserver 터미널 상황
아까 create 하면서 설정한 것만 있으면 된다!
http -v GET 127.0.0.1:8000/products
AttributeError: 'NoneType' object has no attribute 'menu'
[25/Jan/2021 17:06:44] "GET /products HTTP/1.1" 500 67729
😃 ...... 한번에 되는게 없네
아까 급하게 category table에 menu를 넣으면서 null=True로 설정했다. 이 경우 불러올 menu의 값이 없기 때문에 위와 같은 에러가 뜬다... 값.. 넣고온다..그래도 안된다!
... products에서! menu 값이 없다는 뜻이었나???!!!! products table에 menu_id column 만들고 온다.
만들어도 안된다!!! 답은.. products table에서 category_id의 값이 NULL 이었기 때문에 NoneType 에서 읽어들일 수 없다고 뜬 것이었다..
그래서 django shell 을 이용해 빠르게 update 시켜주었다. (장고 쉘 이용 안하려구 이거 배우는 건데 ㅎㅎ;;) 그리고 !! 자나깨나 오타조심!!
{
"results": [
{
"category": "콜드 브루",
"menu": "음료",
"product": "나이트로 바닐라 크림"
},
{
"category": "콜드 브루",
"menu": "음료",
"product": "나이트로 콜드 브루"
},
{
"category": "프라푸치노",
"menu": "음료",
"product": "자바 칩 프라푸치노"
},
{
"category": "프라푸치노",
"menu": "음료",
"product": "화이트 딸기 크림 프라푸치노"
},
{
"category": "블렌디드",
"menu": "음료",
"product": "자몽 셔벗 블렌디드"
},
{
"category": "블렌디드",
"menu": "음료",
"product": "딸기 요거트 블렌디드"
},
{
"category": "에스프레소",
"menu": "음료",
"product": "아이스 커피"
},
{
"category": "에스프레소",
"menu": "음료",
"product": "오늘의 커피"
},
{
"category": "에스프레소",
"menu": "음료",
"product": "더블 에스프레소 크림 라떼"
},
{
"category": "브루드 커피",
"menu": "음료",
"product": "제주 샤이닝 바나나 라떼"
},
{
"category": "콜드브루",
"menu": "음료",
"product": "맛있는 콜드브루"
}
]
}
참고로 위 방법으로 읽히는 것은 models.py 의 __str__함수와는 전혀 상관 없다!!
오늘은 연습하면서 client도 됐다가... server도 됐다가 해봤다..
이런식으로 소통하는구나!!! 를 느낄 수 있었다!
따라치는것 이제 끝내고 스스로 쳐보면서 익히도록 한다.
U.D 는 열심히 googling 하면서 익히도록!