본문 바로가기
[ 빅데이터 ]

[빅데이터] 홈페이지 만들기(2) : 파이썬으로 로그인/로그아웃 데모 앱 만들기(오라클 연동)

by 히앤님 2020. 10. 16.
반응형
SMALL

리눅스에서 jupyter notebook를 실행하고 윈도우에 설치된 오라클 11g와 연동하는 것까지 해보았다.

 

▼저번 포스팅에서 해본 파이썬 - 오라클 연동 정리(링크)

더보기

방법을 간단히 요약하자면,

 

1) 오라클 connection 연결

2) connection이 cursor 객체 가져옴(연결도구)

3) cursor 객체의 fetch메서드를 이용해서 데이터를 서버로부터 가져온다.

4) cursor 객체의  execute() 메서드를 사용해서 파이썬에 입력한 SQL 문장을 오라클 DB 서버로 보낸다.

5) 주고받는 것이 완료되면 connection 객체의 commit() 메서드를 사용해서 데이터를 확정한다.

6) connection.close()를 해서 오라클과 연결을 끊는다.

 

즉, 정리하자면

오라클 수입 : import cx_Oracle as ora
오라클 Connection 연결 : conn = ora.connect('kosmorpa/test00@192.168.0.122:1522/orcl')
Cursor 불러오기 :  cursor = conn.cursor()
a) SQL 입력문장 -> 오라클 DB : cursor.execute( 전송할 sql 문장 )
b) 오라클 DB 데이터 -> 파이썬 : cursor.fetch*****()
Cursor 닫기 : cursor.close()
오라클 DB 저장 : conn.commit()
오라클 연결 끊기 : conn.close()

이걸 이용해서 파이참(PyCharm)에서 DB를 원래 했던 sqlite가 아닌 윈도우에 설치 되어있는 오라클과 연동해서 해보도록 하자.


 

준비된 템플릿에 회원가입 창과 아이디 중복 확인 프로그램을 만들었었다.

 

이번엔 로그인 앱을 만들어 web1과 연결해보자.

 

## web1에 있는 static 파일을 이용해서 추후 web1에 템플릿 디자인으로 적용해보기.

 


[ login/logout 웹 페이지 기능 구현하기 ]


1. login 앱 만들기

늘 하던대로 login > templates > login > index.html 파일 생성

python manage.py startapp login

 

2. index.html 파일 만들기

회원가입(앞선 포스팅 web1에서 만들었던 tripmember를 링크)과 로그인 폼에는 링크를 걸어두었다.

서버 구동을 확인한 후 로그인 폼(loginform)을 만들러 갈 예정.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index.html</title>
    <style>
        ol, ul {list-style:none;}
        ul li { float:left; margin-left:2px; background:pink}
    </style>
</head>
<body>
    <h1>로그인/로그아웃 데모</h1>
    <span>추후 web1에 템플릿 디자인으로 적용하세요.</span>
<nav id="menu">
    <header class="major">
        <ul>
            <li><a href="main">Home</a> </li>
            <li><a href="survey">설문조사</a> </li>
            <li>김길동님 반갑습니다. </li>
            <li><a href="logout">로그아웃</a> </li>
            <li><a href="/web1/tripmember">회원가입</a> </li>
            <li><a href="loginform">로그인폼</a> </li>
        </ul>
    </header>
</nav>
</body>
</html>

3. 뷰 추가(view.py)

이제 이쯤이야 쉽다. 첫페이지 추가

4. urls.py 만들고 내용 추가

5. config/setting 추가

6. config/urls 추가

7. 서버 구동 및 index.html 파일 열기

대충 이런모양이다.

기본 세팅 끝.


본격적으로 첫 페이지의 로그인 폼을 만들러 가자.


 

8. login.html 만들기

index에 web1에서 썼었던 로그인폼 그대로 가져와서 내용 추가하자.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login.html</title>
    <style>
        ol, ul {list-style:none;}
        ul li { float:left; margin-left:2px; background:pink}
    </style>
</head>
<body>
    <h1>로그인 페이지</h1>
    <span>추후 web1에 템플릿 디자인으로 적용하세요.</span>
<nav id="menu">
    <section id="main">
        <header>
            <h2>StarTrip</h2>
            <form method="post" action="">
                {% csrf_token %}
                <div class="fields">
                    <div class="field">
                        <input type="text" name="id" id="id" value="" placeholder="ID"
                        style="text-transform :lowercase"/>
                    </div>
                    <div class="field">
                        <input type="password" name="pwd" id="pwd" placeholder="Password" />
                    </div>
                </div>
                <ul class="actions special">
                    <li><input type="submit" value="로그인" class="primary"/></li>
                </ul>
                <div><span style="color:red;">{{error}}</span> </div>
            </form>
        </header>
    </section>
</nav>
</body>
</html>

 

9. views.py로 와서 추가

login.html를 loginform 이름으로 정의하자.

여기서는 if문을 사용해서 loginform에 대해 1) 전송방식 구분 2) Session 유무에 따른 구분 을 두자.

 

▼왜 갑자기 세션이 나와?

더보기

갑자기 세션이 등장했다.(두둥탁)

JSP에서 쓰던 Session에 대한 개념을 여기에 정리해보고자 한다.

 

원래 HTTP는 비연결성 프로토콜(stateless)이기 때문에 전단계의 데이터 요청과 다음 데이터 요청이 관련이 없다. 이렇게 되면 항상 새롭게 매번, 데이터를 요청하고 받아와야 하기 때문에, 세션과 쿠키가 등장했다. 세션은 웹 컨테이너, 쿠키는 웹 브라우저에 상태 유지를 위한 정보를 저장한다.

 

예시를 들어보자.

원래 회원가입 절차는 사용자가 무조건 각 단계를 순차적으로 넘어와야 한다. HTTP로 구현을 하게 되면 모든 페이지에 대해서 URL(/step1/, /step2/, /step3/)로 접근할 수 있다. 하지만 세션을 사용하면 각 정보를 저장하기 때문에 /step1/ => /step2/ => /step3/ 순서로만 접근이 가능하게 바꿀 수 있다. 각 단계의 순서대로 접근하지 않으면 403 Forbidden 페이지를 볼 수 있을 것이다.

 

Django에서는 기본적으로 세션 관리 기능을 제공해주고, request.session 이라는 딕셔너리 객체에 필요한 값을 저장하고 읽어올 수 있다. view.py 에서 return을 걸어주기 전에 if문을 통해 step1에서 step2로만 가게끔(나머지는 false가 되게끔) 만들면 접근 순서를 제어할 수 있다. (출처)


▽코드 문장으로 읽기

더보기

loginform 두가지 if문이 중첩되어 있다.

1) 만약 user_id 가 request.session(=딕셔너리 객체에 필요한 값을 저장하고 읽어옴) 안에 있다면 /login 페이지로 이동해라.

2) 만약 요청방법이(로그인 폼에서 submit 버튼 누르고 id 비번 값이 넘어가는는 방법이) POST이면?

   n -> login/login.html로 가라.

   y -> post 방식으로 id를 요청해서 user_id 안에 넣어라.(비밀번호도) 그 후에 print해라.

   (db_id와 db_pwd 는 아직 db 연동을 하지 않았기 때문에 임의로 정해놓았음)

   2-1) 그 후 또다른 if문

      만약 db 안에 user 의 아이디와 비밀번호가 있다면? y -> 로그인 성공 띄우고 /login으로 가라.

      n -> 로그인 실패 띄우고 에러메시지 띄우고,  login/login.html로 가라.


from django.shortcuts import render, redirect

# Create your views here.
from django.views.decorators.csrf import csrf_protect


def home(request):
    return render(request, "login/index.html")


# 1. 전송방식 구분
# 2. Session 유무에 따른 구분
@csrf_protect
def ldginform(request):
    # 세션에 등록한 값이 존재하는가?
    if 'user_id' in request.session:
        return redirect('/login')

    if request.method == 'POST':
        user_id = request.POST['id']
        user_pwd = request.POST['pwd']
        print('user_id: ', user_id)
        print('user_pwd: ', user_pwd)
        db_id = 'xman'
        db_pwd = '11'
   
   # 중첩 if 문   
        if user_id in db_id and user_pwd in db_pwd:
            print('로그인 성공')
            request.session['user_id'] = db_id
            request.session['user_name'] = '김길동'
            return redirect('/login')
        else:
            print('로그인 실패')
            msg = '아이디나 비밀번호가 잘못되었습니다.'
            return render(request,"login/login.html",{"error":msg})
    return render(request, "login/login.html")

10. 로그아웃도 추가(view.py)

세션을 삭제하고 나간다.

# 로그아웃 처리
def logout(request):
    del request.session['user_id']
    del request.session['user_name']
    return redirect('/login')

당연히 view에 정의했으니 길 터줘야 한다.

11. urls.py에 path 추가

간-단

12. 세션 나눠주기(index.html)

views.py에서 if문으로 상황에 따라 경로를 만들어주었다.

첫 페이지인 index.html에서도 각 부분에 따른 세션을 나눠줘야 한다. 각각 if / else를 나눠 표시해주자.

왜??

        <ul>
            <li><a href="main">Home</a> </li>
            <li><a href="survey">설문조사</a> </li>

            {% if 'user_id' in request.session %}
            <li>{{request.session.user_name}}님 반갑습니다. </li>
            <li><a href="logout">로그아웃</a> </li>
            {% else %}
            <li><a href="/web1/tripmember">회원가입</a> </li>
            <li><a href="loginform">로그인폼</a> </li>
            {% endif %}
        </ul>

 

[ 실습 예제 ]

[ cx_oracle과 연동해서 로그인 프로그램 완성하기 ]

def getLoginChk() 함수를 만들어서 인자 정의 및 구현을 한다.

 

13. 로그인을 체크하는 모델 추가(models.py)

오라클과 연결하고 sql문을 전송 및 값을 받아온다. datas의 경우 fetchall()로 모든 결과를 리턴한다.

[ Fatch 종류 ]

fetchall()의 경우 결과를 모두 리턴
fetchone()의 경우 하나의 row를 리턴
fetchmany(num rows)의 경우 rows의 숫자 만큼 리턴을 한다.

 

from django.db import models
import cx_Oracle as ora

database = 'kosmorpa/test00@192.168.0.122:1522/orcl'
# Create your models here.

# select count(*) cnt, name from member_table where id='xman' and pwd='121'
# 인자값이 여러개일 경우 함수의 인자를 늘여서 사용하게 되는 부분을 리팩토링한다.
def getLoginChk(**kwargs):
    conn = ora.connect(database)
    cursor = conn.cursor()
    sql_select = "select count(*) cnt, name from member_table" \
                 " where id=:id and pwd=:pwd group by name"
    cursor.execute(sql_select, id=kwargs['id'], pwd=kwargs['pwd'])
    datas = cursor.fetchall()
    cursor.close()
    conn.close()
    return datas

 

 

▼kwargs와 args

더보기

kwargs와 args는 파이썬에서 기존의 함수에 파라미터를 추가하여 새로운 함수를 만드는 경우에 사용한다.

별표시(***)의 경우, 여러 개의 인수를 받을 때, 키워드 인수를 받을 때 사용하는 표시이다.

 

1) **kwargs (keyword argument)

 

**kwargs는 {'키워드': '특정 값'} 형태로 함수를 호출할 수 있다. 또는 특정 키워드에 반응하여 함수를 작성하는 방법도 있다.(if문 사용) 단, 신규로 추가할 파라미터를 **kwargs 의 왼쪽에 써야 한다.

ex)def a(**kwargs, a): 은 틀린 문법(SyntaxError)

 

2) *args(argument)

 

*args 여러개의 인자를 함수로 받고자 할 때 쓰인다. 이름은 임시로 지은거라 *a , *banana 등등 다 가능하다. 튜플(tuple) 형태로 여러개의 인자를 함수로 출력하게 될 경우 {'a', 'b', 'c' } 와 같이 튜플 형태로 출력된다.

 

(예시 출처)

 

1. hello( ) 함수가 있습니다. 부서명과 이름을 받아 인사합니다.

 

2. 어느날 여러 번 인사와 함께 just do it! 을 외치는 새로운 함수를 만들어야 합니다.

단순히 아래처럼 같은 내용을 또 선언 할 수도 있습니다.

)

런 경우 hello( ) 내용이 달라지면 hello_repeat도 변경해야하는 번거로움이 있습니다.

 

3. 이런 경우 기존 hello( )를 그대로 사용하면서 파라미터만 추가로 선언하는 방법을 사용할 수 있습니다.

결과가 같습니다. 이제 hello( ) 내용이 변경되더라도 hello_repeat( )는 변경할 필요가 없습니다.

kwargs와 args는 파이썬에서 기존의 함수에 파라미터를 추가하여 새로운 함수를 만드는 경우에 사용한다.

별표시(***)의 경우, 여러 개의 인수를 받을 때, 키워드 인수를 받을 때 사용하는 표시이다.

 

1) **kwargs (keyword argument)

 

**kwargs는 {'키워드': '특정 값'} 형태로 함수를 호출할 수 있다. 또는 특정 키워드에 반응하여 함수를 작성하는 방법도 있다.(if문 사용) 단, 신규로 추가할 파라미터를 **kwargs 의 왼쪽에 써야 한다.

ex)def a(**kwargs, a): 은 틀린 문법(SyntaxError)

 

2) *args(argument)

 

*args 여러개의 인자를 함수로 받고자 할 때 쓰인다. 이름은 임시로 지은거라 *a , *banana 등등 다 가능하다. 튜플(tuple) 형태로 여러개의 인자를 함수로 출력하게 될 경우 {'a', 'b', 'c' } 와 같이 튜플 형태로 출력된다.

 


(예시 출처)

 

1. hello( ) 함수가 있습니다. 부서명과 이름을 받아 인사합니다.

def hello(department, name):
    print('hello ' + department + ' team ' + name)

 

2. 어느날 여러 번 인사와 함께 just do it! 을 외치는 새로운 함수를 만들어야 합니다.

단순히 아래처럼 같은 내용을 또 선언 할 수도 있습니다.

def hello_repeat(num, department, name):
    for i in range(num):
        print('hello ' + department + ' team ' + name)
    print('just do it!')

)

런 경우 hello( ) 내용이 달라지면 hello_repeat도 변경해야하는 번거로움이 있습니다.

 

3. 이런 경우 기존 hello( )를 그대로 사용하면서 파라미터만 추가로 선언하는 방법을 사용할 수 있습니다.

def hello_repeat(num, **kwargs):
    for i in range(num):
        hello(**kwargs)
    print('just do it!')

결과가 같습니다. 이제 hello( ) 내용이 변경되더라도 hello_repeat( )는 변경할 필요가 없습니다.


 

 

15. views 가서 바꾸기

DB를 연결했으므로 임의로 정한 db_id, db_pwd가 아닌 오라클 DB에 있는 id와 pwd인지 if문을 이용해서 결과값을 리턴한다. 세션에 저장된 user_id가 id와 같을 경우, 로그인 성공창과 함께 0행 1열(2차원 배열 : 즉, 1행2열)을 이름값으로 가져온다.로그인이 실패되면 msg를 띄운다.

@csrf_protect
def loginform(request):
    # 세션에 등록한 값이 존재하는가?
    if 'user_id' in request.session:
        return redirect('/login')

    if request.method == 'POST':
        user_id = request.POST['id']
        user_pwd = request.POST['pwd']
        print('user_id: ', user_id)
        print('user_pwd: ', user_pwd)

        # ----------------- 리펙토링한거 ------------------
        res = getLoginChk(id=user_id,pwd=user_pwd)
        print('='*30)
        print(res)
        if len(res) > 0:
            print('로그인 성공')
            request.session['user_id'] = user_id
            request.session['user_name'] = res[0][1]
            return redirect('/login')
        else:
            print('로그인 실패')
            msg = '아이디나 비밀번호가 잘못되었습니다.'
            return render(request, "login/login.html", {"error": msg})

    return render(request, "login/login.html")

 

좌 : 기존 우 : 바꾼거

DB와 연동되어 로그인이 잘 되었다.

 

로그인 성공
로그인에 실패했을 경우

▼ 전체 코드 보기

더보기

[전체 코드]

1. index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index.html</title>
    <style>
        ol, ul {list-style:none;}
        ul li { float:left; margin-left:2px; background:pink}
    </style>
</head>
<body>
    <h1>로그인/로그아웃 데모</h1>
    <span>추후 web1에 템플릿 디자인으로 적용하세요.</span>
<nav id="menu">
    <header class="major">
        <ul>
            <li><a href="main">Home</a> </li>
            <li><a href="survey">설문조사</a> </li>

            {% if 'user_id' in request.session %}
            <li>{{request.session.user_name}}님 반갑습니다. </li>
            <li><a href="logout">로그아웃</a> </li>
            {% else %}
            <li><a href="/web1/tripmember">회원가입</a> </li>
            <li><a href="loginform">로그인폼</a> </li>
            {% endif %}
        </ul>
    </header>
</nav>
</body>
</html>

2. login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login.html</title>
    <style>
        ol, ul {list-style:none;}
        ul li { float:left; margin-left:2px; background:pink}
    </style>
</head>
<body>
    <h1>로그인 페이지</h1>
    <span>추후 web1에 템플릿 디자인으로 적용하세요.</span>
<nav id="menu">
    <section id="main">
        <header>
            <h2>StarTrip</h2>
            <form method="post" action="">
                {% csrf_token %}
                <div class="fields">
                    <div class="field">
                        <input type="text" name="id" id="id" value="" placeholder="ID"
                        style="text-transform :lowercase"/>
                    </div>
                    <div class="field">
                        <input type="password" name="pwd" id="pwd" placeholder="Password" />
                    </div>
                </div>
                <ul class="actions special">
                    <li><input type="submit" value="로그인" class="primary"/></li>
                </ul>
                <div><span style="color:red;">{{error}}</span> </div>
            </form>
        </header>
    </section>
</nav>
</body>
</html>

3. models.py

from django.db import models
import cx_Oracle as ora

database = 'kosmorpa/test00@192.168.0.122:1522/orcl'
# Create your models here.

# select count(*) cnt, name from member_table where id='xman' and pwd='121'
# 인자값이 여러개일 경우 함수의 인자를 늘여서 사용하게 되는 부분을 리팩토링한다.
def getLoginChk(**kwargs):
    conn = ora.connect(database)
    cursor = conn.cursor()
    sql_select = "select count(*) cnt, name from member_table" \
                 " where id=:id and pwd=:pwd group by name"
    cursor.execute(sql_select, id=kwargs['id'], pwd=kwargs['pwd'])
    datas = cursor.fetchall()
    cursor.close()
    conn.close()
    return datas

4. urls.py

from django.urls import path

from login import views

urlpatterns=[
    path('',views.home),
    path('loginform',views.loginform),
    path('logout',views.logout),
]

5. views.py

from django.shortcuts import render, redirect
from .models import *

# Create your views here.
from django.views.decorators.csrf import csrf_protect


def home(request):
    return render(request, "login/index.html")


# 1. 전송방식 구분
# 2. Session 유무에 따른 구분
@csrf_protect
def loginform(request):
    # 세션에 등록한 값이 존재하는가?
    if 'user_id' in request.session:
        return redirect('/login')

    if request.method == 'POST':
        user_id = request.POST['id']
        user_pwd = request.POST['pwd']
        print('user_id: ', user_id)
        print('user_pwd: ', user_pwd)

        # ----------------- 리펙토링한거 ------------------
        res = getLoginChk(id=user_id,pwd=user_pwd)
        print('='*30)
        print(res)
        if len(res) > 0:
            print('로그인 성공')
            request.session['user_id'] = user_id
            request.session['user_name'] = res[0][1]
            return redirect('/login')
        else:
            print('로그인 실패')
            msg = '아이디나 비밀번호가 잘못되었습니다.'
            return render(request, "login/login.html", {"error": msg})

    return render(request, "login/login.html")


# from .models import * 위쪽에 해줘야함

# ---------------------기존 코드 -> 리펙토링 해보기 ------------------------------
 #       db_id = 'xman'
 #       db_pwd = '11'
 #       if user_id in db_id and user_pwd in db_pwd:
 #           print('로그인 성공')
 #           request.session['user_id'] = db_id
 #           request.session['user_name'] = '김길동'
  #          return redirect('/login')
 #       else:
  #          print('로그인 실패')
   #         msg = '아이디나 비밀번호가 잘못되었습니다.'
   #         return render(request,"login/login.html",{"error":msg})
   # return render(request, "login/login.html")
# ------------------------------------------------------------------------------


# 로그아웃 처리
def logout(request):
    del request.session['user_id']
    del request.session['user_name']
    return redirect('/login')

 

cf) 웹브라우저에 SessionId가 쿠키에 저장되어있는지 확인하는 방법

 

반응형
LIST

댓글