반응형

 Golang에는 웹 프레임워크가 여러가지 있습니다. 제가 공부했던 책에서는 Beego가 추천되었는데, 그 외에도 Revel, Martini, Buffalo, echo, iris 등 여러가지가 있습니다. 요즘은 gin이라는 프레임워크가 대세인 것 같아서 설치해볼까 합니다.
https://github.com/gin-gonic/gin(Gin 소스 페이지)
우선 아래 명령어로 Gin을 설치합니다.

go get -u github.com/gin-gonic/gin

그리고 프로젝트를 생성해보겠습니다. 적당한 폴더를 하나 만들어 주고 Go 파일을 하나 작성해줍니다. 저는 그냥 main.go로 만들었습니다.

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

이제 웹 브라우저에서 localhost:8080/ping을 입력하면 메시지가 응답되는 것을 볼 수 있습니다.

 

 

 

 

 
-끝-

반응형
반응형

 

package main

import (
	"database/sql"
	"fmt"	

	_ "github.com/go-sql-driver/mysql"
)

func checkError(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {

	var name, email, phone string

	db, err := sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/testdb")
	checkError(err)
	defer db.Close()
    
	fmt.Println("connect success")

	rows, err := db.Query("SELECT name, email, phone FROM members where id=?", 6)
	checkError(err)
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&name, &email, &phone)
		checkError(err)
		fmt.Println("rows", name, email, phone)
	}
}
반응형
반응형

 

보통 프로그램이 커질수록 파일을 기능별로 분리 관리를 하죠. Go 언어에서도 파일 분리/관리 방법이 있습니다만 오늘은 이것 때문에 삽질을 좀 많이 했네요. 역시 기초부터 제대로 공부하고 써먹어야한다는 생각을 절실히 체감하는 오늘입니다.

 

1. 같은 package 안에서는 함수, 메서드 등의 이름 첫글자가 소문자여도 사용이 가능합니다. (non-public)

폴더 구분없이 파일만 구분해서 사용하고 싶을 경우, 같은 패키지(현재 main)으로 하고, 함수이름 첫글자 소문자(my_plus)일 경우 문제없이 인식 가능합니다. (import 같은 기능 필요 없음)

 

2. 다른 패키지로 관리할 때, 즉 폴더별로 관리할 경우 주의해야 할 사항이 몇가지 있어서 정리를 할까 합니다.

   1) 함수, 메서드 등의 이름 첫글자가 대문자이어야 사용 가능합니다.

   2) 다음으로는 지금까지 제가 Golang을 잘못 설정해서 쓰고 있던 것일 수도 있는데, 프로그램 작성을 go_pkg/src 하위에 작성해야만 import 시 인식이 가능합니다. 다른 방법(기타 툴의 사용이라던가..)이 있는지는 잘 모르겠으나, 현재까지는 go_pkg/src가 아닌 외부 폴더에서 작업할 경우 인식이 안되는 것으로 확인됩니다.

 

이상 간단판 패키지 관리 삽질기였습니다^^;;

 

~~끝~~

반응형
반응형

지금까지 DB 검색 기능에 대해 만들었으나, 사용자 등록, 로그인, 로그아웃 처리를 위해 대대적인 수정이 있겠습니다.

 

 

1. users 테이블 구성

우선 시작은 Database 구성부터 하도록 하겠습니다. 지난 members 테이블과는 별도로 사용자 관리를 위한 users 테이블을 생성하도록 하겠습니다.

 

2.user_model.py

데이터베이스 테이블에 맞춰 User클래스를 생성합니다. 정보는 ID, 이름, 비번이 되겠습니다.

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'   #테이블 이름 : users

    id = db.Column(db.Integer, primary_key = True)   #id를 프라이머리키로 설정
    userid = db.Column(db.String(32))
    username = db.Column(db.String(8))
    password = db.Column(db.String(64))

3.register.html

다음으로 사용자 등록화면인 register.html을 구성하겠습니다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Register Form</title>
</head>
<body>
<div>
    <h1>회원가입</h1>
</div>
<div>
    <form method="POST" action="/register">
        <div>
            <label for="userid">아이디</label>
            <input type="text" id="userid" placeholder="아이디" name="userid"/>
        </div>
        <div>
            <label for="username">이름</label>
            <input type="text" id="username" placeholder="이름" name="username"/>
        </div>
        <div>
            <label for="password">비밀번호</label>
            <input type="password" id="password" placeholder="비밀번호" name="password"/>
        </div>
        <div>
            <label for="re_password">비밀번호 확인</label>
            <input type="password" id="re_password" placeholder="비밀번호 확인" name="re_password"/>
        </div>
        <button type="submit">등록</button>
    </form>
</div>

</body>
</html>

화면 구성에 대해서는 최대한 자제하고 로직 구성에만 전념하겠습니다. 이에 대한 라우팅은 아래와 같이 구성합니다.

@app.route('/register', methods=['GET','POST'])
def register():
	if request.method =='GET':
		return render_template("register.html")
	else:
		userid = request.form.get('userid')
		username = request.form.get('username')
		password = request.form.get('password')
		re_password = request.form.get('re_password')

		if not (userid and username and password and re_password):
			return "모두 입력해주세요"
		elif password != re_password:
			return "비밀번호를 확인해주세요"
		else:
			user = User()
			user.password = password
			user.userid = userid
			user.username = username
			db.session.add(user)
			db.session.commit()
			return "회원가입 완료"
		return redirect('/')

최초 /register에 접속할 때에는 GET 방식으로 단순 html 파일을 보여주고, html 내 form 양식에 의해

<form method="POST" action="/register"> 로 불러질 때에는 POST 방식에 의해 수행이 됩니다. POST 방식에서는 아이디, 이름, 비번, 비번확인을 받아들여서, 하나라도 빠진게 있으면 체크하고, 비번과 비번확인이 다르면 체크하며, 모두 통과하면 users 테이블에 입력합니다. 입력이 완료되면 '/'으로 리다이렉트 됩니다.

 

4.login.html

로그인 페이지를 아래와 같이 구성합니다. 조금 뒤에 나오겠지만, 'userid'라는 session정보가 있을 경우 이미 로그인 했음을 알려주고, 그렇지 않을 경우 로그인 폼을 보여줍니다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
{% if session['userid'] %}
    <p>이미 로그인 하셨습니다.</p>
{% else %}
<center>
    <div>
        <h2>Login</h2>
        <form action="/login" method="POST">
            <input type="userid" name="userid" placeholder="Userid">
            <input type="password" name="password" placeholder="Password">
            <br><br>
            <input type="submit" value="로그인">
        </form>
    </div>
</center>
{% endif %}
</body>
</html>

# login 페이지 접속(GET) 처리와, "action=/login" 처리(POST)처리 모두 정의
@app.route('/login', methods=['GET', 'POST'])	
def login():
	if request.method=='GET':
		return render_template('login.html')
	else:
		userid = request.form['userid']
		password = request.form['password']
		try:
			data = User.query.filter_by(userid=userid, password=password).first()	# ID/PW 조회Query 실행
			if data is not None:	# 쿼리 데이터가 존재하면
				session['userid'] = userid	# userid를 session에 저장한다.
				return redirect('/')
			else:
				return 'Dont Login'	# 쿼리 데이터가 없으면 출력
		except:
			return "dont login"	# 예외 상황 발생 시 출력

@app.route('/logout', methods=['GET'])
def logout():
	session.pop('userid', None)
	return redirect('/')

로그인 폼을 보여줄 'GET' 방식과, 로그인 처리(사용자 확인)를 위한 'POST'방식을 모두 정의합니다. GET이면 login.html을 곧바로 보여주고, POST방식일 경우 login.html 내 폼에서 userid와 password 부분을 가져와서 database 조회를 합니다. 조회가 성공하면 session['userid']에 폼으로부터 전달받은 userid값을 저장하고 '/'으로 이동합니다. 데이터가 없거나, 예외가 발생하면 그에 따른 처리를 각각 해 줍니다.

 

아울러 '/logout'에 대해서도 함께 정의해줍니다. 이 때에는 GET만 정의하면 됩니다. 

 

5. __init__.py 수정

순서가 뒤죽박죽이 된 것 같네요. 위에서 세션을 사용한 코드를 이미 작성했는데.....한가지, Flask에서는 세션을 사용하려면 어플리케이션에 정의된 시크릿키(SECRET_KEY)가 필요합니다. 이 키로 서명된 쿠키가 사용된다고 합니다. 꼭 잊지말고 넣어주도록 합시다.

그밖에 기존에 사용자 인증과 관련없는 라우팅은 지면관계상 지우도록 하겠습니다.

@app.route('/home')도 지워버리고, 대신 home.html을 '/' 에서 라우팅하도록 하였습니다. 단 session['userid']가 있을 경우와 없을 경우를 나누어 처리하도록 하였습니다. 

from flask import Flask, render_template, request, redirect, session, url_for
from flask_sqlalchemy import SQLAlchemy
from helloflask.model.user_model import Member, User


app = Flask(__name__)

app.secret_key="123123123"

# database 설정파일
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:1234@localhost:3306/testdb"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

@app.route('/')
def home():
	#로그인 세션정보('userid')가 있을 경우
	if not session.get('userid'):  
		return render_template('home.html')
	
	#로그인 세션정보가 없을 경우
	else:		
		userid = session.get('userid') 
		return render_template('home.html', userid=userid)

# @app.route('/home') 삭제
# @app.route('/one') 삭제
# @app.route('/all') 삭제
# @app.route('/search', methods=['POST','GET']) 삭제

# register 페이지 접속(GET) 처리와, "action=/register" 처리(POST) 모두 정의
@app.route('/register', methods=['GET','POST'])
def register():
	if request.method =='GET':
		return render_template("register.html")
	else:
		userid = request.form.get('userid')
		username = request.form.get('username')
		password = request.form.get('password')
		re_password = request.form.get('re_password')

		if not (userid and username and password and re_password):
			return "모두 입력해주세요"
		elif password != re_password:
			return "비밀번호를 확인해주세요"
		else:
			user = User()
			user.password = password
			user.userid = userid
			user.username = username
			db.session.add(user)
			db.session.commit()
			return "회원가입 완료"
		return redirect('/')

# login 페이지 접속(GET)처리와, "action=/login" 처리(POST)모두 정의
@app.route('/login', methods=['GET', 'POST'])	
def login():
	if request.method=='GET':
		return render_template('login.html')
	else:
		userid = request.form['userid']
		password = request.form['password']
		try:
			data = User.query.filter_by(userid=userid, password=password).first()	# ID/PW 조회Query 실행
			if data is not None:	# 쿼리 데이터가 존재하면
				session['userid'] = userid	# userid를 session에 저장한다.
				return redirect('/')
			else:
				return 'Dont Login'	# 쿼리 데이터가 없으면 출력
		except:
			return "dont login"	# 예외 상황 발생 시 출력

@app.route('/logout', methods=['GET'])
def logout():
	session.pop('userid', None)
	return redirect('/')

 

6. home.html 수정

userid 세션이 존재할 경우 logout 버튼이 나오도록 처리하고, userid 세션이 없을 경우에는 등록하기와 로그인 버튼이 나타나도록 처리했습니다.

{% extends "layout.html" %}
{% block content %}

<div class="jumbo">
    <h2>Hello Flask App</h2>
    {% if session['userid'] %}
        <h4>{{ userid }}님 요청 처리에 대한 페이지입니다.</h4>
        <button type="button" onclick="location.href='/logout' ">로그 아웃</button>
    {% else %}
        <h4>Hello World!</h4>
        <button type="button" onclick="location.href='/register' ">등록하기</button>
        <button type="button" onclick="location.href='/login' ">로그인</button>
    {% endif %}
</div>
{% endblock %}

<로그인 세션이 없을 경우>

<로그인 세션이 존재할 경우>

 

~~끝~~

반응형

'Programming > Python_Web' 카테고리의 다른 글

FastAPI 시작하기  (0) 2021.09.09
FastAPI - Jinja2로 프론트 적용하기  (0) 2021.09.09
Flask강좌5 - Flask form입력  (0) 2020.12.03
Flask강좌4 - Flask_SQLAlchemy MySQL연동  (5) 2020.12.02
Flask강좌3 - Request  (0) 2020.12.01
반응형

form을 이용해 입력을 받고, 처리하여, 다시 결과를 보여주는 로직을 구현하겠습니다. 

1. localhost:5000/all의 db.html 화면에서 입력 받고,

2. __init__.py에서 라우팅 처리하고,

3. db.html에 결과를 보여줍니다. 

 

1. __init__.py

form 으로부터 전달된 이름('nm')을 받아서 temp 변수에 저장하고, query.filter_by로 DB에서 조회한 후, 결과를 members로 저장합니다. 그리고 members의 갯수를 count에 저장합니다. render_template함수를 통해 db.html로 연결이 되는데, 이때 members와 count를 함께 넘겨줍니다.

from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from helloflask.model import Members
from datetime import datetime

app = Flask(__name__)

# database 설정파일
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:1234@localhost:3306/testdb"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

@app.route("/")
def home():
	member = Members.query.first()
	return 'Hello {0}, {1}, {2}, {3}, {4}'\
		.format(member.name, member.email, member.phone, member.start.isoformat(), member.end.isoformat())
	#return render_template('home.html')


@app.route('/all')
def select_all():
	members = Members.query.all()
	return render_template('db.html', members=members)

@app.route('/search', methods=['POST','GET'])
def calculate():
	if request.method=='POST':
		#temp = request.args.get('nm')
		temp = request.form['nm']
		members = Members.query.filter_by(name=temp)
		count=members.count()
		return render_template('db.html', members=members, cnt=count)

 

2.db.html

form 입력은 "POST" 형태로 이루어지고, 처리를 한 action을 명시해줍니다. 이후 "/search"에서 처리한 결과는 members 변수에 담아 전달됩니다. members 변수의 각 attribute를 출력하는 부분을 작성합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask App</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>

<form method="POST" action="/search">
    <div>
        <label for="nm">검색이름</label>
        <input type="text" name="nm">

    </div>
    <div class="'button'">
        <button type="submit">검색</button>
    </div>
</form>
    <p>

        {% if members ==None %}
            <h5>결과가 없습니다.</h5>
        {% else %}
            <h5>{{ cnt }}개의 결과가 있습니다.</h5>
        {% endif %}
        <table>
        {% for member in members %}
            <tr>
                <td>{{ member.id }}</td>
                <td>{{ member.name }}</td>
                <td>{{ member.email }}</td>
                <td>{{ member.phone }}</td>
                <td>{{ member.start }}</td>
                <td>{{ member.end }}</td>
            </tr>
        {% endfor %}
        </table>
    </p>
</div>

</body>
</html>

<결과>

(1) localhost:5000/all 접속화면

(2) 검색이름에 '홍길동' 을 입력 후 검색한 화면

반응형
반응형

ourcodeworld.com/articles/read/434/top-5-best-free-jquery-and-javascript-dynamic-gantt-charts-for-web-applications

반응형
반응형

이번 강좌에서는 ORM 방식으로 Database와 연동하는 방법에 대해 포스팅하겠습니다. ORM은 Object-Relational Mapping 이라고 하여, Database 객체를 객체지향 프로그래밍 언어로 변환하는 기법입니다. (자세한 내용은 다른 포스팅들을 참조하시기 바랍니다.) 그 중에서도 Flask에서 ORM을 구현할 수 있게 해주는 라이브러리가 Flask-SQLAlchemy 입니다. 이 Flask-SQLAlchemy를 이용하여 MySql과 연동해보도록 하겠습니다.

 

1. Database 자료 생성

아래와 같이 id, name, email, phone, start(datetime), end(datetime)을 필드로 하는 자료를 생성해놓습니다.

2. 라이브러리 설치

먼저 말했듯이 이번 강좌의 메인인 flask_sqlalchemy 라이브러리를 설치합니다. 그리고 mysql과 연동하기 위한 pymysql라이브러리도 함께 설치해줍니다.

pip install flask_sqlalchemy
pip install pymysql

 

3. 앱 구성

이번 helloflask앱은 아래와 같은 구성으로 만들려고 합니다. DB연동은 __init__.py에서 구현하고 db.html에서 결과를 표시합니다.

 

3. model.py

연결된 Database의 table을 받아들일 class를 정의합니다.

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class Members(db.Model):
    """ table name : members
        table info 
    - id : index id 
    - name 
    - start: start datetime
    - end: end datetime """
    
    __tablename__ = 'members'
    
    id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True)
    name = db.Column(db.String(20, 'utf8mb4_unicode_ci'))
    email = db.Column(db.String(50, 'utf8mb4_unicode_ci'))
    phone = db.Column(db.String(20, 'utf8mb4_unicode_ci'))
    start = db.Column(db.DateTime, default=datetime.utcnow())
    end = db.Column(db.DateTime, default=datetime.utcnow())

    def __init__(self, name, email, phone, start, end):
        self.name = name
        self.email = email
        self.phone = phone
        self.start = start
        self.end = end

4. __init__.py

예제 구성을 단순화하기 위해 database설정부분을 __init__.py 파일 안에 포함시켰습니다. 본인의 Database/ID/Password 등에 맞게 설정을 하시면 됩니다. one만 출력할 때에는 string을 return시켰으며, all을 출력할 때에는 db.html에 출력하도록 구성하였습니다.

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from helloflask.model.user_model import Members

app = Flask(__name__)

# database 설정파일
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:1234@localhost:3306/testdb"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

@app.route('/home')
def home():
    return render_template('home.html')
    
@app.route("/one")
def home():
	member = Members.query.first()
	return 'Hello {0}, {1}, {2}, {3}, {4}'\
		.format(member.name, member.email, member.phone, member.start.isoformat(), member.end.isoformat())
	#return render_template('home.html')
    
@app.route('/all')
def select_all():
    members = Members.query.all()
    return render_template('db.html', members=members)

5. db.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask App</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<table>
{% for member in members %}
    <tr>
        <td>{{ member.id }}</td>
        <td>{{ member.name }}</td>
        <td>{{ member.email }}</td>
        <td>{{ member.phone }}</td>
        <td>{{ member.start }}</td>
        <td>{{ member.end }}</td>
    </tr>
{% endfor %}
</table>

</body>
</html>

<결과>

 

~~끝~~

반응형

'Programming > Python_Web' 카테고리의 다른 글

Flask강좌6 - 등록/로그인/로그아웃  (0) 2020.12.04
Flask강좌5 - Flask form입력  (0) 2020.12.03
Flask강좌3 - Request  (0) 2020.12.01
Flask강좌2 - Global Object: g, Response객체  (0) 2020.12.01
Flask강좌1 - hello flask!  (0) 2020.12.01
반응형

1. Request Event Handler

주요 Request Event Handler(Web Filter)는 아래와 같습니다.

 

@app.before_first_requst : 첫번째 요청을 부를 때

@app.before_request : 매 요청에 대해 router가 받아서 모델이 처리하기 전에

@app.after_request : 응답이 나가기 직전에 (DB Close와 같은 작업 처리)

@app.teardown_request : 응답이 나가고 나서

@app.teardown_appcontext : application Context가 끝났을 때

 

 

2. Request Parameter

 

# GET
request.args.get('q')  .....> q파라미터를 GET으로 받음

 

# POST
request.form.get('p', 123) .....> p파라미터를 POST로 받음. 값이 없으면 123

 

# GET or POST
request.values.get('v') .....> GET/POST 둘 다 받음

 

# Parameters
request.args.getlist('qs') .....> GET으로 list를 받을 때 쓰임

반응형

'Programming > Python_Web' 카테고리의 다른 글

Flask강좌5 - Flask form입력  (0) 2020.12.03
Flask강좌4 - Flask_SQLAlchemy MySQL연동  (5) 2020.12.02
Flask강좌2 - Global Object: g, Response객체  (0) 2020.12.01
Flask강좌1 - hello flask!  (0) 2020.12.01
Flask - IIS연동  (2) 2020.10.23

+ Recent posts