프로그램언어+

식별계정 콘솔 DB Migration WORKFLOW (작업중)

logthink 2018. 12. 27. 04:38

주제


패스워드 콘솔 만들기


개요


애초에 sqlite를 이용해 ORM 적용해 두었었던 작품입니다.

(참고 : https://pypi.org/project/python-sqlite-orm/)


그런데 sqlite 사용하는 관점과 mysql(mariaDB) 사용적 관점에서 migration 할 타이밍이 온 것같습니다.

(사실 DBMS까지 다 비교하진 않았습니다. 다만, Console개념을 살려서 Client-Server구조의 Storage 프로그램이 필요했을뿐)

간단히 알아봅시다.


세대별 DBMS의 구조

구분 

 모델

 설명

DBMS 

 1 세대 

 파일시스템

 : 데이터가 계층적이며 상하 종속적인 관계로 구성
- 장점 : 데이터의 엑세스 속도가 빠르고, 데이터의 사용량을 쉽게 예측 할 수 있다.

-ISAM

-VSAM 

 2 세대

 계층형 (Hierachical DBMS) 

  : 데이터가 계층적이며 상하 종속적인 관계로 구성
- 장점 : 데이터의 엑세스 속도가 빠르고, 데이터의 사용량을 쉽게 예측 할 수 있다.

-IMS

-System2000 

 3 세대

 네트워크형 (Network DBMS) 

 : 데이터 구조를 네트워크상의 노드 형태로 논리적이게 표현한 데이터 모델로서 각각의 노드를 서로 대등한 관계로 구성한 시스템(여기서 노드란 시스템을 의미하는 것이 아니라 자료를 말한다.)
- 장점 : 계층형 데이터베이스 관리시스템의 문제점인 상하 종속적인 관계는 해결되었다.
- 단점 : 구성과 설계가 복잡하고 궁극적으로 데이터의 종속성을 해결하지 못하였다.

-IDS

-IDMS

-TOTAL

 4 세대

 관계형 (Relational DBMS) 

 : 수학적 논리 관계를 테이블의 형태로 구성한 구조로서 테이블 내의 컬럼 중 일부를 다른 테이블과 중복해 각 테이블간의 상관관계를 정의
- 장점 : 업무 변화에 대한 적응력 높아 변화하는 업무에 쉽게 활용하며 유지보수 편리하다. 따라서 생산성도 향상된다.
- 단점 : 다른 DBMS 보다 더 많은 자원이 활용되어 시스템의 부하가 높다.

-Oracle

-Mysql

-DB2

-SQL Server

-Sybase

 5 세대

 객체지향 (Object Oriented DBMS) 

 : 멀티미디어 데이터의 원활한 처리와 RDBMS의 비지니스형 데이터 타입만 처리되는 기본적인 제한점을 극복하고자 고안

-Object Store

-UniSQL 



1
2
3
mysql> create database manage_console default CHARACTER SET UTF8;
 
Query OK, 1 row affected (0.00 sec)
cs


일단 DB만들고, 확인


1
2
3
4
5
6
7
8
9
10
11
12
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| manage_console     |
| mysql              |
| performance_schema |
| project            |
| sys                |
+--------------------+
6 rows in set (0.00 sec)
cs


테이블 생성

1
2
3
4
5
6
mysql> CREATE TABLE managesite(idx int primary key auto_increment,
    -> sitename varchar(30) not null,
    -> siteurl varchar(100),
    -> snsauth varchar(20) default 'null'
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)
cs


확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> show tables;
+--------------------------+
| Tables_in_manage_console |
+--------------------------+
| managesite               |
+--------------------------+
1 row in set (0.00 sec)
 
mysql> desc managesite;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| idx      | int(11)      | NO   | PRI | NULL    | auto_increment |
| sitename | varchar(30)  | NO   |     | NULL    |                |
| siteurl  | varchar(100) | YES  |     | NULL    |                |
| snsauth  | varchar(20)  | YES  |     | null    |                |
+----------+--------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
cs


그리고 DB사용자를 추가

1
create user 'namki'@'localhost' identified by '%password%';
cs


mysql ERROR 1819 (HY000): Your password does not satisfy the current policy requirements 라는 에러가 발생하면 Mysql password policy requirements 에러 validation 제거하여 해결하기 을 참고하자


내 계정 만들고 권한 설정 끝

1
2
mysql> grant all privileges on *.* to 'namki'@localhost;
Query OK, 0 rows affected (0.00 sec)
cs


이제 새 테이블을 만드려고 했는데, 에러발생.


1
ERROR 1215 (HY000): Cannot add foreign key constraint
cs


이전 테이블에서 키가 더 필요하다 여기서 키를 좀 조사해보면은


키(key)의 종류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
* 키(Key)
- 열쇠는 무언가를 열거나 잠글 때 사용하는 것으로, 같은 것이 하나도 없다. 우리집 열쇠가 옆집의 열쇠랑 다르듯이 말이다.
- 이와 같이 키라는 것은 무언가를 식별하는 고유한 식별자(identifier) 기능을 한다.
- 즉, 키는 데이터베이스에서 조건에 만족하는 관계의 행을 찾거나 순서대로 정렬할 때 다른 행과 구별할 수 있는 유리한 기준이 되는 속성의 집합이다.
- 키의 종류로는 기본키, 슈퍼키, 후보키, 대체키, 외래키 등이 있다.
 
1. 슈퍼키(Super Key)
- 테이블에서 각 행을 유일하게 식별할 수 있는 하나 또는 그 이상의 속성들의 집합이다. 슈퍼키는 유일성만 만족하면 슈퍼키가 될 수 있다.
- 유일성이란 하나의 키로 특정 행을 바로 찾아낼수 있는 고유한 데이터 속성을 말한다. 예를 들면 전국에서 나를 구별할 수 있는 유일하고 고유한 속성은 주민번호이듯이 말이다. 주민번호는 전국민이 모두 겹치지 않아 유일하고 고유한 구별 방법으로 쓰인다.
- 아래 사진을 보자. 7조라는 팀에 팀원은 4명이 있다. 이 4명을 구분할 수 있는 것은 절대 겹치지 않는 학번 일수도 있고, 주민번호일 수도 있다.
- 이름과 나이를 묶어서 하나의 속성으로 만드는 것도 가능하다. 이름과 나이를 합쳐서 7조안에서 중복만 되지 않으면 가능하기 때문이다. 이름과 나이를 합쳐서 4명을 구분할 수 있으면 슈퍼키가 될 수 있다.
- 학번과 주민번호를 묶어서 슈퍼키로 만들수도 있고, 학번과 주민번호과 이름을 합쳐서 슈퍼키로도 만들수 있고, 학번과 주민번호과 이름과 나이를 합쳐서 슈퍼키를 만들수도 있다. 어떤 속성끼리 묶던 중복값이 안나오고 서로 구별만 할 수 있으면 된다.
 
2. 후보키(Candidate Key)
- 테이블에서 각 행을 유일하게 식별할 수 있는 최소한의 속성들의 집합이다. 후보키는 기본키가 될 수 있는 후보들이며 유일성과 최소성을 동시에 만족해야한다.
- 아래 사진을 보자. 7조라는 팀에 팀원은 4명이 있다. 이 4명을 구분하는 슈퍼키들이 모여 있는데, 슈퍼키들 중에서 속성은 최소한의 갯수로 4명을 구분할 수 있어야 후보키가 될 수 있다.
- 학번 슈퍼키와 주민번호 슈퍼키는 속성들이 각 1개씩 이루어져 있다. 하지만 이름+나이 슈퍼키는 이름과 나이를 묶어서 2개의 속성으로 되어 있다. 이름+나이 슈퍼키는 2개 이므로 각 1개의 속성인 주민번호와 학번 슈퍼키가 최소성을 만족한다고 할 수 있다.
- 따라서 이름+나이 슈퍼키는 갯수가 다른 것보다 많기 때문에 최소성을 만족하지 못해서 후보키가 될 수 없다.
 
3. 기본키(Primary Key)
- 후보키들 중에서 하나를 선택한 키로 최소성과 유일성을 만족하는 속성이다.
- 테이블에서 기본키는 오직 1개만 지정할 수 있다.
- 기본키는 테이블 안에서 유일하게 각 행들을 구별할 수 있도록 쓰인다.
- 기본키는 NULL 값을 절대 가질수 없고, 중복된 값을 가질 수 없다.
- 각 행들을 구별하려면 값이 없어선 안되고, 중복되어서도 안되기 때문이다.
 
4. 대체키(Alternate Key)
- 후보키가 두개 이상일 경우 그 중에서 어느 하나를 기본키로 지정하고 남은 후보키들을 대체키라한다.
- 대체키는 기본키로 선정되지 않은 후보키이다.
- 아래 사진을 보자. 7조라는 팀에 팀원은 4명이다. 후보키로 학번과 주민번호가 뽑혔고, 둘 중에서 기본키는 학번이 되었다. 학번이 기본키가 되고 남은 후보키인 주민번호는 대체키가 될 수 있다. 학번 기본키가 없어지게 되면 주민번호는 없어진 기본키를 대체할 수 있게된다.
 
5. 외래키(Foreign Key)
- 테이블이 다른 테이블의 데이터를 참조하여 테이블간의 관계를 연결하는 것이다. 데이터를 좀더 조회하기 쉽다.
- 다른 테이블의 데이터를 참조할 때 없는 값을 참조할 수 없도록 제약을 주는 것이다.
- 참조 될 테이블(A)이 먼저 만들어지고 참조하는 테이블(B)에 값이 입력되어야 한다.
- 이때, 참조될(A) 열의 값은 참조될(A) 테이블에서 기본키(Primary Key)로 설정되어 있어야한다.
- 외래키는 참조되는 테이블의 기본키와 동일한 키 속성을 가진다.
- 참조되는 부모테이블이 먼저 생성된 뒤 데이터를 넣고, 참조하는 자식 테이블이 다음에 생겨야된다.
- 부모 테이블 먼저 삭제될 수 없다. 왜냐하면 부모테이블을 참조하는데 부모테이블이 삭제되면 자식테이블은 참조하는 것이 없어지기 때문에 외래키 오류가 생긴다.
- 외래키 관계에서 부모테이블을 삭제하려면 자식테이블 먼저 삭제한 후 부모테이블을 삭제해야한다.
 
- 아래 사진을 보자. 부모 테이블은 학생 테이블이고, 자식 테이블은 수강 테이블이다.
- 학생테이블은 학번이 기본키이자 참조되는 참조키이다.
- 수강테이블은 학번이 참조하는 키이자 외래키이다.
- 기본 형태 :
 
컬럼명 컬럼타입 FOREIGN KEY (외래키) REFERENCES 부모테이블명(참조키);
cs


그래서 기존 테이블에 유니크한 키를 추가했다.


1
2
3
mysql> alter table managesite add unique key `primary key` (sitename);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
cs


그리고 나서 다시 테이블(완전 식벽자의 데이터를 품을) 생성.


1
2
3
4
5
6
7
8
9
mysql> CREATE TABLE pwd_identity(
    -> idx int primary key auto_increment,
    -> userid varchar(30) not null,
    -> userpw varchar(30) not null,
    -> rdate date,
    -> sitename varchar(30) not null,
    -> CONSTRAINT foreign key (sitename) references managesite (sitename)
    -> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.01 sec)
cs


그리고 내용을 추가해야하는데, 아무래도 민감한데이터가 존재하니 데이터를 암호화 하자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mysql> select hex(AES_ENCRYPT('abc', 'a'));
+----------------------------------+
| hex(AES_ENCRYPT('abc', 'a'))     |
+----------------------------------+
| 31314BA898CCDE00814E2520B02B646B |
+----------------------------------+
1 row in set (0.00 sec)
 
mysql> select AES_DECRYPT(UNHEX("AE1A17EC25E92DF81AA67584D51D5741"),'b');
+------------------------------------------------------------+
| AES_DECRYPT(UNHEX("AE1A17EC25E92DF81AA67584D51D5741"),'b') |
+------------------------------------------------------------+
| abc                                                        |
+------------------------------------------------------------+
1 row in set (0.00 sec)
 
'''
# "암호화 키"는 임의의 값이 올 수 있으며, "문자열"은 암호화하고자 하는 값이 됩니다.
 
 # AES_ENCRYPT 암호화
  INSERT INTO 테이블명 VALUES (HEX(AES_ENCRYPT('문자열', '암호화 키')));
 
 # AES_DECRYPT 복호화
  SELECT AES_DECRYPT(UNHEX(필드명), '암호화 키') FROM 테이블명;
 
예제 (ex #1
 # AES_ENCRYPT 암호화
 INSERT INTO tbname VALUE (HEX(AES_ENCRYPT('123456','가나다라')));
 // 결과: 5A33E11DC0B638E4E5E74EBD52F55E3D
 
 # AES_DECRYPT 복호화
 SELECT AES_DECRYPT(UNHEX(필드명), '가나다라') FROM tbname;
'''
cs



(주의 Hash값 16자리 이상인 경우 길이는 64, 그 이하의 길이는 32)


Okay이제는 python 메서드를 사용해서 mysql를 제어하겠다.

필요한 라이브러리는 pip search로 검색할 수 있다.(로컬쪽 모듈 한계) 그래서 pypi 문서에서 하나를 찾게 되었다. 그이름은 바로


1
2
pip3 install mysql-connector-python
pip3 install mysqlclient
cs


이 모듈은 MySQL C 클라이언트 라이브러리에 의존하지 않고, Python으로 작성된 MySQL 드라이버이다.

그 다음으로 python을 이용해 mysql 커넥션 pool을 만드는 코드를 짰다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: utf-8 -*-
import mysql.connector #DB 모듈
from mysql.connector import Error
#create Connection
#C:\Bitnami\wampstack-7.1.24-1\mysql\
#127.0.0.1
def connect():
    try:
        conn = mysql.connector.connect(
                            host="127.0.0.1",
                            user="{userid}",
                            passwd="{password}"
        )
        if conn.is_connected(): #연결에 대한 로직
            print("Connected to mysql DB")
    except Error as e:
        print("error name : {}".format(e))
    finally:
        conn.close()
    return conn
 
if __name__=="__main__":
    db = connect()
    print("good")
    print(db)
 
cs


수정 (전)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Connector(Singleton):
    conn = None
    def __init__(self, connect_info=None):
        global engine
        if engine is None:
            engine = sqlalchemy.create_engine(
                connect_info, pool_size=5,
                max_overflow=5, pool_recycle=505)
    def __enter__(self):
        self.conn = engine.connect()
        return self.conn
    def __exit__(self, exe_type, exc_val, exc_tb):
        self.conn.close()
with Connector(config['MARIADB']['MARIADB_CONNECT_INFO']) as con:
    onion_count = con.execute("select count(*) from onions_info").fetchall()[0]
return onion_count
cs
cs

수정 (후)

(참고 : http://www.mikusa.com/python-mysql-docs/index.html)


크게 두 가지 이유로 현재 코드는 동작은 하지만 뭔가 굉장히 허전하다. 

1. 리소스 낭비(weak resource)

2. 보안에 취약(dynamic of qry vuln & structure)


그 이외 몇가지 부수적인것들로 인해 세션과 ORM 모듈을 적용하기로 생각했고, DB커넥션 풀을 객체로 사용하기로 마음먹음.

(오후에 vue.js랑 Node.js 코딩테스트(18시~23시29분) 때문에 멘탈 정상아님...하....테스트 포기함유 ㅠㅠ )

DB커넥션 풀을 객체로 반환할 때는 with grammer를 사용할 것이다. 그러면 미리 커넥션이 생성하고 DB이벤트마다 트랜잭션 사이클을 돌릴 수 있어서 

자원을 조금 더 효율적으로 사용가능하다. -> 이 기법자체가 사실 Connection Pool 이랍니다.(블로그찾음)


 DB 구현 함수

 DB 생성

 테이블 생성

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = 'CREATE DATABASE test'
        cursor.execute(sql)
    conn.commit()
finally:
    conn.close()
cs
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        db='test',
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = '''
            CREATE TABLE users (
                id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
                email varchar(255) NOT NULL,
                password varchar(255) NOT NULL
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8
'''
        cursor.execute(sql)
    conn.commit()
finally:
    conn.close()
cs

 데이터 삽입

 데이터 조회

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        db='test',
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = 'INSERT INTO users (email, password) VALUES (%s, %s)'
        cursor.execute(sql, ('test@test.com''my-passwd'))
    conn.commit()
    print(cursor.lastrowid)
    # 1 (last insert id)
finally:
    conn.close()
cs
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        db='test',
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = 'INSERT INTO users (email, password) VALUES (%s, %s)'
        cursor.execute(sql, ('your@test.com''your-passwd'))
    conn.commit()
 
    with conn.cursor() as cursor:
        sql = 'SELECT * FROM users'
        cursor.execute(sql)
        result = cursor.fetchall()
        print(result)
        # ((1, 'test@test.com', 'my-passwd'), (2, 'your@test.com', 'your-passwd'))
finally:
    conn.close()
cs

 데이터 수정

데이터 삭제 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        db='test',
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = 'UPDATE users SET email = %s WHERE email = %s'
        cursor.execute(sql, ('my@test.com''test@test.com'))
    conn.commit()
    print(cursor.rowcount) # 1 (affected rows)
finally:
    conn.close()
cs
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pymysql.cursors
 
conn = pymysql.connect(host='localhost',
        user='user',
        password=None,
        db='test',
        charset='utf8mb4')
 
try:
    with conn.cursor() as cursor:
        sql = 'DELETE FROM users WHERE email = %s'
        cursor.execute(sql, ('my@test.com',))
    conn.commit()
    print(cursor.rowcount) # 1 (affected rows)
finally:
    conn.close()
cs



ORM


SQLAlchemy 객체 관계형 매퍼는 데이터베이스 테이블을 이용해 사용자가 정의한 파이썬 클래스의 메소드와 각각의 행을 나타내는 인스턴스로 표현된다. 객체와 각 연관된 행들의 모든 변경점들이 자동으로 동기되어 인스턴스에 반영되며, 그와 동시에 사용자가 정의한 클래스와 각 클래스 사이에 정의된 관계에 대해 쿼리할 수 있는 (Unit of work이라 하는)시스템을 포함하고 있다.

이 ORM에서 사용하는 SQLAlchemy 표현 언어는 ORM의 구성 방식과도 같다. SQL언어 튜토리얼에서는 직접적인 의견을 배제한 채 데이터베이스들의 초기에 어떻게 구성해 나가야 하는지에 대해 설명하는 반면 ORM은 고수준의, 추상적인 패턴의 사용 방식과 그에 따른 표현 언어를 사용하는 방법을 예로 보여준다.

사용 패턴과 각 표현 언어가 겹쳐지는 동안, 초기와 달리 공통적으로 나타나는 사항에 대해 표면적으로 접근한다. 먼저 사용자가 정의한 도메인 모델서부터 기본적인 저장 모델을 새로 갱신하는 것까지의 모든 과정을 일련의 구조와 데이터로 접근하게 해야한다. 또 다른 접근 방식으로는 문자로 된 스키마와 SQL 표현식이 나타내는 투시도로부터 명쾌하게 구성해, 각 개별적인 데이터베이스를 메시지로 사용할 수 있게 해야 한다.

가장 성공적인 어플리케이션은 각각 독자적인 객체 관계형 매퍼로 구성되야 한다. 특별한 상황에서는, 어플리케이션은 더 특정한 데이터베이스의 상호작용을 필요로 하고 따라서 더 직접적인 표현 언어를 사용할 수 있어야 한다.

(제 실력이 미천해 깔끔하게 번역이 안되네요. 공통된 부분에만 집중하고 각 데이터베이스의 특징을 몰개성화 하며 단순히 저장공간으로 치부하는 다른 ORM과 달리 SQLAlchemy는 각 데이터베이스의 특징도 잘 살려내 만든 ORM이다, 대충 이런 내용입니다. 원문 보세요. ㅠㅠ)

근데 sqlalchemy는 DB 세션을 이용가능한 engine을 생성하여 편함.


1
pip3 install sqlalchemy
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import mysql.connector #DB 모듈
from mysql.connector import Error
from sqlalchemy import create_engine
from sqlalchemy import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
 
engine = create_engine('mysql://namki@localhost/?charset=utf8', convert_unicode=False)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))                        
#refer: https://docs.sqlalchemy.org/en/rel_0_9/core/engines.html
Base = declarative_base()
Base.query = db_session.query_property()
 
def init_db(): 
    import models 
    Base.metadata.create_all(engine)
cs

mysql_control.py



접속이 끝나더라도 계속 해서 연결 상태를 유지시키기 위해 session_maker를 통해 세션을 만들어 준다.

scoped_session은 Thread_safe를 유지하기 위해 주로 웹 어플리케이션에서 사용한다.


새로운 Table과 mapper를 만들기 위해 declarative_base()를 호출하여 Base를 생성하고, 생성된 Base의 메타데이터를

해당하는 model의 값으로 생성한다.

DB 연결과 세션 생성에 대한 스크립트가 완료되었다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime 
from database import Base 
import datetime
 
engine = create_engine('mysql://namki:dd4351@localhost/?charset=utf8', convert_unicode=False)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))                        
#refer: https://docs.sqlalchemy.org/en/rel_0_9/core/engines.html
Base = declarative_base()
Base.query = db_session.query_property()
#insert into managesite (sitename, siteurl, snsauth) values('facebook', 'https://www.facebook.com/', 'false')
#insert into pwd_identity (userid, userpw, rdate, sitename) values ('01094065290', hex(AES_ENCRYPT('pw', md5('key'))), now(), 'facebook');
 
def init_db(): 
    import models 
    Base.metadata.create_all(engine)
 
def todaydate():
    d=datetime.date.today()
    return d.isoformat()
 
class User(Base): 
    _tablename_ = 'managesite' 
    idx = Column(Integer, primary_key=True, not null, auto_increment) #{Field:idx, Type:int(11), Null:NO, Key:PRI, Extra:auto_increment}
    sitename = Column(varchar(30), not null, unique_key=True) #{Field:sitename, Type:varchar(30), Null:NO, Key:UNI}
    siteurl = Column(varchar(100)) #{Field:siteurl, Type:varchar(100), Null:YES}
    snsauth = Column(varchar(20)) #{Field:snsauth, Type:varchar(20), Null:YES}
    def __init__(self, sitename, siteurl, snsauth): 
        self.sitename = sitename 
        self.siteurl = siteurl 
        self.snsauth = snsauth
    def __repr__(self): 
        return "<managesite(%s', '%s', '%s'>" %(self.sitename, self.siteurl, self.snsauth)
 
class Pwd(Base):
    __tablename__="pwd_identity"
    idx = Column(Integer, primary_key=True, not null, auto_increment) #{Field:idx, Type:int(11), Null:NO, Key:PRI, Extra:auto_increment}
    userid = Column(varchar(30), not null#{Field:userid, Type:varchar(30), Null:NO}
    userpw = Column(varchar(100), not null#{Field:userpw, Type:varchar(100), Null:NO}
    rdate = Column(varchar(30)) #{Field:rdate, Type:varchar(50), Null:NO}
    sitename = Column(varchar(30), not null, forenign_key=True) #{Field:sitename, Type:varchar(30), Null:NO}
    def __init__(self, userid, userpw, rdate=todaydate(), sitename):
        self.userid = userid
        self.userpw = userpw # required hash
        self.sitename = sitename
    def __repr__(self):
        return "<pwd_identity(%s', '%s', '%s'>" %(self.userid, self.userpw, self.sitename)
 
if __name__ == "__main__" : main()
    init_db()
    pri_user = User()
    db_session.add(pri_user)
    db_session.commit()
    pri_user_pwd = Pwd()
    db_session.add(pri_user)
    db_session.commit()
cs


이것으로 마무으리~다음편을 기대하시라....사실 이번에는 밑도 끝도 없는 포스팅임과 동시에

공부하는데 의미를 두게 되었다.(까먹은 DB야 오랜만:D)


참고


ref : sqlite 내부 조인 -http://thinking-jmini.tistory.com/14

ref : 생활코딩 내부 조인 - https://www.youtube.com/watch?v=U8FWvjaQBDs

ref : 미래학자의 MYSQL - http://futurists.tistory.com/11

ref : 흔한 컴공의 개발기 - http://simsimjae.tistory.com/75

ref : 진화중 - https://m.blog.naver.com/PostView.nhn?blogId=imf4&logNo=220779816879&proxyReferer=https%3A%2F%2Fwww.google.com%2F

ref : TCP스쿨 - http://tcpschool.com/mysql/mysql_constraint_foreignKey

ref : Oracle Advanced SQL 강좌 - http://www.gurubee.net/lecture/2688

ref : mysql내장함수 암복호화 - http://blog.habonyphp.com/entry/mysql-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%95%94%ED%98%B8%ED%99%94-%EB%B3%B5%ED%98%B8%ED%99%94%ED%95%98%EB%8A%94-AES-%ED%95%A8%EC%88%98#.XCMrKmgzZPY

ref : 농사짓는 개발자 - https://openlife.tistory.com/350

ref : 데이터 암복호화 : http://jeonjin.tistory.com/673