본문 바로가기
Programming/Django

[게르만 민족 프로젝트]Django로 카카오페이 API 사용하기

by IN.0 2020. 4. 24.
반응형

SSAFY 스터디원들과 Django 토이 프로젝트 배달 웹을 만들어보기로 했다.

총 4명이 진행하며, 각자 역할은 사다리 타기로 정했다. 나는 결제 관련 구현을 담당하게 되었다.

수업 중에 공공 API 맛보기로 조금 다뤄본 것 말고는 API를 사용해본 적이 없어서 걱정이 많았는데,

Kakao Developers 사이트와 구글 신이 도움이 많이 되었다.

그러나 검색 결과 Django로 카카오페이를 구현한 글이 거의 없어서 내가 작성해본다.

아직 주니어라고 말하기에도 많이 부족한 초보지만, 다른 초보분들께 도움이 되면 좋겠다.


* Django 프로젝트 생성 및 app 생성 과정은 생략한다.

1. 결제 버튼이 있는 페이지를 연결할 url 생성

from django.urls import path
from . import views

app_name = "kakaopay"

urlpatterns = [
    path('', views.index, name="index"),
]

app_name은 kakaopay로 설정했다.

현재 작성한 url.py는 결제 app 안에 속한 url 파일이고, 루트 url에서 이 url을 kakaopay로 받고 있다.

즉, 주소/kakaopay/ 로 접속하면 views.index로 연결된다.

 

2. views.py 설정

from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'kakaopay/index.html')

html을 연결해주는 기본 설정만 했다.

그리고 html 파일은 이렇게 구성되어있다.

 

3. html 작성

{% extends 'base.html' %}
{% block content %}
  <div class="row mt-5">
    <h1 class="col-12 text-center my-5">KAKAO PAY</h1>
    <form method="post" class="col-12 text-center">
      {% csrf_token %}
      <button class="btn btn-warning">카카오페이로 결제하기</button>
    </form>
  </div>
{% endblock %}

버튼을 눌렀을 때 카카오페이가 돌아가는지 확인하는 것이 목적이기 때문에 제목과 버튼만 넣었다.

여기서 중요한 것은 form 태그이며, 메서드 설정을 반드시 post로 하고 바로 밑에 csrf_token을 달아야 한다.

post는 csrf 공격(사용자의 의지와 무관하게 삭제, 수정, 등록 등을 요청)을 방어하기 위해 csrf 토큰을 필수로 요구한다.

form 안에서 button 태그는 type이 commit인 input 태그와 동일한 역할을 한다.

그리고 이 버튼을 눌렀을 때, 같은 주소로 POST 요청을 보내므로 다시 view.py를 수정해야 한다.

 

4. views.py 수정

from django.shortcuts import render, redirect
import requests

# Create your views here.
def index(request):
    if request.method == "POST":
        URL = 'https://kapi.kakao.com/v1/payment/ready'
        headers = {
            "Authorization": "KakaoAK " + "Kakao Developers에서 생성한 앱의 어드민 키",   # 변경불가
            "Content-type": "application/x-www-form-urlencoded;charset=utf-8",  # 변경불가
        }
        params = {
            "cid": "TC0ONETIME",    # 테스트용 코드
            "partner_order_id": "1001",     # 주문번호
            "partner_user_id": "german",    # 유저 아이디
            "item_name": "연어초밥",        # 구매 물품 이름
            "quantity": "1",                # 구매 물품 수량
            "total_amount": "12000",        # 구매 물품 가격
            "tax_free_amount": "0",         # 구매 물품 비과세
            "approval_url": "결제 성공 시 이동할 url",
            "cancel_url": "결제 취소 시 이동할 url",
            "fail_url": "결제 실패 시 이동할 url",
        }

        res = requests.post(URL, headers=headers, params=params)
        request.session['tid'] = res.json()['tid']      # 결제 승인시 사용할 tid를 세션에 저장
        next_url = res.json()['next_redirect_pc_url']   # 결제 페이지로 넘어갈 url을 저장
        return redirect(next_url)


    return render(request, 'kakaopay/index.html')

 

갑자기 코드가 많아졌지만, 차근차근 살펴보자.

일단 request method가 POST일 때(사용자가 결제하기 버튼을 눌렀을 때)는 if문 안의 내용을 처리하고 redirect를 리턴한다.

request method가 POST가 아닐 때(그냥 결제 페이지로 접속했을 때)는 아까와 같이 실행해준다.

if문 안으로 들어가 보면, URL이 제일 먼저 설정되어 있다. 카카오페이 문서에 나와있는 URL이다.

이 URL은 각 단계에서 맨 뒤의 요소(ready)만 바뀌므로, 추후에 따로 변수 지정하여 하드코딩을 줄일 수 있을 것 같다.

headers라는 dict를 만들어 요청 시 헤더에 보낼 필수 값을 넣는다. 헤더에는 주로 params에 들어가기에는 민감한 정보들을 담아준다. Authorization에 필요한 admin key는 Kakao Developers에 가입하여 앱을 생성하면 받을 수 있다.

Content-type은 무엇을 의미하는지 아직 모르겠다.. 공식 문서에 있는 것을 그대로 가져왔다.

이제 params에 값을 넣어준다. 나는 필수 값만 넣었지만, 공식문서에 가보면 다른 파라미터도 많이 있다.

그리고 지금은 DB와 연동이 안되어있어서 직접 값을 타이핑했지만. DB를 연결하면 결제버튼을 누르는 순간 값을 넘겨받아와야 한다.

그리고 import 한 requests로 URL, headers, params를 지정하여 post 요청을 보낸다.

여기서, requests는 주로 http 통신을 위해 사용하는 것이고 request는 서버 내부에서 통신하기 위해 사용한다.

요청을 보내면 응답이 올 텐데, 그것을 res라는 변수에 담는다.

그리고 응답(response) 받은 것들 중에 tid는 나중에 결제 승인 시 필요하므로 세션에 남겨준다.

쿠키와 세션 중에 어디에 남길지 고민했는데, 그래도 나름 중요한 정보라 생각해서 세션에 보관했다.

참고로 res.json()이라는 코드는 dict형이라 대괄호로 key값을 넣어 value를 반환받을 수 있다.

그리고 session도 dict 형태이기 때문에 대괄호로 key를 설정하고 value를 넣어주었다.

next_url에는 카카오 결제창으로 넘어갈 url을 저장해준다. 그리고 redirect로 해당 url에 넘어간다.

 

5. 지금까지 진행한 것이 돌아가는지 체크

 

index.html

결제 버튼이 있는 페이지다. 저 버튼을 누르면~

카카오 결제 페이지

이렇게 뜬다.

그리고 번호와 생년월일을 입력하고 결제 요청을 누르면

모바일 결제하기

이렇게 카카오톡으로 결제 요청 메시지가 온다.

요청중

웹의 상태는 이러하다.

결제를 누르면 결제 완료 페이지로 넘어가는데,

중요한 건 완료 페이지가 떴다고 해서 결제가 된 것은 아니다.

 

6. 결제 승인 단계

나는 결제 승인에 넘어가는 페이지를 approval.html로 정의하고, views.py에서도 같은 이름으로 함수를 생성하였다.

사전에 url도 연결해주었다.

# 앞의 코드는 생략

def approval(request):
    URL = 'https://kapi.kakao.com/v1/payment/approve'
    headers = {
        "Authorization": "KakaoAK " + "자신의 admin key 넣기",
        "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
    }
    params = {
        "cid": "TC0ONETIME",    # 테스트용 코드
        "tid": request.session['tid'],  # 결제 요청시 세션에 저장한 tid
        "partner_order_id": "1001",     # 주문번호
        "partner_user_id": "german",    # 유저 아이디
        "pg_token": request.GET.get("pg_token"),     # 쿼리 스트링으로 받은 pg토큰
    }

    res = requests.post(URL, headers=headers, params=params)
    amount = res.json()['amount']['total']
    res = res.json()
    context = {
        'res': res,
        'amount': amount,
    }
    return render(request, 'kakaopay/approval.html', context)

index와 마찬가지로 처리하되, 들어가는 params값이 다르다.

먼저, 아까 세션에 저장한 tid를 불러와 "tid"의 value로 넣어야 하고,

pg_token은 주소창에 쿼리 스트링으로 받기 때문에 request.GET.get을 사용해 값을 받는다.

주문 id와 유저 id는 지금 하드코딩 상태이지만, 나중에 쿠키나 세션으로 받아 처리할 예정이다.

그리고 response 받는 값 중에 amount는 dict 형태로 구성되어 있으므로 total(총금액)은 따로 저장해준다.

그리고 context에 담아 approval.html에 같이 넘긴다.

 

7. 결제 승인 페이지

{% extends 'base.html' %}
{% block content %}
  <div class="mt-5 pt-5 row justify-content-center">
    <h2 class="text-center my-5 col-12">결제가 완료되었습니다!</h2>
    <div class="col-4 p-5 bg-light">
      <h3 class="text-center my-5">주문자 정보</h3>
      <div>
        <div class="my-3 row"><div class="h5 col-6">주문번호</div><div class="h6 col-6 text-right">{{ res.partner_order_id }}</div></div>
        <div class="my-3 row"><div class="h5 col-6">상품명</div><div class="h6 col-6 text-right">{{ res.item_name }}</div></div>
        <div class="my-3 row"><div class="h5 col-6">결제금액</div><div class="h6 col-6 text-right">{{ amount }}원</div></div>
        <div class="my-3 row"><div class="h5 col-6">결제승인시각</div><div class="h6 col-6 text-right">{{ res.approved_at }}</div></div>
      </div>
      <div class="mt-5 pt-3 text-center">
        <a href="#" class="btn btn-warning">메인으로 돌아가기</a>
      </div>

    </div>

  </div>

{% endblock %}

각 요소들은 DTL 형식으로 값을 받아준다.

명시한 값 말고도 받을 수 있는 값이 많다. 공식 문서에 잘 정리되어 있다.

 

8. 결제 승인 확인

approval.html

이렇게 결제 페이지가 잘 뜬다!

그리고 카카오톡으로 결제가 완료되었다는 메시지도 날아온다.

 


여기까지 Django에서 Kakaopay API를 사용하는 방법에 대해 알아보았다.

아직 DB와 연결도 안 되어있고, 하드 코딩한 부분도 많지만

기능 구현은 얼추 끝내서 마음이 편하다 ㅎㅎ

다음에 다른 API도 사용해볼 수 있겠다는 자신감도 생겼다.

 

2탄 보러가기 ↓

https://in0-pro.tistory.com/27

 

[게르만 민족 프로젝트]Django로 카카오페이 API 사용하기2

프로젝트를 어느 정도 진행한 후 지난번에 작성한 카카오페이 API 사용 후기와 달라진 점이 많아서 2탄을 만들었다 지난번 게시글 ↓↓↓↓↓↓↓↓ https://in0-pro.tistory.com/16 [게르만 민족 프로젝�

in0-pro.tistory.com

 

반응형

댓글