미국은 거의 맥을 사용해서 그런지 설치도 맥 버전으로만 설명해서 그냥 따라하다가 오류가 나서 또 한참 헤맸다.
일단 Flask와 Falsk-SQLAlchemy를 설치한 후 코드를 작성하고 run을 하려니 FLASK_APP을 실행할 수 없다고 나왔다.
그래서 확인해보니 윈도우에서는 실행시키는 명령어가 달랐다 . cmd에서 할 때와 PowerShell에서 할 때도 다르게 작성해야 하는데
내 컴퓨터에서는 뭐가 꼬였는지 cmd로 할때는 계속 실행이 안되었다(update ==> 안되었던 이유: FLASK_APP = app.py
처럼 등호 양 옆에 공백이 있어서는 안된다!!!!! FLASK_APP=app.py
로 작성되어야 함). 그래서 PowerShell로 들어가서 했더니 된다.
$env:FLASK_APP = "flask-hello-app.py"
flask run
++ Command Line Interface of Flask
위의 코드를 실행시키면
Running on http://127.0.0.1:5000/
과 같이 development server가 생기는데 이는 http://IP주소:포트넘버/
이다. 왜냐하면 웹 서버도 우리의 로컬 머신 안에 있고 우리의 로컬 머신에서 연결을 허용할 것이기 때문이다. shrotcut은 localhost:5000
# flask-hello-app.py
from flask import Flask
app = Flask(__name__) ## flask application을 만드는 가장 기본적인 방법
## 홈페이지에 가서 내가 쓴 Hello World를 출력하고자 한다.
@app.route('/') # 연결을 위한 homepage route
def index(): # route handler, Index is a standard name for the route handler that listens for connections to the root route and figures out what do next.
return 'Hello World!'
@app.route is a Python decorator. Decorators take functions and returns another function, usually extending the input function with additional("decorated") funcionality. @app.route is a decorator that takes an input function index()
as the callback that gets invoked when a request to route /
comes from a client.
@app.route('/')
을 처음 봐서 이해가 잘 안갔었는데 찾아보고 내가 이해한 바로는, localhost:5000 + 괄호 안에 있는 문자열이 url이 되고 해당 url에서(url을 방문하면) index()가 리턴한 결과를 보여준다.
__main__
if __name__ == '__main__':
app.run()
app.py
스크립트 하단에 위와 같은 메소드를 정의하면 방금전에 사용한 실행코드를 이용하지 않아도 된다. 그냥 app.py
를 실행하면 app.run()
을 호출하고 flask app도 실행된다.
우리가 스크립트를 실행하면 파이썬 인터프리터에 의해 스크립트의 __name__
은 __main__
으로 설정이되고 스크립트의 모든 코드를 실행한다. 그리고 끝에 다다라서 if __name__ == 'main'
을 찾으면 이것을 True
로 판단하고 app.run()
을 호출하여 Flask app이 실행된다.
개인적으로 첫번째 방법으로 실행할 때는 운영체제에 따라 코드가 달라져서 헤매었던 반면 이 방법은 상대적으로 나한테 더 간단하게 느껴져서 이 방법이 더 좋았다.
flask_sqlalchemy
에서 SQLAlchemy
클래스를 import하여 Flask application에 연결하는데 사용하며 SQLAlchemy 사용을 시작한다.db = SQLAlchemy(app)
로 설정하는데 우리의 Flask application인 app
을 넣어준다.
Dialect + DBAPI(ex. postgresql + psycopg2)로 작성할 수도 있지만 DBAPI를 적는 것은 선택 사항임. 또한 Postgres를 사용하는 파이썬 어플리케이션에서는 기본으로 psycopg2가 데이터 베이스 어답터로 설정되어 있다.
# flask-hello-app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres@localhost:5432/example'
db = SQLAlchemy(app)
@app.route('/')
def index():
return 'Hello World!'
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
db
represents an instance of our database that we can interact using SQLAlchemy and it comes from the SQLAlchemy class that we had imported from the Flask SQLAlchemy library.
db
는 SQLAlchemy 기반 인터페이스를 제공하는데 특히 db
는 다양한 objects를 제공한다.
db.Model
: Ability to create and manipulate data modelsdb.session
: Ability to create and manipulate database transctionsperson
class with db.Model
class Person(db.Model): # By inheriting from db.Model we wound up linking and connectiong to SQLAlchemy's mappings between classes and tables.
__tablename__ = 'persons' # 기본적으로 SQLAlchemy는 클래스명의 소문자 버전으로 테이블 이름이 설정되지만 변경하고 싶을때
id = db.Column(db.Integer, primary_key=True) # two attributes: id, name
name = db.Column(db.String(), nullable=False)
원래 클래스에서는 초기화 메소드가 있어야하지만 여기서는 db.Column
에서 구체화 해주었으므로 초기화 메소드가 필요 없다.
앞서 만든 클래스를 실제로 테이블로 생성한다.
db.create_all()
: Detects models and creates tables for them (if they don't exist)SQLAlchemy에서는 정수값을 가진 id가 있을때 id값을 자동 증가시킨다. 만약 빈 테이블에 'Amy'라는 이름을 추가했다면 그 아이디는 자동으로 1이 된다. 그 다음 이름을 추가하면 id는 2, 그 다음은 3과 같다.
데이터베이스에서 INSERT INTO ...
를 이용해 첫번째 레코드를 추가한다.
파이썬 스크립트에서 해당 데이터베이스의 값을 불러올때는 다음과 같다.
@app.route('/')
def index():
person = Person.query.first() # give us the first record inside of our persons table.
return 'Hello ' + person.name # name은 클래스에서 선언했던 attribute.
debug mode를 켜두면 어플리케이션에 변동이 있을 때마다 서버를 자동으로 다시 시작해준다.(수정사항의 실시간 반영)
if __name__ == '__main__':
app.run(debug=True)
과 같이 디버그 모드를 설정할 수 있다.
We can experiment with our app using the interactive mode of the Python interpreter.
flask-hello-app.py
-> flask_hello_app.py
(파이썬 인터프리터에서 인식할 수 있도록)ren flask-hello-app.py flask_hello_app.py
import flask_hello_app
--> deprecation warning 발생app.config[SQLALCHEMY_TRACK_MODIFICATIONS'] = False
exit()
후 다시 파이썬 인터프리터 접속import flask_hello_app
from flask_hello_app import Person
Person.query.all()
[<Person 1>]
Person.query.first()
: person
클래스의 가장 첫 레코드를 불러옴Person.query.filter(Person.name == 'Amy')
: 이름이 Amy인 레코드들의 base query objects를 가져옴Person.query.filter(Person.name == 'Amy').first()
: 필터가 적용된 첫 레코드만 불러옴Person.query.filter(Person.name == 'Amy').all()
: 필터된 모든 레코드들을 불러옴위의 실행 결과에서는 Person 1, Person 2 등으로 클래스의 이름과 ID만이 출력되고 이름이 출력되지 않는다.
이름이 나오도록 dander wrapper method를 다음과 같이 정의할 수 있다.
def __repr__(self_:
return f'<Person ID: {self.id}, name: {self.name}>'
위와 같은 메소드를 Person
클래스에 정의하고 파이썬 인터프리터에서 다시 Person.query.first()
를 하면 결과 값은 Person ID: 1, name: Amy
가 나온다.
from flask_hello_app import db, Person
person = Person(name='Amy') # Create an instance of a Person, setting its attribute
db.session.add(person) # A method on the Session interface in SQLAlchemy
# This will queue up a `INSERT INTO .... VALUES ('Amy');` statement in a transaction that is managed by db.session.
db.session.commit()
String(size)에서 size는 string의 최대 길이를 의미한다. Postgres에서는 다양한 character string를 나타낼 수 있기 때문에 size 변수를 생략 할 수 있다. 그래서 db.string()일 때는 varchar(가변형) 데이터 타입을 의미한다.
CREATE TABLE
을 할 때 column name, column datatye 뒤에 오는 PRIMARY KEY
, NOT NULL
과 같은 제한 사항을 의미한다.db.Column()
내에 위치하며 데이터 타입을 지정한 후에 설정된다.nullable=False
는 SQL에서의 NOT NULL
과 동일하다.unique=True
는 SQL에서의 UNIQUE
와 동일하다.Class User(db.Model):
...
name = db.Colum(db.String(), nullable=False, unique=True)
또는 정수 관련해서 constraint를 실행할 때는 db.CheckConstraint
를 사용한다.
Class Product(db.Model):
...
price = db.Column(db.Float, db.CheckConstraint('price>0'))