본문 바로가기
LG 헬로비전 DX DATA SCHOOL/Python

Django REST API

by 황밤 2023. 7. 27.
728x90
반응형

2023/0727

SMALL

2023.07.26 - [LG 헬로비전 DX DATA SCHOOL/Python] - Django

 

Django

2023/07/26 2023.07.25 - [LG 헬로비전 DX DATA SCHOOL/DATA BASE] - 데이터 베이스 데이터 베이스 2023-07-25 1. 데이터 베이스 1.1) SQR 사용에 따른 분류 RDBMS : 테이블 구조를 이용하는 데이터베이스, SQL을 이용해서

dxdata.tistory.com

저번 Django의 기본적인 내용을 보고 오시면 좋을 겁니다!

기본 적인 내용들은 반복될 예정입니다.

 

출처 : 송준호우

 

 

1. API(Application Programming Interface)

  • 프로그램과 프로그램을 연결시켜주는 매개체
  • 데이터의 형태로 제공될 수도 있고 함수나 클래스 또는 패키지 또는 프레임워크 형태로 제공될 수도 있습니다.
  • Open API : API를 누구나사용할 수 있도록 공개한 것 

2. CSR(Client Side Rending)

  • API Server는 화면 구성은 하지 않고 데이터만 제공하고 클라이언트 프로그램에서 데이터를 받아서 화면 출력을 하게되는데 이런 구조를 Client Side Rendering 이라고 합니다.
  • API Server를 구축할 때 Restful 하게 구성하는 것을 권장

3. REST

  • REpresentational State Transfer 의 약자로 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍쳐의 종류
  • 원칙 :

인터페이스 일관성 : 어떤 기기에서 접근을 하던 동일한 작업은 동일한 URL로 처리

무상태(Stateless) : 클라이언트의 컨텍스트를 서버에 저장하지 않아야 한다.

 

캐싱 기능 활용

계층화

Code on Demand : 기능을 확장할 수 있도록 생성

클라이언트와 서버 분리

 

Client  <->   연결 서버  <-> Middel Ware(Security, Load Balancing) <->  API Server(일을 하고 결과를 생성) <-> Data Server

 


 

4. Rest API Server 프로젝트 생성 및 설정!

 

4.1) 프로젝트 디렉토리 생성

pycharm의 new 프로젝트를 생성하여 가상환경 생성!

 

 

4.2) 필요한 패키지 설치

  • django
  • djangorestframework
  • mysqlclient
pip install django
pip install djangorestframework
pip install mysqlclient

 

4.3) django 프로젝트 생성

  • apiserverproject
django-admin startproject apiserverproject .

 

4.4) django 애플리케이션 생성

  • apiserverapplication
python manage.py startapp apiserverapplication

 

4.5) settings.py 에서 필요한 내용 수정

 

# Application definition

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

 

 

  • 데이터 베이스 접속 정보 수정
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "svng",
        "USER": "root",
        "PASSWORD": "252585",
        "HOST": "127.0.0.1",
        "PORT": "3306"
        
    }
}

 

  • 시간 변경
TIME_ZONE = "Asia/Seoul"

 

 

4.6) 프로젝트 실행

 

python manage.py runserver   (터미널에서 작성)

 

 

4.7) 브라우저에서 접속

 

초기 django의 기본 페이지 형식이 나타납니다.

 


 

5. 프로젝트에 사용할 테이블 생성 및 연결 확인

 

5.1) models.py 파일에 필요한 모델을 작성

 

class Item(models.Model):
    itemid = models.IntegerField(max_length=10)
    title = models.CharField(max_length=50)
    author = models.CharField(max_length=50)
    category = models.CharField(max_length=10)
    pages = models.IntegerField()
    price = models.IntegerField()
    published_date = models.DateField()
    description = models.CharField(max_length=150)

 

5.2) models.py 의 변경 내용을 데이터베이스에 적용

python manage.py makemigarations
python manage.py migrate

 

 

5.3) 변경 내용이 적용되었는지 확인

 

use 데이터베이스이름;



show tables;



desc 테이블이름(애플리케이션이름_모델이름);

 


6. 직렬화

  • Serializable(직렬화) : 프로그래밍 언어에서 만든 객체를 전송하기 위한 작업
  • Client 에서 받은 데이터를 Python 객체로 변환해주고 Python 객체를 Client에게 전송하기 위한 JSON 문자열로 변환해주는 역할을 수행
  • 이 작업 수행시, Response로 return 해야하고, 이 작업을 수행하지 않을 시, JsonResponse로 return 해주면 된다.

 

  • 애플리케이션에 serializers.py 파일을 만들고 작성
from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers) :
    class Meta :
        model = Item
        fields = ['itemid', 'title', 'author',
                  'category', 'pages', 'price',
                  'published_date', 'description']

 


 

 

7. 샘플 URL 처리

 

7.1) 프로젝트 urls.py 파일에 가서 URL을 처리할 함수 나 클래스와 URL을 연결

 

  • 프로젝트의 urls.py 에 직접 연결을 시키게 되면 애플리케이션이 여러 개 일 때 코드가 너무 길어지고 가독성이 떨어짐.
  • 따라서 각 Application이 URL을 처리하도록 설정하는 것이 좋다.
기존 : path("URL", 함수) 형태로 직접 연결하여 사용
from django.contrib import admin
from django.urls import path, include



urlpatterns = [
    path("admin/", admin.site.urls),
    #example로 시작하는 url은 apiserverapplicaion.urls.py에서 처리하도록 설정
    path("example/", include("apiserverapplication.urls"))

 

 

 

7.2) 애플리케이션에 urls.py 파일을 추가하고 URL 과 처리할 함수나 클래스를 연결

from django.contrib import admin
from django.urls import path
from .views import helloAPI

urlpatterns = [
    #/example/hello/ 요청이 오면 helloAPI 함수가 처리
    path("hello/", helloAPI)
    
    
#아직 helloAPI를 만들지 않아 에러
#그럼 이제 helloAPI 만들러 고고!

 

 

 

7.3) 애플리케이션의 views.py 파일에 helloAPI 함수를 작성

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.decorators import api_view
# Create your views here.


#GET 요청만 처리
@api_view(['GET'])
def helloAPI(request):
    return Response("HELLLO REST API")

 

 

7.4) 서버를 재실행하고 브라우저에서 확인 (로컬 주소 + /example/hello/)

실행 결과

여기서 잠깐!

example/ 을 호출후 hello/를 호출하였을 때 나타나는 기능만 구현함.
따라서 example/만 치거나, hello/만 치면 아무런 기능이 구현되지 않아 page not found 에러가 발생한다 

 

 

7.5) Response 클래스

 

  • 응답 결과를 위한 클래스
  • 첫번째 매개변수는 데이터이고 status는 상태 코드
  • 첫번째 매개변수만을 이용하면, 성공한 경우에는 괜찮으나 실패할 경우 어떤 이유로 실패했는지 알 수가 없음.
  • 상태코드
200 번대 - 정상
300 번대 - Redirect 중
400 번대 - Client 오류 (403: Forbidden -> 권한 부족, 404 -> URL오류)
500 번대 - Server 오류

 

 

 

8. 데이터 삽입 처리 : 삽입은 POST방식

 

8.1) 처리할 함수를 생성 - views.py

 

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.decorators import api_view
# Create your views here.
from serializers import ItemSerializer
from rest_framework import status
#GET 요청만 처리
@api_view(['GET'])
def helloAPI(request):
    return Response("HELLLO REST API")


@api_view(['POST'])
def itemsAPI(request):
    #클라이언트가 전송한 데이터를 모델이 사용할 수 있는 데이터로 변환
    serializer = ItemSerializer(data = request.data)
    #유효성 검사
    if serializer.is_valid():
        serializer.save() #데이터 저장
        #성공시, 전송한 데이터를 다시 전송
        return Response(serializer.data, status.HTTP_201_CREATED)

    #실패시 처리
    Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

 

 

 

8.2) URL과 함수를 연결 - urls.py

 

from django.contrib import admin
from django.urls import path
from .views import helloAPI, itemsAPI

urlpatterns = [
    #/example/hello/ 요청이 오면 helloAPI 함수가 처리
    path("hello/", helloAPI),
    #example/fbv/items 요청이 오면 itemsAPI 함수가 처리
    path("fbv/items", itemsAPI)
]

 

serializers.py

from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ['itemid', 'title', 'author',
                  'category', 'pages', 'price',
                  'published_date','description']

서버 실행 후 아래의 데이터 삽입 -> 200 번대의 결과 -> 성공

{
"itemid":1,
"title":"POST",
"author":"writer",
"category":"분류",
"pages":300,
"price":12000,
"published_date":"2023-07-27",
"description":"설명"
}

#post 에 넣을 데이트

 

 

 

8.3) 실행 한 후 브라우저에 lacalhost:8000/example/fbv/books 를 입력

 

  • 화면의 상자에 데이터를 입력하고 POST를 눌러서 데이터가 전송되는지 확인
  • 에러가 발생하면 urls 의 url 과 views의 함수 이름을 먼저 확인하고 models와 serializers에 작성한 클래스의 필드 이름을 확인하고 브라우저에서 입력한 이름과 같은지 확인.
  • models에 작성한 모델과 serializers에 입력한 내용은 처음 한 번만 확인하면 됩니다.

 

 

 

9. 전체 데이터 가져오기 구현 - GET

 

9.1) views.py 파일의 itemAPI 함수만 수정

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import ItemSerializer
from rest_framework import status
from .models import Item


@api_view(['POST','GET'])
def itemsAPI(request):
    #전송 방식을 확인하는 방법은 request.method를 확인하면 됩니다.
    if request.method=='GET':
        #전체 데이터 가져오기
        serializer = ItemSerializer(data=request.data)
        items = Item.objects.all()
        return Response(serializer.data, status=status.HTTP_200_OK)
        
        
    elif request.method == 'POST':
        serializer = ItemSerializer(data=request.data)
        if serializer.is_valid():
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

 

9.2) URL은 동일하게 출력되는지 확인

완료!

 


 

10. 데이터 1개 가져오기

 

  • 기본키 값을 매개변수로 받아야 한다.

매개변수 1개를 받을 때는 직접 입력하지 않고 URL 뒤에 붙여서 전송.

 

  • 애플리케이션 urls.py 에 URL을 처리할 수 있는 함수를 등록
  • views.py 에 itemAPI 함수를 추가
#urls.py 속 urlpatterns에 추가


    #itemid 값을 받아, 1개의 데이터를 찾아오는 것을 bookAPI함수가 처리
    path("fbv/book/<int:itemid>", itemAPI)





#views.py 내용에 추가

#기본키를 가지고 데이터를 1개 찾아오는데 없으면 404에러 발생
from rest_framework.generics import get_object_or_404
@api_view(['GET'])
def itemAPI(request, itemid) :
    #기본키를 바탕으로 데이터 1개 가져오기
    item = get_object_or_404(Item, itemid=itemid)
    serializer = ItemSerializer(item)
    return Response(serializer.data, status=status.HTTP_200_OK)

 

 

11. Web Client 에서 서버에 데이터 요청

 

11.1) ajax(Asynchronous Javascript XML)

 

  • 비동기적으로 Server에게 데이터를 요청하는 것
  • 한 번 요청하고 응답이 오면, 연결이 해제됩니다.

 

 

11.2) Web Socket

  • TCP 연결을 이용해서 Web Server 와 데이터를 주고 받을 수 있는 HTML5 API
  • 연결 한 후 명시적으로 close()를 호출하지 않으면 연결 유지
  • ajax는 헤더의 크기가 websocket 보다 큼
  • 짧은 메시지를 자주 전송하는 경우에는 websocket이 ajax 보다 효율적

web socket 출처 : 알유 프린스 송? 예아

 

 

11.3) SSE(Server Sent Event - Web Push)

 

  • 서버에게 구독 신청을 하면 서버가 데이터를 일방적으로 보내주는 방식
  • 구독 신청을 하면 이후에는 데이터 요청을 하지 않아도 데이터를 받을 수 있습니다.
  • 알림을 받는 방식입니다.

APNS(Apple Push Notification Service)

FCM(Firebase Cloud Messaging Service)

 

통신의 과정/출처 : 송쥬노안정주뇨늘정쥬는송쥬노

 

 

11.4) 모바일 푸시

 

  • 스마트 폰 애플리케이션에서 알림을 받고자 하는 경우 아래 2개 중 하나를 학습

APNS(Apple Push Notification Service)

FCM(Firebase Cloud Messaging Service)

 

 


 

12. 비동기 통신

 

 

 

12.1) 구현 방법

 

  • ajax 이용 : XMLHttpResquest 이용
  • Promise 이용
  • Fetch API 이용 - 가장 권장
  • axios 같은 외부 라이브러리 이용 - 가장 많이 사용

 

 

12.2) ajax

 

  • 객체 생성
new XMLHttpRequest()

 

  • 객체 속성
responseText : XML 이외의 데이터를 받았을 때 데이터

responseXML : XML 데이터를 받은 경우 받은 내용

 

  • 객체의 메서드
setRequestHeader(헤더이름, 데이터): 헤더 설정
open(전송방식, 전송할 URL, 비동기 전송 여부): 연결 설정
send(데이터) : 요청 전송
sendAsBinary(데이터): 바이너리 데이터(파일) 전송시 호출

 

  • 이벤트
load : 데이터를 전부 전송받으면 호출되는 이벤트

error : 데이터를 전송받는 도중 에러가 발생한 경우 호출되는 이벤트

 

 

12.3) 실습을 위해서 화면 생성

 

  • 프로젝트의 urls.py 파일에 요청을 생성
from django.contrib import admin
from django.urls import path, include

from apiserverapplication import ajax

urlpatterns = [
    path("admin/", admin.site.urls),
    #example로 시작하는 url은 apiserverapplicaion.urls.py에서 처리하도록 설정
    path("example/", include("apiserverapplication.urls")),
    path("ajax/", views.ajax)

 

 

  • 애플리케이션의 views.py 파일에 ajax 함수를 생성
#views 파일에서 ajax 함수 생성
def ajax(request):
    return render(request, 'ajax.html')

 

  • templates 디렉토리 생성 후, ajax.html 생성
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AJAX</title>
</head>
<body>
    <div id="display"></div>
<button id="allbtn">전체 데이터 가져오기</button>
</body>
<script>
    document.getElementById("allbtn").addEventListener("click",
        (e) => {
        let request = new XMLHttpRequest();
        //출력하는 함수에 객체 대입하면 toString 메서드를 호출합니다.
            //python은 __str__ 메서드를 호출합니다.
            //위 메서드를 재정의하면 그 내용이 출력되지만, 재정의를 하지 않으면
            //기본적으로 설정된 값이 출력된다.
            alert(request)

            //요청 생성
            //http://localhost:8000/example/fbv/items
            //현재는 http://localhost:8000/ajax
            request.open('GET', '../example/fbv/items', true);
            //요청전송
            request.send('')
            //응답이 오면 호출
            request.addEventListener('load', (e) => {
                alert(request.responseText)
            })
    })

 

 

 

  • 실행결과 :

실행 결과

 

 

이후 ajax.html 의 페이지를 수정한다면 조금더 괜찮은 페이지를 만들 수 있다.

 

 

저 버튼을 클릭하게 되면, 

 

 

ajax를 통해 클라이언트의 데이터 요청에 대한 전달 구현

 

 

 

이렇게 데이터를 가져올 수 있음을 확인할 수 있다.

 

 

 

12.4) 해당 문자열을 JavaScript 데이터로 변환! 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AJAX</title>
</head>
<body>
    <div id="display"></div>
<button id="allbtn">전체 데이터 가져오기</button>
</body>
<script>
    document.getElementById("allbtn").addEventListener("click",
        (e) => {
        let request = new XMLHttpRequest();
        //출력하는 함수에 객체 대입하면 toString 메서드를 호출합니다.
            //python은 __str__ 메서드를 호출합니다.
            //위 메서드를 재정의하면 그 내용이 출력되지만, 재정의를 하지 않으면
            //기본적으로 설정된 값이 출력된다.
            alert(request)

            //요청 생성
            //http://localhost:8000/example/fbv/items
            //현재는 http://localhost:8000/ajax
            request.open('GET', '../example/fbv/items', true);
            //요청전송
            request.send('')
            //응답이 오면 호출
            request.addEventListener('load', (e) => {
                //문자열
                //alert(request.responseText)

                //문자열을 자바스크립트 데이터로 변환
                // 객체들의 배열
                let data = JSON.parse(request.responseText);
                let txt = '';
                for(let item of data){
                    txt += '<h5>' + item.title + '</h5>';
                    txt += '<p>' + item.price + '</p>';
                    txt += '<p>' + item.published_date + '</p>';

                }
                document.getElementById('display').innerHTML =
                    txt;
            })
    })

</script>

실행결과 :

화면에 출력 결과

 

  • 함수 생성 시 여러 개의 데이터 리턴
def f() :
     result = [  ]
     result 값 대입
     return result

 

  • 1개 리턴하는 함수
def f() :
    result = None
    result 값을 대입
    return result

 

12.5) ajax.html을 수정하여 데이터를 입력받아 해당하는 값을 가져오는 프로그램 구현

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AJAX</title>
</head>
<body>
    <div id="display"></div>
<button id="allbtn">전체 데이터 가져오기</button>
itemid <input type="text" id="itemid" />
<button id="getbtn">데이터 1개 가져오기</button>
</body>
<script>
    document.getElementById("getbtn").addEventListener('click',
        (e) => {
        // 아이디가 itemid인 입력의 값을 가져온다
            let itemid = document.getElementById("itemid").value;
            //alert(itemid);

            let request = new XMLHttpRequest();
            request.open('GET', '../example/fbv/book/' + itemid, true);
            request.send('');
            request.addEventListener('load', (e) => {
                //없는 번호인 경우는 detail에 NotFound 값이 넘어옵니다.
                //alert(request.responseText)

                // Parsing 진행
                let data = JSON.parse(request.responseText);
                //alert('detail' in data)
                let txt = "";
                if('detail' in data){
                    // 데이터가 없을 때 처리
                    txt = "<h3>해당 되는 itemid가 없습니다.</h3>";


                }else {
                    //데이터가 있을 때 처리
                    txt += "<h3>" + data.itemid + "</h3>"
                    txt += "<h3>" + data.title + "</h3>"
                    txt += "<h3>" + data.price + "</h3>"

                }
                document.getElementById('display').innerHTML = txt;
            })
        });

이제 

 

실행시켜서 어떤 table에 id 값을 입력하고, 그 데이터가 있으면 출력, 없으면 해당 되는 id가 없다는 문장을 출력하는지 확인해보겠습니다.

 

 

  • 해당되는 id가 존재하는 번호로 출력

존재하는 id의 데이터를 출력

 


 

 

  • 해당되는 id가 없는 번호로 출력

존재하지 않는 id로 출력

## 입력받은 데이터 null 여부 확인 다른 방법

x = " ";
if(x.trim().length == 0);

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

오늘은 여기까지!
오늘 하루 모두 내일의 자신에게 혼나지 않을 삶을 보냈나요? 하루 하루만 보면 아무것도 아닌 듯 보이나
그 하루가 모이면 1달, 1년이 됩니다.
하루하루 소중히 우리 모두 더 나아가려 한 발자국 내밀어 봅시다
반응형
LIST

'LG 헬로비전 DX DATA SCHOOL > Python' 카테고리의 다른 글

Python 데이터 분석 Pandas 2  (0) 2023.08.09
데이터 분석 Python (with numpy & pandas)  (0) 2023.08.07
Django  (0) 2023.07.26
Python 예외처리 / File handling  (0) 2023.07.14
파이썬 Data Type 및 처리  (0) 2023.07.11