Flask-SQLAlchemy

rang-dev·2020년 3월 17일
0

Install

미국은 거의 맥을 사용해서 그런지 설치도 맥 버전으로만 설명해서 그냥 따라하다가 오류가 나서 또 한참 헤맸다.
일단 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

Hello App with Flask-SQLAlchemy - Part 1

# 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()가 리턴한 결과를 보여준다.

Alternative approach to run a Flask app: using __main__

if __name__ == '__main__':
   app.run()

app.py 스크립트 하단에 위와 같은 메소드를 정의하면 방금전에 사용한 실행코드를 이용하지 않아도 된다. 그냥 app.py를 실행하면 app.run()을 호출하고 flask app도 실행된다.
우리가 스크립트를 실행하면 파이썬 인터프리터에 의해 스크립트의 __name____main__으로 설정이되고 스크립트의 모든 코드를 실행한다. 그리고 끝에 다다라서 if __name__ == 'main'을 찾으면 이것을 True로 판단하고 app.run()을 호출하여 Flask app이 실행된다.

개인적으로 첫번째 방법으로 실행할 때는 운영체제에 따라 코드가 달라져서 헤매었던 반면 이 방법은 상대적으로 나한테 더 간단하게 느껴져서 이 방법이 더 좋았다.

라우팅 참고자료

Connection to the Database

  • flask_sqlalchemy에서 SQLAlchemy 클래스를 import하여 Flask application에 연결하는데 사용하며 SQLAlchemy 사용을 시작한다.
  • db = SQLAlchemy(app)로 설정하는데 우리의 Flask application인 app을 넣어준다.
  • This would link an instance of a database that we can interact with in SQLAlchemy land to our Flask app.
  • 데이터베이스와 상호작용 하기전에 먼저 해야될 것은 Flask application에서 우리의 데이터베이스에 연결하는 것이다. ==> setting a configuration variable on out application.
  • Flask의 모든 configuration variables는 딕셔너리 app.config에 있다.
  • Flask-SQLAlchemy가 이해할 수 있는 방식으로 URI를 작성해주어야 한다.

Database Connection URI Parts

uri
Dialect + DBAPI(ex. postgresql + psycopg2)로 작성할 수도 있지만 DBAPI를 적는 것은 선택 사항임. 또한 Postgres를 사용하는 파이썬 어플리케이션에서는 기본으로 psycopg2가 데이터 베이스 어답터로 설정되어 있다.

Database Connection된 flask-hello-app.py

# 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!'

db.Model and defining models

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 models
    • 클래스로 정의된 Model들은 데이터베이스에 있는 테이블들로 맵핑된다.
  • db.session: Ability to create and manipulate database transctions

Creating person 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에서 구체화 해주었으므로 초기화 메소드가 필요 없다.

Syncing Models, db.create_all()

앞서 만든 클래스를 실제로 테이블로 생성한다.

  • db.create_all(): Detects models and creates tables for them (if they don't exist)
    • 만약 테이블이 이미 존재한다면 아무 일도 발생하지 않는다.

Auto-incrementing

SQLAlchemy에서는 정수값을 가진 id가 있을때 id값을 자동 증가시킨다. 만약 빈 테이블에 'Amy'라는 이름을 추가했다면 그 아이디는 자동으로 1이 된다. 그 다음 이름을 추가하면 id는 2, 그 다음은 3과 같다.

Inserting Records, Using Debug Mode

Inserting Record

데이터베이스에서 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

debug mode를 켜두면 어플리케이션에 변동이 있을 때마다 서버를 자동으로 다시 시작해준다.(수정사항의 실시간 반영)

if __name__ == '__main__':
    app.run(debug=True)

과 같이 디버그 모드를 설정할 수 있다.

Experimenting in Interactive Mode

We can experiment with our app using the interactive mode of the Python interpreter.

  • 파이썬 파일 이름 변경 flask-hello-app.py -> flask_hello_app.py (파이썬 인터프리터에서 인식할 수 있도록)
    cmd: ren flask-hello-app.py flask_hello_app.py
  • cmd창에서 python 실행
  • import flask_hello_app --> deprecation warning 발생
    • 해결: app에 configuration 추가 --> app.config[SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  • exit()후 다시 파이썬 인터프리터 접속

next

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(): 필터된 모든 레코드들을 불러옴

Dander Wrapper Method

위의 실행 결과에서는 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()

SQLALchemy Data Types

db.string(), db.Text, db.DataTime...

datatype

String(size)에서 size는 string의 최대 길이를 의미한다. Postgres에서는 다양한 character string를 나타낼 수 있기 때문에 size 변수를 생략 할 수 있다. 그래서 db.string()일 때는 varchar(가변형) 데이터 타입을 의미한다.

SQLAlchemy Constraints

  • Column constrainst란 CREATE TABLE을 할 때 column name, column datatye 뒤에 오는 PRIMARY KEY, NOT NULL과 같은 제한 사항을 의미한다.
  • Column constraints는 데이터베이스의 데이터 무결성을 보장하며 데이터가 정확하고 일관될 수 있도록 한다.
  • Constraints는 컬럼의 조건이며 데이터의 유효성을 체크한다. constraint를 위반하는 데이터는 데이터베이스에 추가되지 않는다.
  • SQLALchemy에서 constraints는 db.Column()내에 위치하며 데이터 타입을 지정한 후에 설정된다.
    • nullable=False는 SQL에서의 NOT NULL과 동일하다.
    • unique=True는 SQL에서의 UNIQUE와 동일하다.

Example

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'))
profile
지금 있는 곳에서, 내가 가진 것으로, 할 수 있는 일을 하기 🐢

0개의 댓글