기본 콘텐츠로 건너뛰기

django REST API practice like a boss

pycharm 안녕.
django project 생성.

실행환경은 virtualenv로 3.6.x
virtualenv 생성에 약간 시간 소모.
setting.py와 urls.py가 반겨줌

djex1 프로젝트를 만들었음
__init__.py
settings.py
urls.py
wsgi.py
요렇게 생김.

자, 게임을 시작해볼까?
option+R 누름.

이런 애가 나옴.
startapp product 라고 쳐서 product 업무를 만들어보자.
자동완성이 된다.

product 아래
admin.py
apps.py
models.py
tests.py
views.py
이런 파일들이 생겼다. rails 생각이 난다.
내용물은 텅텅 비어서 실망스럽다.
comment라도 있을 줄 알았는데.
여튼 텍스트로 hello world 같은 건 안찍어본다. 바로 rest API
http://www.django-rest-framework.org/tutorial/quickstart/
돌입한다.
pip install djangorestframework
뭔가 설치했으니
requirements.txt로 pip freeze하여 깡통인 곳에서 설치할때 pip install -r requirements.txt로 설치할 수 있게 만들자.
pip freeze > requirements.txt

REST API framework는 설치했고 DB를 만들자.
먼저 migrate을 돌려주자.
option+R 상태에서 migrate 엔터
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK
Following files were affected
 /Users/spectrum/Documents/python/djex1/db.sqlite3
이런 식으로 죽 올라가고 db.sqlite3 이란 파일이 생겼다.
로컬디비가 기본이 sqlite다.
pycharm의 툴을 이용해서 연결해놓자.
아니 이렇게 좋은 것이?
만일 처음 sqlite data source를 추가하는 것이면 Download missing driver files 라고 나올 수도 있는데 Download를 누르면 알아서 드라이버를 받는다.
기본은 pycharm 에서 관리하는 경로인데 File: 에서 ... 을 눌러 현재 프로젝트의 db.sqlite3랑 연결하자.
Project에서 Copy Path 해놓은 걸 붙여넣기 하면 편하다.
Test Connection 눌러서 Successful 떨어지는 거 구경하고 OK
기본 서비스가 훌륭
DB가 있으니 모델을 만들자.
product/models.py 에 자동완성을 써가면서 만들어 보았다.
from django.db import models

class Product(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.TextField()
    price = models.IntegerField()
    createdAt = models.DateTimeField(auto_now_add=True)
오케이 makemigrations product 해보자
App 'product' could not be found. Is it in INSTALLED_APPS?
하고 묻는다.
djex1/settings.py 에 INSTALLED_APPS를 수정하자.
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # apps
    'product',
]
시키는 대로 했다.
Migrations for 'product':
  product/migrations/0001_initial.py
    - Create model Product

Following files were affected 
 /Users/spectrum/Documents/python/djex1/product/migrations/0001_initial.py
migrations 파일이 생겼다.
Database는 변함이 없는데
방금 생성한 migrations 를 가지고 실제 table들을 만들자
option+R 상태에서 migrate
그리고 python console 에서 확인해보자.
PyDev console: starting.
Python 3.6.2 (v3.6.2:5fd33b5926, Jul 16 2017, 20:11:06)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Django 2.0.1
>>> from product.models import Product
>>> Product.objects.all()
<QuerySet []>
좋아보인다. import를 하는 순간. Product가 watch에 보이는게 좋다.

db 를 새로고침하면
테이블명이 엄하다.
업무명인 product에 entity명도 product 니 product_product로 나올 수 밖에.
graphviz로 ERD도 뽑아보자.
brew install graphviz
pip install django-extensions
pip install pygraphviz
쭉 설치하고
djex1/settings.py 에 INSTALLED_APPS에 django-extensions 추가
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'product',
    # extension
    'django_extensions',]
option+R에서 graph_models product -o test.png 뽑아본다.

괜찮네.
어드민도 있었지. 한번 볼까.
option+R에서 createsuperuser
유저명/이메일/암호 다 넣고
녹색 삼각형 눌러서 django Rrrrrrrrrrrun!
createsuperuser로 진입하면 이렇게 된다.
groups/users가 기본이고 users에 admin계정 하나 달랑 들었다.

view 만들어 볼 차례다.

product/views.py 를 열고
from rest_framework.generics import ListAPIView
from rest_framework import serializers
from product.models import Product
3개를 import 하자. ListAPIView하고 serializers는 이 view에서 사용할 것이고 대상인 모델은 product.models의 Product이다.
실제로 화면에 연결할 View를 만들기 전에 Product model을 가져와보자.
그냥은 가져올 수 없고 serializers.ModelSerializer 를 사용하는 serializer를 먼저 만들어야한다.
class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
이정도면 일단 오케이
여기에 실제 url 과 연결할 View를 만들자
class ProductsView(ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
중요한 건 queryset.
product/views.py는 이렇게 완성하자.
from rest_framework.generics import ListAPIView
from rest_framework import serializers
from product.models import Product

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product

class ProductsView(ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
나머지는 연결하는 것만 남았다.
djex1/urls.py 의 최종모습은
from django.contrib import admin
from django.urls import include, path
from product.views import ProductsView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('product/', ProductsView.as_view()),
]
이와 같다.
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
커멘트에 있는 내용대로 path와 View 클래스.as_view()로 연결했다.

API서버가 완성되었다.
http://127.0.0.1:13000/product/?format=json 하면 [] 값만 나오기도 한다.

django admin을 이용해 model로 만든 테이블에 값을 입력해보자.
product/admin.py 에서 admin.site.register() 를 사용하여 model을 추가한다.
model은 from product.models import Product 있으니
from django.contrib import admin
from product.models import Product
admin.site.register(Product)
이정도면 된다.
/admin 을 보자.

Product / Products가 나왔다.
+ Add 를 눌러서 데이터를 입력할 수 있다.

relation을 만들기 위해 Coupon도 한번 만들어보자.
class Coupon(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    product_id = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
    )
    createdAt = models.DateTimeField(auto_now_add=True)
product_id라는 필드를 foreignkey로 product와 완결했다.
product삭제시에 같이 삭제되도록 models.CASCADE를 지정했다.
product/admin.py를 조금 손봐서
from django.contrib import admin
from product.models import Product, Coupon

class ProductAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'price')

class CouponAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'product_id')

admin.site.register(Product, ProductAdmin)
admin.site.register(Coupon, CouponAdmin)
이렇게 만들고 django admin에서 값을 입력해보면
이 경우 Coupon -> Product 인 상태에서 
1. Coupon을 기준으로 Product 접근:
  Coupon.objects.get(id=2).product_id.price # 한개
  Coupon.objects.filter(id=2).select_related() # 일치하는 여러개
2. Product를 기준으로 Coupon 접근:
  Product.objects.get(id=2).coupon_set.all() # 한개
  Product.objects.filter(id=2).prefetch_related() # 일치하는 여러개
이 가능하다.

이번에 처음 django를 써봤는데 안정적이고 완성도 높은 framework이네.
admin하나만 해도 꽤 훌륭해보인다.

이 블로그의 인기 게시물

ESP32 DevBoard 개봉기

오늘 드디어 손에 넣었다. ESP32 DevBoard!
Adafruit 에서 15개 한정 재입고 트윗을 보고 광속 결제.
그리고 1주일의 기다림. 사랑해요 USPS <3
알리를 이용하다보니 1주일 정도는 광속 배송임.
물론 배송비도 무자비함 -_ㅜ
15개 한정판 adafruit 발 dev board
그놈이 틀림없으렸다.
오오 강려크한 포스
ESP32_Core_board_V2라고 적혀있군요.
ESP32 맞구요. 네네. ESP32-D0WDQ6 라고 써있는데 D → Dual-core 0 → No internal flash W → Wi-Fi D → Dual-mode Bluetooth Q → Quad Flat No-leads (QFN) package 6 → 6 mm × 6 mm package body size 라고 함.
길이는 이정도
모듈크기는 이정도
코어는 6mm밖에 안해! 여기에 전기만 넣으면 BLE+WIFI!
밑에 크고 발 8개 달린 놈은 FM25Q32라고 32Mbit 플래시메모리
ESP8266 DevBoard 동생이랑 비교 크고 아름다운 레귤레이터랑 CP2102 USB Driver가 붙어있음.
ESP8266 DevBoard엔 CH340G 인데 확 작아졌네.
머리를 맞대어 보았음.
모듈크기는 아주 약간 ESP32가 더 큰데 워낙에 핀이 많고 촘촘함. ESP8266인 ESP12는 핀 간격이 2.00mm인데 비해
ESP32는 1.27mm 밖에 안함.
딱봐도 비교가 될 정도.
https://www.sparkfun.com/news/2017 크고 아름다운 Pinouts

ESP8266 보드랑 별로 안달라보인다.
http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers.aspx#mac
에서 CP2102 드라이버를 설치하고
screen 으로 연결해보자.
내 경우엔 tty.SLAB_USBtoUART 로 잡혔다.
어디서 기본 속도가 115200bps 라고 들은 적이 있어서
screen /dev/tty.SLAB_USBtoUART …

즐거운 Online Prototyping Tool 들

jsbin, codepen, jsfiddle 이런 것들은 일단 생략. 너무 유명한 것들이라.

https://launchpad.graphql.com - node.js 기반 graphQL 연습장. 이것만으로도 충분히 훌륭한 백엔드
https://codesandbox.io/ npm 사용이 가능한 클라이언트 사이드 연습장. webpackbin이 너무 문제가 많아서 찾아본 것.

https://scrimba.com 이건 codesandbox+ asciinema(https://asciinema.org/) 같은 느낌인데 키 녹화와 음성 녹화 기능이 추가되었다. 다 좋은데 화살표 키로 빨리감기 뒤로감기 기능이 안되고 익스포트(youtube등)으로 지원이 없는게 아쉽다.

이 둘이 만나면? https://codesandbox.io/s/jvlrl98xw3?from-embed
뭐야 이거 무서워 하지마 ㄷㄷ;  graphql+react-native-web(부왘ㅋㅋ)

https://repl.it/languages 전통을 자랑하는 REPL 도구. 지원 언어 종류가 -_-;;;;;

https://tio.run/# repl.it? 장난함? 얘는 지원 언어가 무려 386종류. J랑 아희도 있다.

https://play.golang.org/ 즐거운 go playground. 소스 포멧팅 넘 좋아.

http://decaffeinate-project.org/repl/ 최고의 coffeescript REPL. 원래 용도는 coffee를 ecma6코드로 바꾸는 것이지만...

https://scaphold.io
https://www.graph.cool/ graphql backend service. scaphold.io는 설치도 필요없는 클라우드. graphcool은 호스팅+클라우드 다있음. 둘 다 막상막하. 푸쉬서버도 되고 뭐 미친득.

https://glitch.com/ gomix에서 결국 glitch로 안착.  node.js

https://www.shadertoy.com 잘하고 싶다! 쉐이다! 오디오도 된다!

http:/…

graphql 연습 /w launchpad

https://launchpad.graphql.com/mw9wkzv99
단순 전체쿼리+조건쿼리+추가

http://graphql.org/graphql-js/passing-arguments/
참고. random ID는 crypto 1.0.1 사용
  type Query {
    Members: [member]
    getMember(id: ID!): member
  }
  type member {
    id: ID!
    text: String
  }
  input memberInput {
    text: String
  }
  type Mutation {
    addMember(member: memberInput): member
  } SQL 정의. facebook 쪽은 스트링에 지지는 거 진짜 좋아하네. *.gql 파일이 있다고 하니 이해해주자.
resolver는 var buffer = [];
const resolvers = {
  Query: {
    Members: (root, args, context) => {
      return buffer;
    },
    getMember: (id)=> {
      return buffer.find(o=>o.id)
    }
  },
  Mutation: {
    addMember(_, {member}) {
      const mm = { ...member, id:randomBytes(10).toString('hex') };
      buffer.push(mm);
      return mm;
    }
  }
}; 평범 평범.
https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951 다음으로 pub/sub 연습.
https://launchpad.graphql.com/xvn94n3ql   type Subscription {
    memberAdded: member
  } member가 added되는 순간을 감시. imp…