sqlalchemy_query.pdf
0.05MB

유다시티 fullstack수업 Study note입니다.

 

Tech Stack

Flask - Python web frame work

PostgreSQL - Relational Database

Psycopg2 - Python library to connect  data base to a Flask app

SQLAlchemy - Python library to connect  data base to a Flask app

Flask-SQLAlchemy - Flask extention for using SQLAlchemy more easily

 

Interacting with databases

PostgreSQL is one of popular relational Database Management System

-There are many other relational DB management system (MySQL Oracle SQLite and so on..)

-Non-relational DBMS would be like MongoDB, cassandra ..

 

Database Application Programming Interfaces (DBAPIs)

-used to interact with a database from another language

- For python there are DBAPI modules for different DBMS

postgresql - psycopg2(DBMS - DBAPI) / SQLite - sqlite3 / mySQL - mysql.connector

- psycopg2 is python module that sends sql query to LOCAL server

- SQLAlchemy is ORM model but it has DBAPI in it, so it eventually send queries to a server. 

 

SQL (structured query language)

- There are dialects per each DB management systems

- DBMS recieves query and EXCUTES it by its engine.

 

Key concepts : Client, Server, TCP/IP, Port, connection, session, transaction, commit, rollback

 

Postgres와 psql, pgadmin실행/설치 :

postgres같은 경우에 server를 start하고 stop하는 커맨드가 cmd나 git bash에서는 잘 안먹혀서window service app에서 직접 키고 껐다. (start 메뉴에서 service 검색)

psql은 postgres에 기본으로 같이 install 되는 terminal application이라고 할 수 있는데 local로만 접속이 가능하다.

git bash에서는 커맨드가 잘 안먹히고 cmd에서는 된다.(리눅스 환경에서는 잘 될수도 있음)

수업이 리눅스 커맨드 위주라 그냥 pgAdmin이라는 윈도우용 GUI client 이용했음.

 

**postgres clients

command line tools : psql, createdb, dropdb

GUIs : pgAdmin, popSQL

Database adapters(DBapi) : psycopg2 (making a client application in python)

 

*DB와 interaction할때 psql 과 같은 command terminal app이나 GUI를 이용해도 되지만 결국은 프로그래밍을 해야 하기 때문에 DBAPI가 필요하다. DBAPI는 Database Application for "one" Programming "language" Interface라고 할 수 있다. one programing language는 나의 경우는 python. 굉장히 low level library.

(내생각) python이라는게 결국 runtime 환경이므로 파이썬 언어로 run하는 앱인데 데이타베이스랑 interaction할수 있는 app인거 같다. 명령어들을 알맞는 SQL언어로 변환해주고 DBMS의 포트로 리쓰닝하고 센딩하는 앱일듯(내생각)

 

psycopg2:

postgres용 python dbapi library이다. sqlalchemy에 dbapi기능이 포함되어 있으므로, 사용할 필요는 별로 없었으나,

python script를 활용한 db와의 interaction을 배우고, connection, transaction, commit, rollback 등의 개념을 공부하긴 좋았다.

 

psycopg2 예시)

import psycopg2

connection = psycopg2.connect('dbname=example')

cursor = connection.cursor()

cursor.execute('DROP TABLE IF EXISTS table2;')

cursor.execute('''
  CREATE TABLE table2 (
    id INTEGER PRIMARY KEY,
    completed BOOLEAN NOT NULL DEFAULT False
  );
''')

cursor.execute('INSERT INTO table2 (id, completed) VALUES (%s, %s);', (1, True))

SQL = 'INSERT INTO table2 (id, completed) VALUES (%(id)s, %(completed)s);'

data = {
  'id': 2,
  'completed': False
}
cursor.execute(SQL, data)

connection.commit()

connection.close()
cursor.close()

 

SQLAlchemy basics

 

What is SQLAlchemy?

- Object-Relational Mapping library

- Object형이라 구조짜기 편하고, python으로만 코딩할수있고(직접적인 sql안써도 됨), 다양한 DBMS과 호환 (dialects free)되기 때문에 development 단계에서 가벼운 DB system (SQlite) 으로 해보고 나중에 무거운 DB system으로 (Postgre) switch 가능

 

ORM layer

- Highest level of abstraction; maps classes to tables. (uses python objects and classes)

SQL expressions layer

- Lets you compose SQL statements by building Python objects (excutes SQLalchemy expressions)

Engine layer

-Lowest layer of abstraction; looks a lot like interacting directly with a DB-API (excutes raw sql)

-ORM을 전혀 안쓰고, engine layer에서 sqlalchemy 사용할수도 있다. psycopg2와 비슷한 방식의 코드를 써야함. 

Dialect

- DB시스템마다 다른 언어를 통합관리

Connection pool

- connection opening and closing management, network 끊김 관리

-Avoids opening and closing connections for every data change

 

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# 파일이름의 앱의 instance 생성
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://yourid@localhost:5432/example'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# DB intance 혹은 db와 interact하기 위한 interface instance

class Person(db.Model):
  __tablename__ = 'persons'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(), nullable=False)

  def __repr__(self):
    return f'<Person ID: {self.id}, name: {self.name}>'

db.create_all()
# 한번 생성된 테이블은 다시 또 생성되진 않는다

@app.route('/')
def index():
  person = Person.query.first()
  return 'Hello ' + person.name

 

 

 

** 실행시에 debug variable을 true로 해주는 것이 좋다 (서버 restart된다, 코드에 변화있을때마다)

export FLASK_DEBUG=true

flask run

 

**Python interactive mode로 psql처럼 db에 접근해볼 수 있다. (bash나 cmd환경에서)

$ python3

>>> from flask_hello_app import Person, db

>>> Person.query.all()

>>> Person.query.first()

>>> query = Person.query.filter(Person.name == 'Amy')

>>> query.first()

>>> query.all()

>>> person = Person(name='Amy')

>>> db.session.add(person)

>>> db.session.commit()

 

SQLAlchemy REFERENCES (data type과 constraints들)

-flask-sqlalchemy.palletsprojects.com/en/2.x/models/

-www.postgresqltutorial.com/postgresql-data-types/

-docs.sqlalchemy.org/en/latest/core/constraints.html

 

SQLAlchemy LifeCycle (깃에서 애드 커밋 하는 스테이지랑 비슷한 단계가 있다는 정도로만 이해하자)

롤백과 커밋이라는 개념.

-1. Transient: an object exists, it was defined. ...but not attached to a session (yet).

user1 = User(name='Amy')

-2. Pending: an object was attached to a session.

"Undo" becomes available via db.session.rollback().

Waits for a flush to happen

-3. Flushed: about ready to be committed to the database, translating actions into SQL command statements for the engine.

-4. Committed: manually called for a change to persist to the database (permanently); session's transaction is cleared for a new set of changes.

 

MVC

단순히 말하면 model은 DB server고 Controller는 webapp, View는 frontend라고할수 있다.

전체적인 구조를 설계하거나 디버그할때 신경쓰고 있어야할 구조.

** Model이 직접적으로 View를 update하는 화살표가 좀 이상할 수 있는데, 뷰 자체가 컨트롤러에 의해서 모델의 데이터가 바뀌면 자동적으로 바뀌게 bind되어 있을때를 도식화한것.

 

 

Flask 관련 메모

data를 url query에서 받을때

/foo?field1=value1

request.args.get('field1')

form input에서받을때

username = request.form.get('username')

data type application/json 에서 받을때

data_string = request.data

data_dict = json.loads(data_string)

 

**위의 두방식은 optinal second parameter를 쓸수있다. 갖고 온 값이 없는 경우 대체할 값.

ex) request.args.get('field1', 'my default')

 

인풋방식에 따라 get이냐 method냐에 따라 http contenttype과 request body 양식이 다르다 동영상 다운받아놨음

 

**동영상 자료에 에러잡는 모습은 나중에 또 참고할만하다 sessions in controller자료

 

 

Migration

flask-migrate.readthedocs.io/en/latest/

참고문서

 

데이터 베이스 스키마의 버전컨트롤이라고 할 수 있다.

기존의 데이터를 날리지 않고 디비 모델을 바꿀수 있으며, 필요시 이전 버전으로 롤백할수 있음

자세한 방안은 동영상 다운 받아 놓음.

alembic.sqlalchemy.org/en/latest/

alembic은 flask migrate이 underneath에서 사용하는 library

 

경우에 따라 버전 파일을 직접 수정할수 있다

op.execute 이용하여 데이터 수정하거나, op.alter_column 같은 걸 사용할수있다

 

 

Modeling Relationship

sql join table 참고자료

www.sql-join.com/sql-join-types

www.geeksforgeeks.org/sql-join-set-1-inner-left-right-and-full-joins/

 

 

문법

class SomeParent(db.Model):
   __tablename__ = 'some_parents'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(50), nullable=False)
  children = db.relationship('SomeChild', backref='some_parent', lazy=true)
    
Class SomeChild(db.Model):
  id = db.Column....
  name = ...
  some_parent_id = db.Column(db.Interger, db.ForeignKey('some_parents.id'), nullable=False)

backref로 인하여 child11.some_parent 는 child11에 매칭된 parent를 불러온다

lazy loading, eager loading

 

relationship 옵션 참고자료

docs.sqlalchemy.org/en/13/orm/relationship_api.html#sqlalchemy.orm.relationship

backref나 lazy말고도 collection_class, cascade와 같은 추가 option이 있다.

 

parent1=SomeParent(name='hahaha')

child1=someChild(name='hey')

child2=someChild(name='hey2')

child1.some_parent = parent1     **backref를 이용한 파렌트지정

chid2.some_parent = parent2

db.session.add(parent1)

db.session.commit() casecade 기본 세팅때문에 파렌트옵젝트만 애드 커밋해주면 칠드런은 자동생성

 

 

 

Many to Many Relationship Example

order_items = db.Table('order_items',
    db.Column('order_id', db.Integer, db.ForeignKey('order.id'), primary_key=True),
    db.Column('product_id', db.Integer, db.ForeignKey('product.id'), primary_key=True)
)

class Order(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  status = db.Column(db.String(), nullable=False)
  products = db.relationship('Product', secondary=order_items,
      backref=db.backref('orders', lazy=True))

class Product(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(), nullable=False)

두 테이블을 엮어주는 association table이 필요하다 여기 같은 경우에는 order_item

**psql에서 sql 커맨드할때 table이름이 order라서 syntax order관련해서 에러가 날수있음. order주위에 ""를 넣어줄것

select * from "order"

'백엔드 > 유다시티수업' 카테고리의 다른 글

4.2 kubernetes, AWS, EKS  (0) 2021.01.12
4.1 Docker, containerization  (0) 2021.01.09
3. Identity and Access Management  (0) 2020.12.27
2. API development and Documentation  (0) 2020.12.26

+ Recent posts