SQL 쿼리를 sqlalchemy로 바꾼 방식을 틈날때마다 하나씩 추가하려함


# update


# 예) 게시판 테이블에 회원번호 칼럼이 있고 이를 회원 테이블로부터 가져와서 해당 회원에 맞게 업데이트 해야하는 상황이다
# update bbs set user_num = (select user_num from user where user.id = bbs.id)

#UPDATE table_one SET column_one = (SELECT column_one FROM table_two WHERE table_one.column_two = table_two.column_two)
query = session.query(table_one).filter(table_onw.column_two == table_two.column_two)
query = query.update({"column_one": table_two.column_one}, synchronize_session=False) # synchronize_session이 핵심!

python-flask에서 DB와의 커넥션은 엔진을 만들고 이를 바탕으로 session을 가져오는 방식으로 진행한다


# Engine을 통해서 session을 가져온다
Engine = create_engine( ~~~~~)
Session= scoped_session(sessionmaker(~~~~~, bind = Engine)

#session을 통해서 테이블의 데이터를 가져올 수 있다.
session.query(table).all() # 1) 해당 테이블 전체  가져오기
session.query(table).first() # 2) 해당 테이블에서 한줄만 가져오기

# 내가 해당 테이블의 모든 칼럼 정보가 필요로 하다면 위에처럼 가져오는게 맞다. 하지만 특정 칼럼 정보만 필요하다면 
session.query(table.column_one).first() # 3) 이런식으로 특정 칼럼을 명시해주는 것이 퍼포먼스 상으로 좋다.

# 하지만 만약에 특정 칼럼만 가져와서 데이터 확인 후 이를 업데이트 해야하는 경우가 있다면 위의 3)의 경우를 사용할 수 없다.

row = session.query(table).first() # 4)

row.column = new_value 
or 
setattr(row, column, new_value) 

# 보통 session으로 가져왔을 경우의 update 방식이다. 이 경우는 table에서 특정 칼럼을 지칭하지 않았다.
# 하지만 이럴 경우 위에서 언급했듯이 퍼포먼스의 이슈가 있고 좀더 빠르게 처리하기 위해선 특정 칼럼 가져오기 + update를 해야한다.
# 3)에서 했던 방식으로 update를 할 경우.. 즉

row = session.query(table.column).first() # 5)
row.column = new_value or setattr(row, column, new_value)
# 위 방식으로 할 경우 업데이트가 되지 않는다.
# 왜냐하면 4번의 결과값과 5번의 결과값은 확연히 다르기 때문이다.

# 4번은 colletion_result이므로 setter가 존재한다. 하지만 5)번은 4번과 모양은 같지만 타입은 tuple에 불과하다. 그렇기에 setter가 존재하지 않는다.
# https://stackoverflow.com/questions/51391039/cant-set-attribute-on-result-objects-in-sqlalchemy-flask 를 보면 자세히 알 수 있다.

# 그렇다면 특정 칼럼만 가져오면서 update를 할 수 있는 방법은 없을까?
# rom sqlalchemy.orm import load_only 를 사용하면 된다.

query = session.query(Table).options(load_only("column_one", "column_two")) # 6)
# 위 방법은 컬럼을 단 두개만 가져온다. 또한 setter를 가지고 있기에 update를 사용할 수 있다.
# 실제 0.76 정도 걸리던 실행시간이 0.40 정도로 줄일 수 있었다.

python-devel 패키지? 가 없어서 발생하는 에러라고 한다.

설치된 파이썬 버젼에 맞춰서 설치해주면 되는데..


링크 : 스택오버플로우


나는 안된다.



내 에러는 위와 같은데 setup.py를 하는 도중 에러가 발생하고, 아래서 세번째 줄을 보면 -fpic -I 어쩌고 하는 부분에서 3.6이 언급되어있다.


링크 : 위 관련 블로그


나는 여태 3.4버젼을 사용하니 python34-devel을 설치하면 되는줄 알았는데 얘는 그게 아니었다.

그래서 python36-devel로 설치한 후 원하는 패키지를 설치하니 성공하였다...


동시에 많은 수의 requests를 날리기 위해 async를 사용해야했다.

그리고 간단한 테스트 등은 주피터 노트북이 편하기에 거기서 스크립트를 작성하여 async로 날렸는데 event loop is running 에러가 뜬다.


원인은 주피터 내에 있는 tornado 때문인듯(?)

tornado가 5버젼 이상이면 그리하다고 하여

torando를 다운그레이드 하였다.


!pip install tornado==4.5.3 인가.. 암튼.. 5보다 낮게.


jupyter notebook event loop tornado로 검색하면 많이 나올 것이다.

date_time_str = 'Tue Sep 18 2018' date = 'Tue Sep 18 2018 17:51:39' date_time_obj = datetime.strptime(date, '%a %b %d %Y %H:%M:%S') # 얘는 문자를 datetime 타입으로 date_time = datetime.strftime(date_time_obj, '%a %b %d %Y') # 얘는 datetime을 문자로 변경해준다 # 이 두개의 차이점은 strptime이냐 strftime 이냐 이 차이이다. # p이냐 f이냐에 따라서 달라진다. print(date_time_obj) print(date_time)

추가로 저 %에 따라서 날의 표현이 달라진다
"Jun 28 2018 at 7:40AM" -> "%b %d %Y at %I:%M%p"
"September 18, 2017, 22:19:55" -> "%B %d, %Y, %H:%M:%S"
"Sun,05/12/99,12:30PM" -> "%a,%d/%m/%y,%I:%M%p"
"Mon, 21 March, 2015" -> "%a, %d %B, %Y"
"2018-03-12T10:12:45Z" -> "%Y-%m-%dT%H:%M:%SZ"
할때마다 추가해야지. 특정 모양대로 사용하면 편하다


다만 datetime 객체를 사용하는것은 생각보다 코스트가 높다.

그리고 저렇게 일일히 신경 쓰기 싫으면 datetime.parser를 불러내서 사용하는게 제일 편하다.


pip install mysqlclient

이런식으로 하게 될 경우 c++ 에러가 뜬다.
물론 가장 간단하게는 비주얼 스튜디오를 설치하면 되지만 시간도 오래걸리고 용량도 크기에 다른
방법을 찾아보았다.

찾은 방법은 wheel 파일을 다운 받는것. 아마 파일 그대로 다운 받아서 설치하는 방식인듯..
아래 두 링크는 모두 stackoverflow이다
wheel 인스톨 방법
wheel 인스톨시 에러날때
1. 간단히 설명하자면 wheel이 있는 곳에서 원하는 패키지를 다운 받는다1
2. 패키지 명에 cp 라고 적혀있는데 이는 파이썬 버젼을 뜻하는 것이라 한다. 3.6이면 cp36을 받으면 된다
3. 마지막으로 다운 받은 경로 전체를 적어줘야한다
# 뒤에 파일명에는 경로가 전체 
pip install C:/desktop/folder/filename/파일명.whl
이런식으로


0. sqlalchemy는 기존의 자바-스프링과 다른듯.

매퍼가 따로 필요없나? 싶기도 하고, mybatis와 같은 프레임웍인가 싶기도 하고

아직도 감을 못잡겠다.


1. DB와의 접속을 위에 session()을 선헌해주고 이를 가져온다.

#공간확보
session = Session() # DB 접속을 위해 세션에 연결한다. 당연히 이 Session은 create_engine을 통해 DB와 연결을 해야한다.. 이건 나중에..

query = session.query(users)  #괄호 안에 테이블, 또는 테이블.칼럼명(users.id) 이런식으로 하여 연결한다
# 여기서 query 자체는 그냥 쿼리문이다! 데이터를 가져오려면 
query.all()
query.first() # 등을 해야한다

query = session.query(users).all() # select * from users
query = session.query(users.id) # select id from users
query = session.query(users.id, users.email) # select id, email fromusers

# filter, func 등을 사용하면 where, 집계 함수 등을 사용할 수 있다.
query = session.query(user).filter(user.id = 'test') # select * from users where id = 'test'
query = session.queyr(user).filter(user.id = 'test).filter(user.email = 'gamil') # select * from user where id = 'test and email = 'gmail'
# 위 쿼리는 모양이 바로 이해가 안간다. 이럴경우 and_ 를 임포트 해서 filter에 사용하면 된다.(or_ 등도 다 임포트 해야함)
query = session.query(user).filter(and_(user.id = 'test', user.email = 'gmail')

#all()를 통해 가져온 값은 리스트이고 sqlalchemy_results 객체이다.
# 쉽게 생각하면 해당 테이블의 칼럼 값들의 튜플 형태이다.

# 결과값에서 칼럼들의 값을 동적으로 뽑고 싶은경우(또는 넣고싶은 경우)에는 getattr, setattr을 사용한다
getattr(query, id)
setattr(query, id, 'kkk')
# 이거를 왜 언급하냐면 쿼리문의 결과값은 리스트가 아니라서 query['id'] 이런식으로 못가져온다.
# query.id 이렇게 해야 가져와진다. 
# dot point는 변수를 통해서 접근이 안된다
temp = 'id'
query.temp # query.id로 인식을 못함

'파이썬 > flask' 카테고리의 다른 글

flask의 목표  (0) 2018.08.06

물론 앞으로 내 길이기도 하지만

일단은 자바 스프링을 까먹기 전에 최대한 flask와 비교하는 것을 작성해보려 함..

시간 나는 대로 튜토리얼을 따라하며 spring과 비교 후 기존에 내 서비스를 flask로 리팩토링 하는게 목표.

기간은 무한대...

'파이썬 > flask' 카테고리의 다른 글

sqlalchemy 간략 정리  (0) 2018.09.02


이번에 수정한 부분은 위와 같다.

chart 클래스가 버튼을 생성하고, 그 버튼의 값을 entry에 보여줘야 하므로

chart클래스가 entry타입을 받게끔 하였다.

그리고 버튼을 클릭하면 값이 보이게 하는 메서드를 밖으로 빼서 만들었다.

문제는 문장을 보여줘야하므로 바뀌는 값이 계속 저장되게끔 해야하는데 이 구성을 어떻게 매끄럽게 할지가 가장 큰 고민이다.


from tkinter import *;
from chart import *;
from display import *;

window = Tk();
window.title("Maplotlib Calc");
window.geometry("500x400");
# 결과들을 보여주는 아웃풋
output = display(window, 0, 0);
out_entry = output.make_Entry(0,0,70,"light green")
# class를 생성할시엔 무조건 frame row, col을 받게끔 해야함
chart = chart(window,2,0,out_entry); # 버튼을 만들기 위함
chart.make_button();
window.mainloop();

from tkinter import *;
class chart:
    def __init__(self, window, row, column, output_entry):
        self.window = window;
        self.pad = Frame(window);
        self.row = row;
        self.column = column;
        self.outentry= output_entry;
        self.pad.grid(row = self.row, column = self.column,sticky = W);

    def make_button(self):
        char_lst = ['LINE', 'SCATTER']
        r , c = 0,0
        for k, v in enumerate(char_lst):
            def inner(index = k):
                self.show(index)
            Button(self.pad, text = v, width =10, command = inner).grid(row = r, column = c)
            c +=1;

    def show(self, index): # 버튼만 보여주는 메서드
        button_pad = Frame(self.window)
        button_pad.grid(row =3, column =0, sticky = N);
        if index == 0:
            cr = {'black' : 'k', 'green':'g', 'red':'r'};
            ls = {'solid' : '-', 'dashed' : '--', 'dashed dot' : '-.'};
            marker = {'point' : '.', 'circle' : 'o', 'triangle_up' : '^'};
            category = [cr, ls, marker];
            r = 0;
            c = 0;
            record_lst = [];
            for i in range(len(category)):
                for key,value in category[i].items():
                    def inner(k = key, v = value, index =i):
                        print(i)
                        del record_lst[i:i+1];
                        record_lst.insert(i,{k,v});
                        self.button_action(k,record_lst);
                    Button(button_pad,text = i, width = 10, command = inner).grid(row = r, column=c);
                    c += 1;
                if c > 2:
                    c = 0;
                    r += 1;

    def button_action(self,key,lst):
        #str = "plt.plot([10, 20, 30, 40], [1, 4, 9, 16], c= '%s', ls='%s', marker='%s')" %(lst[0][key],lst[1][key], lst[2][key]);
        print(lst);
        self.outentry.delete(0, END);
        self.outentry.insert(END, "Test");


기존에 진행중이던 것들이 어느정도 끝났기에 얼른 이것을 마무리 하려한다.

지난번에는 main 클래스에 모든것을 다 넣고서 돌아가게끔 하는게 목적이었고 이번엔 지난번 것을 바탕으로

나름 클래스화 하여 구성해보려 한다.


메인 화면은 크게

1. 내가 선택한 파라미터 명령어가 나오게 하는 것

2. 차트 종류를 선택하면 그에 해당하는 파라미터가 등장

3. 파라미터 버튼 클릭시 1번 화면 업데이트

4. 생성 버튼 클릭시 matplot 화면을 보여줌

5. 파라미터 클릭시 실시간 변화...


이렇게 5개의 기능이 목표이다.



from tkinter import *;
from chart import *;
from display import *;

window = Tk();
window.title("Maplotlib Calc");
window.geometry("400x300");
# 결과들을 보여주는 아웃풋
output = display(window, 0, 0);
output.make_Entry(0,0,70,"light green")
# class를 생성할시엔 무조건 frame row, col을 받게끔 해야함
chart = chart(window,2,0); # 버튼을 만들기 위함
chart.make_button();
window.mainloop();

기본적으로 tkinter를 이용해 gui를 구성, 현재 위 메인단에서 클래스는 하나는 버튼용, 하나는 out풋 용으로 만들었다


from tkinter import *;
class display():
    def __init__(self, window, row,col):
        self.window = window;
        self.row = row;
        self.col = col;
        self.tpfr = Frame(window);
        self.tpfr.grid(row = self.row, column = self.col, sticky = N);

    def make_Entry(self, row, col, width, color):
        display = Entry(self.tpfr, width = width, bg=color)
        display.grid(row = row, column = col);

단순히 엔트리(녹색 입력창?) 을 만들기 위한 클래스, 모든 클래스는 frame 생성을 위해 row, col을 받게끔 설정


from tkinter import *;
class chart:
    def __init__(self, window, row, column):
        self.window = window;
        self.pad = Frame(window);
        self.row = row;
        self.column = column;
        self.pad.grid(row = self.row, column = self.column,sticky = W);

    def make_button(self):
        char_lst = ['LINE', 'SCATTER']
        r , c = 0,0
        for k, v in enumerate(char_lst):
            def inner(index = k):
                self.show(index)
            Button(self.pad, text = v, width =10, command = inner).grid(row = r, column = c)
            c +=1;

    def show(self, index):
        button_pad = Frame(self.window)
        button_pad.grid(row =3, column =0, sticky = N);
        print("show show", index)
        if index == 0:
            cr = {'black' : 'k', 'green':'g', 'red':'r'};
            ls = {'solid' : '-', 'dashed' : '--', 'dashed dot' : '-.'};
            marker = {'point' : '.', 'circle' : 'o', 'triangle_up' : '^'};
            category = [cr, ls, marker];
            r = 0;
            c = 0;
            for i in range(len(category)):
                for key,value in category[i].items():
                    Button(button_pad,text = key, width = 10).grid(row = r, column=c);
                    c += 1;
                if c > 2:
                    c = 0;
                    r += 1;

문제의 버튼 클래스, 처음에 차트 종류를 보여주고, 클릭하면 파라미터가 보여질수있게끔 코드를 짜다보디 이런모양이 되었다..

+ Recent posts