don't stop believing

Flask로 API 서버 만들기 (3) - User 테이블 만들기 본문

Python/Flask

Flask로 API 서버 만들기 (3) - User 테이블 만들기

Tongchun 2018. 11. 12. 11:59

Developing API Sample Server by Flask 

Original Post: How to structure a Flask-RESTPlus web service for production builds

Github: https://github.com/cosmic-byte/flask-restplus-boilerplate


Flask로 API 서버 만들기 (1) - 개발 환경 준비

Flask로 API 서버 만들기 (2) - config 와 실행 확인

Flask로 API 서버 만들기 (3) - User 테이블 만들기

Flask로 API 서버 만들기 (4) - Testing

Flask로 API 서버 만들기 (5) - User Operations

Flask로 API 서버 만들기 (6) - Security and Authentication

Flask로 API 서버 만들기 (7) - Route protection and Authorization

Flask로 API 서버 만들기 (8) - Extra tips (Makefiles)


이제 DB 를 만들어 보겠습니다.

model 폴더 아래 user.py 파일을 만들고 user 테이블을 만듭니다.

1
$ sudo vim ./app/main/model/user.py
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

user.py파일에 아래 script를 작성합니다.

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
from .. import db, flask_bcrypt
class User(db.Model):
""" User Model for storing user related details """
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(255), unique=True, nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
public_id = db.Column(db.String(100), unique=True)
username = db.Column(db.String(50), unique=True)
password_hash = db.Column(db.String(100))
@property
def password(self):
raise AttributeError('password: write-only field')
@password.setter
def password(self, password):
self.password_hash = flask_bcrypt.generate_password_hash(password).decode('utf-8')
def check_password(self, password):
return flask_bcrypt.check_password_hash(self.password_hash, password)
def __repr__(self):
return "<user '{}'>".format(self.username)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

User 클래스는 sqlalchemy의 db.Model 클래스를 상속받습니다.

user 데이블에 id, email, registered_on, admin, public_id, username, password_hash 컬럼을 만들어 줍니다.


이제 user 테이블을 사용하기 위해 manage.py 파일에 아래와 같이 import 합니다.

1
from app.main.model import user
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

manage.py 파일은 아래와 같습니다.

1
$ sudo vim manage.py
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
import os
import unittest
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from app.main import create_app, db
from app.main.model import user
app = create_app(os.getenv('BOILERPLATE_ENV') or 'dev')
app.app_context().push()
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
@manager.command
def run():
app.run()
@manager.command
def test():
"""Runs the unit tests."""
tests = unittest.TestLoader().discover('app/test', pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
if __name__ == '__main__':
manager.run()
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

migrateCommand로 db를 생성하겠습니다.

init 명령으로 초기화 합니다.

1
2
3
4
5
6
7
8
$ python manage.py db init
Creating directory /home/ngle/nGleAPI/migrations ... done
Creating directory /home/ngle/nGleAPI/migrations/versions ... done
Generating /home/ngle/nGleAPI/migrations/script.py.mako ... done
Generating /home/ngle/nGleAPI/migrations/env.py ... done
Generating /home/ngle/nGleAPI/migrations/alembic.ini ... done
Generating /home/ngle/nGleAPI/migrations/README ... done
Please edit configuration/connection/logging settings in '/home/ngle/nGleAPI/migrations/alembic.ini' before proceeding.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

migrate 명령으로 db를 생성합니다.

1
2
3
4
5
$ python manage.py db migrate --message 'initial database migration'
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'user'
Generating /home/ngle/nGleAPI/migrations/versions/faba1bd89e48_initial_database_migration.py ... done
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

upgrade 명령으로 적용합니다.

1
2
3
4
$ python manage.py db upgrade
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> faba1bd89e48, initial database migration
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

정상적으로 생성되었다면 main 폴더 아래 flask_boilerplate_main.db 파일이 생성됩니다.

이후로 database model이 변경될 경우 migrate 과 update 명령을 실행하면 됩니다.


여기까지해서 User 테이블을 만들었습니다.


tree 명령으로 디렉터리를 확인하면 아래와 같이 migrations 폴더가 생성됩니다.

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
$ tree
.
├── app
·· ├── __init__.py
·· ├── main
···· ├── config.py
···· ├── controller
······ └── __init__.py
···· ├── flask_boilerplate_main.db
···· ├── __init__.py
···· ├── model
······ ├── __init__.py
······ ├── __pycache__
········ ├── __init__.cpython-36.pyc
········ └── user.cpython-36.pyc
······ └── user.py
···· ├── __pycache__
······ ├── config.cpython-36.pyc
······ └── __init__.cpython-36.pyc
···· └── service
···· └── __init__.py
·· ├── __pycache__
···· └── __init__.cpython-36.pyc
·· └── test
·· ├── __init__.py
·· ├── __pycache__
···· └── test_config.cpython-36.pyc
·· └── test_config.py
├── manage.py
├── migrations
·· ├── alembic.ini
·· ├── env.py
·· ├── __pycache__
···· └── env.cpython-36.pyc
·· ├── README
·· ├── script.py.mako
·· └── versions
·· ├── 95f4f62caf8d_initial_database_migration.py
·· └── __pycache__
·· └── 95f4f62caf8d_initial_database_migration.cpython-36.pyc
├── __pycache__
·· └── manage.cpython-36.pyc
└── requirements.txt
15 directories, 26 files
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX