INSERT INTO topics (title, body) VALUES ('SQLite', 'SQLite is ...');
SELECT * FROM topics;
입력한 데이터가 잘 출력되는 것을 볼 수 있다.
import sqlite3
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
Python에는 SQLite가 내장되어 있기 때문에 따로 설치하지 않아도 바로 import 해서 사용할 수 있다.
sqlite.connect() 함수로 DB 파일을 열고, cursor를 설정해준다.
cursor.execute('SELECT * FROM topics;')
topics = cursor.fetchall()
cursor.execute() 함수로 쿼리를 실행할 수 있다. 쿼리가 실행된 결과의 가장 앞에 cursor가 위치하고, cursor.fetchall() 함수로 해당 내용을 전부 가져올 수 있다.
이렇게 가져온 정보를 print해보자.
print(topics)
구문을 python 파일에 추가하고, 터미널에서 방금 작성한 python 파일을 실행한다.
topics에 DB 내용이 잘 들어왔다.
import sqlite3
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('SELECT * FROM topics;')
topics = cursor.fetchall()
for topic in topics:
print(topic[0], topic[1])
conn.close()
출력이 잘 된다.
import sqlite3
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
title = input('title : ')
body = input('body : ')
cursor.execute('INSERT INTO topics (title, body) VALUES (?, ?);', (title, body))
conn.commit()
conn.close()
import read
마지막에 import read 해주어서 입력 후 바로 테이블 내용을 출력하게 해주었다.
각 함수마다 sqlite connection을 생성한다. conn.close()로 닫아주는 것을 잊지 말자. template() 함수 내에 다음과 같이 작성했다.
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('SELECT * FROM topics')
topics = cursor.fetchall()
conn.close()
tuple로 정보를 받아오게 되고, dictionary에 해당했던 문법 대신 tuple에 맞도록 출력 부분을 topic[0], topic[1] 이런 식으로 넣어준다.
for topic in topics:
liTags += f'<li><a href="/read/{topic[0]}/">{topic[1]}</a></li>'
read 함수에서는 해당하는 번호의 게시물 내용을 가져오도록 작성했다.
def read(num):
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('SELECT * FROM topics WHERE id=?', (num,))
topic = cursor.fetchone()
conn.close()
content = f'<h2>{topic[1]}</h2>{topic[2]}'
return template(content, num)
(num,) 이라고 쉼표를 붙여준 것은 (num)으로 넘길 시 그냥 숫자로 넘어가고 (num,)으로 넘기면 튜플로 넘어가기 때문이다.
기존 insert는 전역 변수 리스트인 topics에 항목을 추가하는 방식이었고, 이제 SQLite DB를 연결했으니 DB에 저장하는 방식으로 변경해보았다.
@app.route("/create_process/", methods=['POST'])
def create_process():
title = request.form['title']
body = request.form['body']
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('INSERT INTO topics (title, body) VALUES (?,?)',(title, body))
nextId = cursor.lastrowid
conn.commit()
conn.close()
return redirect(f'/read/{nextId}')
처음에는 SELECT 함수로 가장 마지막 id값을 가져오는 것으로 코딩했는데, cursor.lastrowid라고 마지막 row의 id값을 가져오는 매우 훌륭한 내장 변수가 존재하고 있었다.
입력이 잘 된 것을 확인할 수 있다.
@app.route('/delete/<int:num>/')
def delete(num):
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('DELETE FROM topics WHERE id=?', (num,))
conn.commit()
conn.close()
return template(f'<h2>Delete Succeeded</h2>Content number {num} deleted.')
Delete 함수도 구현했다.
HBase 글이 삭제된 것을 확인할 수 있다. 잘 작동된다.
(디자인이 바뀐 것은 부트스트랩을 사용해 버튼 속성을 변경해주었고 갑자기 CSS 복습을 해서...)
이렇게 2주 간의 웹 입문 교육이 마무리되었다.
수업이 끝나고 게시물 수정 기능도 구현해보았다. Create와 Delete를 적절히 섞으면 되니 어렵지는 않다.
@app.route('/modify/<int:num>/')
def modify(num):
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('SELECT * FROM topics WHERE id=?', (num,))
topic = cursor.fetchone()
conn.close()
content = f'''
<h2>Modify</h2>let\'s modify!<br>
<form action="/modify_process/{num}/" method="POST">
<p><input type="text" name="title" value="{topic[1]}"></p>
<p><textarea name="body">{topic[2]}</textarea></p>
<p><input type="submit" value="수정"></p>
</form>
'''
return template(content)
@app.route("/modify_process/<int:num>/", methods=['POST'])
def modify_process(num):
title = request.form['title']
body = request.form['body']
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('UPDATE topics SET title = ?, body = ? WHERE id=?',(title, body, num))
conn.commit()
conn.close()
return redirect(f'/read/{num}')
modify()와 modify_process()를 작성했다.
modify()는 수정하는 화면을 보여주는데 create()와 유사하나 이미 작성된 내용을 입력 창에 나타나게 만들었다.
modify_process()도 create_process()와 유사한데, 매개변수로 num일 넘겨받아 id 값에 해당하는 row를 UPDATE 하도록 구현했다.
DB2 게시물에서 수정 버튼을 눌러보면,
위와 같이 수정 화면이 나타난다.
내용을 변경한 후 수정 버튼을 눌러보면,
내용이 변경된 것을 확인할 수 있다.
데이터를 받아서 id, title, body에 접근할 때 topic[0], topic[1] 이렇게 인덱스 값으로 접근하는 것은 위험하다. dictionary로 변환하는 기능이 필요해 보인다.
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute('select * from topics')
result = cursor.fetchall()
하면 dictionary로 구성된 list로 반환이 된다고 한다.
오늘로 이고잉 강사님의 강의가 끝났다. 2주 동안 나름 정이 든 것 같은데 마지막이라니 아쉬운 마음이 들었다. 오랜만에 웹을 만져봤는데 변한 것도 많고 (javaScript의 let, const나, Flask 등...) 내가 참 오랫동안 손을 놓고 있었구나 깨닫고 겸손해지는 시간이었다. 어쨌든 내 손으로 그럴싸한 웹사이트 하나 만들어내서 뿌듯하다. 게시물 등록 삭제 수정이 되는 홈페이지라니! github에는 HTML, CSS, JavaScript 등 정적인 페이지만 호스팅 가능해서 Flask로 만든 동적인 웹은 어디에 올리면 좋을지 고민이다. Glitch는 월 8달러를 내야 24시간 서비스할 수 있다는데, 조금 괜찮은 걸 만들면 이용해보아도 좋을 것 같다.