본문 바로가기
Study/PYTHON,Django

Django(3)-RestAPI 구현

by 왕방개 2024. 1. 25.

4.★REST API 구현 -중요★

1)웹 서비스를 구현하는 방식
=> 서버 사이드 랜더링

클라이언트(web browser)의 요청을 서버가 받아서 처리한 후 서버가 출력하는 코드를 만들어서 클라이언트에게 전송을 하고 클라이언트는 이 코드를 받아서 파싱해서 출력하는 방식

서버 코드와 클라이언트 코드를 하나의 프로젝트에 전부 작성
이렇게 작성하면 서버 코드를 수정할 때 클라이언트 코드가 영향을 받을 수 있고 클라이언트 코드를 수정할 때 서버 코드가 영향을 받을 수 있음

이 방식으로 서비스를 만들려면 템플릿 언어라는 것을 학습해야함
최근에 이방식 선호x

=>클라이언트 사이드 랜더링
서버는 클라이언트 요청을 받아서 데이터(XML->요새는JSON)을 응답으로 전송하고 클라이언트는 응답을 받아서 직접 데이터를 해석해서 출력하는 코드를 만들고 화면에 랜더링하는 방식

이방식에서는 서버 프로그램(Python의 django 나 Java의 Spring, JavaScript의 express.js)과 클라이언트 프로그램(vue.js,react.js -> next.js,android-java나 kotlin,ios-swift,플로터)을 별도로 작성.

서버 코드가 클라이언트 코드에 영향을 주지 않고 클라이언트 코드가 서버 코드에 영향을 주지 않습니다. 이렇게 통신만으로 서로 연동되는 경우를 느슨한 결합(loosly coupling)이라고 합니다

최근에는 프로그램에 유지/보수가 자주 발생하므로 이러한 느슨한 결합의 형캐로 프로그램을 만들기를 권장합니다.

프로그래밍 언어에서의 객체
ex.)   {name:"아담",age:53} -dict

person=Person()
person.name="아담"
person.age=53

프로토콜을 만들어야만 서로 대화를 할수 있음. 프로토콜의 진화과정
일반 텍스트
아담 53
군계일학 47

tsv- 탭으로 구분
아담  53
군계일학 47

★csv-콤마로 구분.절대로 변하지 않는 데이터는 csv로
이름,나이
아담,53
군계일학,47

★XML(eXtensible Markup Langauge):데이터를 태그로 표현,현재는 일부 RSS서비스에서만 사용되고 대부분 설정파일에서 많이 이용


아담
</age v="53">



군계
</age v="47">




csv보다 보기 좋으나, 길이가 너무 길어짐.

★JSON(JavaScript Object Notation-자바스크립트 객체 표현법: 파이썬과 동일):최근에 데이터 교환에 가장 많이 사용.모바일은 거의 대부분 이 방식.서버 개발자,클라이언트 개발자(데분).json파싱을 잘해야함.실시간으로 받아오는 데이터는 대부분.OpenAPI의 대부분

객체:{}
배일:[]

[{"name":"아담","age":53},{"name":"군계","age":47}]


★YAML-이메일 표현 방식을 이용해서 데이터를 구현, 최근에 설정에 많이 이용.현재까지 데이터교환할때 사용하지 않음.
person:
name:아담
age:53
person:
name:군계
age:52


2)python django에서 json 데이터를 제공하는 방법
=>dict 나 list(tuple) 로 데이터를 만들어서 직접 리턴하는 방식
=>프레임워크를 이용하는 방식

3)직접 dict 나 list 를 만들어서 리턴하는 방식
=>되도록이면 하나의 instance 를 dict로 만들어주는 함수나 클래스를 만들어서 사용하는 것이편리

person=Person()
person.name="아담"
person.age=53
이거를
p={"name":person.name, "age":person.age}

4)전체보기를 JSON으로 출력
=>model 클래스의 instance를 dict로 변환해주는 함수를 views.py에 작성

def itemToDictionary(item):
  output ={} #dict 생성
  output["itemid"] =item.itemid
  output["itemname"] = item.itemname
  output["price"] = item.price
  output["description"] = item.description
  output["pictureurl"] = item.pictureurl

  return output


=>views.py 파일에 전체보기를 처리할 함수를 생성

def allItems(request):
  #전체데이터를 가져오기
  items=Item.objects.all()
  #여러개의 데이터 이므로 list에 저장
  datas=[]
  for item in items:
    datas.append(itemToDictionary(item))
  #list를 JSON으로 리턴
  return JsonResponse({"data":datas})


=>urls.py 파일에 url과 views.py의 함수를 연결
urls.py에 urlpatterns에path("allitem/",views.allItems) 을 추가

=>서버를 구동하고 127.0.0.1/allitem/으로 브라우저에 요청하고 결과를 확인

 

5)상세보기 구현
=>views.py에 상세보기를 처리할 함수 생성

def get(request,itemid):
  #itemid가 매개변수인 데이터 가져오기
  #앞의 itemid는 컬럼 이름 이도 뒤의 itemid는 매개변수로 넘어온 값
  item=Item.objects.get(itemid=itemid)
  return JsonResponse(itemToDictionary(item))



=>서버를 구동하고 127.0.0.1/8000/get/번호로 브라우저에서 요청하고 결과를 확인
path("get/<int:itemid>",views.get)을 url patterns에 추가


 

1.REST API
1)API(Application Programming Interface)
=>프로그램과 프로그램을 연결시켜주는 매개체
=>프로그램을 만들기 위한 데이터를 제옹하는 기능이나 데이터를 사용하기 위한 프로그램이나 라이브러리를 API라고 합니다
Open API는 이러한 API를 누구나 사용할 수 있도록 공개한 것
=>데이터 대신에 프레임워크나 라이브러리 형태로 제공되면 SDK(Software Development Kit)이라고 합니다

2)CSR(Client Side Rendering)
=>서버는 클라이언트에게 데이터를 제공하고 클라이언트는 이 데이터를 받아서 직접 출력하는 코드를 만들어서 출력하는 방식
=>서버의 역할은 클라이언트로 부터 요청을 받아서 데이터를 제공하는 형식으로 구성

3)REST
=>개요
Representational State Transfer 의 약자로 분산 하이퍼 미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식

별도의 전송계층 없이 간단한 인터페이스로 자원을 정의하는 방식

=>6가지 제약 조건
Client -Server 구조

Stateleess:무상태,이전에 했던 작업에 대한 내역을 가지고 있지 않습니다.

Cacheable Data

Layered System:여러 개의 계층으로 나누어서 서비스가 가능

Uniform Interface:인터페이스가 일관성이 있어야 한다

아이템을 가져오는 URL -http://www.adamsoft.co.kr/get
아이템을 추가하는 URL -http://www.adamsoft.co.kr/insert
이러다 갑자기 수정하는 URL- http://www.adamsoft.co.kr/item/update 로 다르게 해놓음

Code-On-Demand:선택적 사항으로 클라이언트는 서버에 코드를 요청 할 수 있고, 서버가 리턴한 코드를 클라이언트에서 실행할 수 있음

=> 제약 조건을 지켜 만든 서버를 RESTful 하다고 합니다.

4)django에서 REST API Server를 구현하기 위한 방법
=>views에서 JsonResponse 를 리턴하는 방식-테스트를 하고자 하면 클라이언트를 구현하거나 테스트도구를 사용해야합니다
=>djangorestframwork 라는 패키지를 이용하는 방식 - 자체 테스트가 가능

2.django rest framework
0)확인
=>데이터베이스가 사용가능한지 확인
=>작업을 수행할 디렉토리 생성

1)프로젝트와 앱을 생성하고 기본 설정한 후 테스트
=>가상환경 생성
python -m venv myvenv
myvenv\Scripts\activate

=>필요한 패키지 설치(django,djangorestframework.mysqlclient)
pip install django djangorestframework mysqlclient

=>프로젝트 생성
django-admin startproject apiproject .

=>애플리케이션 생성
python manage.py startapp apiapp

=>기본설정 변경:프로젝트의 settings.py파일
Installed_APPS에 애플리케이션을 등록 -apiapp 대신에 자신의 애플리케이션 이름 추가

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "apiapp",
    "rest_framework"
]

=>데이터 베이스 접속 정보를 수정
settings.py에 데이터베이스 내용 변경
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "****",
"USER":"****",
"PASSWORD":"****",
"HOST":"127.0.0.1",
"PORT":"3306"
    }
}

=>시간 대역 수정
settings.py에 Time_zone 수정
TIME_ZONE = "Asia/Seoul"

=>데이터베이스 적용
python manage.py makemigrations

python manage.py migrate
=>실행한 후 테스트
python manage.py runserver 0.0.0.0:80 로 실행한 후 브라우저에서 127.0.0.1 로 접속해서 장고로고가 나오면 확인




2)요청 처리 " 
=>요청을 분할해서 처리
지금까지는 모든 요청 처리를 프로젝트의urls.py에 작성해서 사용했습니다.
요청이 많아지면 프로젝트의 urls.py 파일의 내용이 많아지고 한곳에 내용이 많아지면 소스코드를 읽기가 어려워지고 유지보수가 어렵고 여러명이 동시에 작업하는것이 어렵습니다
url 요청을 분할해서 처리할때는 프로젝트의 urls.py 파일에 django.urls.inclue를 import 하고 path("공통url", include("처리할 모듈 이름"))을 추가해주면 됩니다. 그렇게 하면 공통 url 은 처리할 모듈이름에서 처리하게 됩니다. 

=>example/hello 라는 요청이 오면 메세지를 출력하는 처리를 작성
-프로젝트의 urls.py 파일에 처리를 위임하는 코드 추가

from django.contrib import admin
from django.urls import path
#url의 처리를 다른 모듈에게 위임하고 할 때 사용하는 패키지 import
from django.urls import include


#    path("example/",include("appiapp.urls")),
#위 문장은 example로 시작하는 요청이 오면 apiapp 애플리케이션 urls.py 파일에 처리 위임


urlpatterns = [
    path("admin/", admin.site.urls),
    path("example/",include("appiapp.urls")),
]


-apiapp.views.py 파일에 요청이 오면 처리하는 함수를 작성

from rest_framwork.response import Response
from rest_framework.decorators import api_view

#python에서 @으로 시작하는 단어는 decorator라 하는데
#실제함수를 호출하면 특정내용을 삽입해서 함수를 실행
#반복적으로 사용하는 내용이나 직접 작성하기 번거로운 내용을
#decorator 라고 만듭니다
#GET 요청이 오면 함수 호출
@api_view(['GET']) 

def hello(request):
  return Response("Hello Rest API"))

-apiapp 디렉토리에 urls.py 파일을 생성하고 url을 연결하는 코드를 작성
from django.urls import path
from .views import hello

urlpatterns=[
  path("hello/",hello),
]



3)데이터베이스에 테이블을 생성
=>models.py 파일에 Model class로 부터 상속받는 클래스를 생성

class BOOK(models.Model):
  bid =models.IntegerField(primary_key=True)
  title=models.CharField(max_length=50)
  author=models.CharField(max_length=50)
  publishdate=models.DateField()
  existence=models.BooleanField()


  

=>데이터베이스 반영
python manage.py makemigrations
python manage.py migrate

=>데이터베이스에 접속해서 apiapp_book 테이블이 만들어졌는지 확인
show tables;

4)삽입과 조회
=>개요
삽입을 하는 경우 클라이언트가 삽입할 데이터를 매개변수로 전송하면 서버는 매개변수를 각각 읽어서 모델 글래스를 변환한 후 save 메서드를 호출하면 삽입이 됩니다

rest_framework 에서는 serializer를 정의하면 클라이언트가 전송한 매개변수를 가지고 모델 클래스로 자동변환이 가능합니다.
Serializer은 통신을 할때 객체를 전송할 수 있게 해줌. 기본적으로 바이트나  텍스트만 가능. but 객체를 파일로 만들어서 보내게 해주는게 Serializer

=>apiapp 디렉토리에 serializers.py 파일을 만들고 클라이언트의 매개변수를 Book 모델로 변환하는 Serializer 클래스를 생성

#serializers.py
from rest_framework import serializers
from .models import BOOK

class BookSerializer(serializers.ModelSerializer):
  class Meta:
    model=Book
    #클라이언트에서 입력하는 데이터만 나열
    #아래 나열한 데이터를 입력하면 Book 클래스의 인스턴스 생성
    fields=['bid','title','author','publishdate','existence']



=>데이터를 삽입하는 처리와 전체를 조회하는 함수
 =>서버를 구동하고 브라우저에 주소 입력하고 확인
데이터를 삽입할때 에러가 발생
rest_framework 를 사용할 떄는 데이터를 save할때 is_valid()를 호출해서 유효성 검사 통과후 삽입되도록 해야합니다.   

-views.py에 함수 생성

from rest_framework import status
from rest_framework.generics import get_object_or_404

from .models import Book
from .serializers import BookSerializer

#get과 포스트 모두를 처리
@api_view('GET','POST')
def booksAPI(request):
  #조회(GET)을 요청
  if request.method =='GET':
    #테이블의 데이터를 전부 가져오기
    books=Book.objects.all()
    #출력하기 위해서 브라우저의 형식으로 데이터 변환
    serializer=BookSerializer(books,many=True)
    #출력
    return Response(serializer.data)
    
  #POST 방식의 처리 -삽입하는 경우
  elif request.method =="POST":
    serializer = BookSerializer(data=request.data)
    if seriallizer.is_valid():
      serializer.save()
      return Response(serializer.data)
    return Response(serializer.errors)



=>apiapp 디렉토리의 urls.py 파일에 url과 이전에 만든 함수 연결

from django.urls import path
from .views import hello, booksAPI


urlpatterns=[
  path("hello/",hello),
  path("books/",booksAPI),
]


5)데이터 1개 가져오기
=>데이터 1개를 가져올려면 클라이언트에서 기본키 값을 서버에게 제공해야 하고 서버는 이 값을 읽어서 하나의 데이터를 찾아서 넘겨줘야 합니다.

=>views.py 파일에 데이터를 처리하는 함수 작성

@api_view(['GET'])
def oneBookAPI(request,bid):
  #BOOK 테이블에서 bid 칼럼의 값이 bid인 값을 찾아옵니다
  book=get_object_or_404(Book,bid=bid)
  #출력할수 있도록 변환
  serializer=BookSerializer(book)
  return Response(serializer.data)



=>urls.py 파일에 url과 함수를 연결하는 코드 추가
from .views import hello, booksAPI,oneBookAPI
urlpatterns=[
path("book/<int:bid>",oneBookAPI),]















'Study > PYTHON,Django' 카테고리의 다른 글

Django(2)-데이터베이스 연동  (0) 2024.01.25
Django(1)-웹 프로그래밍 기초  (0) 2024.01.24
Python(4)-OOP심화  (0) 2024.01.19
PYTHON(3)-객체지향(OOP)  (0) 2024.01.09
Python(2)-모듈,패키지  (0) 2024.01.05