
참고: jupyter notebook에서 %를 앞에 붙이면 cmd창에서 해당 명령어를 실행하겠다는 의미
import psycopg2
# 데이터베이스 연결 설정
conn = psycopg2.connect(
host="localhost", #데이터베이스 호스트 이름
port=5432,
database="postgres", #데이터베이스 이름
user="postgres", #데이터베이스 사용자 이름
password="123" #데이터베이스 비밀번호
)
# 커서 생성
cur = conn.cursor()
cur.execute("SELECT * FROM user_info")
rows = cur.fetchall()
for row in rows:
print(row)
query = "INSERT INTO user_info VALUES ('chris2', '김객곽', '9303132984027', 'SK', '01048484848');"
cur.execute(query)
conn.commit()

conn.rollback()
query = "UPDATE user_info SET user_name = '김곽객' WHERE user_name = '김객곽';"
try:
cur.execute(query)
conn.commit()
except Exception as e:
conn.rollback()
print(f"Error: {e}")
cur.close()
conn.close()
query = "INSERT INTO user_info VALUES (%s, %s, %s, %s, %s);"
cur.execute(query, ('chris4', '곽객객', '9510132222222', 'KT', '01055555555'))
cur.execute("SELECT * FROM fms.chick_info")
results = cur.fetchall()
col_names = [desc[0] for desc in cur.description]
df = pd.DataFrame(results, columns=col_names)

# warning 발생
total_result = pd.read_sql_query("SELECT * FROM fms.total_result", conn)

import pandas as pd
query = "SELECT c.code_desc, b.raw_weight FROM fms.chick_info a, fms.prod_result b, fms.master_code c WHERE a.chick_no = b.chick_no and a.breeds = c.code"
try:
cur.execute(query)
except Exception as e:
conn.rollback()
print(f"Error: {e}")
results = cur.fetchall()
col_names = [desc[0] for desc in cur.description]
df = pd.DataFrame(results, columns=col_names)
plt.figure(figsize=(8,4))
sns.boxplot(
x='code_desc',
y='raw_weight',
data=df
)
plt.xlabel('품종')
plt.ylabel('무게')
plt.title('품종별 무게 분포')
plt.show()


from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()

pip install flask
flask run

DB_NAME='DB이름'
DB_USER='유저이름'
DB_HOST='localhost'
DB_PORT=5432
DB_PASSWORD=비밀번호
pip install python-dotenv
from dotenv import load_dotenv
import os
import psycopg2
from psycopg2.extras import DictCursor
from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
from dotenv import load_dotenv
from datetime import datetime
import json
# 로컬 환경에서는 .env를 읽고, Azure에서는 패스.
if os.path.exists('.env'):
load_dotenv()
app = Flask(__name__)
app.secret_key = os.urandom(24)
# 데이터베이스 연결 함수
def get_db_connection():
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD'),
sslmode='require' #Azure를 위해 반드시 추가
)
print('get_db_connection', conn)
conn.autocommit = True
return conn
@app.route('/')
def index():
# 1. 데이터 베이스에 접속
conn = get_db_connection()
print('get_db_connection', conn)
cursor = conn.cursor(cursor_factory=DictCursor)
# 2. SELECT
cursor.execute("SELECT id, title, author, created_at, view_count, like_count FROM board.posts ORDER BY created_at DESC")
posts = cursor.fetchall()
cursor.close()
conn.close()
# 3. index.html 파일에 변수로 넘겨주기
return render_template('index.html', posts = posts)
@app.route('/create/', methods=['GET'] )
def create_form():
return render_template('create.html')
@app.route('/create/',methods=['POST'] )
def create_post():
#1. 폼에 있는 정보들을 get
title = request.form.get('title')
author = request.form.get('author')
content = request.form.get('content')
if not title or not author or not content:
flash('모든 필드를 똑바로 채워주세요!!!!')
return redirect(url_for('create_form'))
# 1. 데이터 베이스에 접속
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=DictCursor)
# 2. INSERT
cursor.execute("INSERT INTO board.posts (title, content, author) VALUES (%s, %s, %s) RETURNING id", (title,author,content ))
post_id = cursor.fetchone()[0]
cursor.close()
conn.close()
flash('게시글이 성공적으로 등록되었음')
return redirect(url_for('view_post', post_id=post_id))
@app.route('/post/<int:post_id>')
def view_post(post_id):
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=DictCursor)
cursor.execute('UPDATE board.posts SET view_count = view_count + 1 WHERE id = %s', (post_id,))
cursor.execute('SELECT * FROM board.posts WHERE id = %s', (post_id,))
post = cursor.fetchone()
if post is None:
cursor.close()
conn.close()
flash('게시글을 찾을 수 없습니다.')
return redirect(url_for('index'))
cursor.execute('SELECT * FROM board.comments WHERE post_id = %s ORDER BY created_at', (post_id,))
comments = cursor.fetchall()
cursor.close()
conn.close()
user_ip = request.remote_addr
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM board.likes WHERE post_id = %s AND user_ip = %s', (post_id, user_ip))
liked = cursor.fetchone()[0] > 0
cursor.close()
conn.close()
return render_template('view.html', post=post, comments=comments, liked=liked)
@app.route('/edit/<int:post_id>', methods=['GET'])
def edit_form(post_id):
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=DictCursor)
cursor.execute('SELECT * FROM board.posts WHERE id = %s', (post_id,))
post = cursor.fetchone()
cursor.close()
conn.close()
if post is None:
flash('게시글을 찾을 수 없습니다.')
return redirect(url_for('index'))
return render_template('edit.html', post=post)
@app.route('/edit/<int:post_id>', methods=['POST'])
def edit_post(post_id):
title = request.form.get('title')
content = request.form.get('content')
if not title or not content:
flash('제목과 내용을 모두 입력해주세요.')
return redirect(url_for('edit_form', post_id=post_id))
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'UPDATE board.posts SET title = %s, content = %s, updated_at = %s WHERE id = %s',
(title, content, datetime.now(), post_id)
)
cursor.close()
conn.close()
flash('게시글이 성공적으로 수정되었습니다.')
return redirect(url_for('view_post', post_id=post_id))
@app.route('/delete/<int:post_id>', methods=['POST'])
def delete_post(post_id):
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('DELETE FROM board.posts WHERE id = %s', (post_id,))
cursor.close()
conn.close()
flash('게시글이 성공적으로 삭제되었습니다.')
return redirect(url_for('index'))
@app.route('/post/comment/<int:post_id>', methods=['POST'])
def add_comment(post_id):
author = request.form.get('author')
content = request.form.get('content')
if not author or not content:
flash('작성자와 내용을 모두 입력해주세요.')
return redirect(url_for('view_post', post_id=post_id))
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'INSERT INTO board.comments (post_id, author, content) VALUES (%s, %s, %s)',
(post_id, author, content)
)
cursor.close()
conn.close()
flash('댓글이 등록되었습니다.')
return redirect(url_for('view_post', post_id=post_id))
@app.route('/post/like/<int:post_id>', methods=['POST'])
def like_post(post_id):
user_ip = request.remote_addr
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM board.likes WHERE post_id = %s AND user_ip = %s', (post_id, user_ip))
already_liked = cursor.fetchone()[0] > 0
if already_liked:
cursor.execute('DELETE FROM board.likes WHERE post_id = %s AND user_ip = %s', (post_id, user_ip))
cursor.execute('UPDATE board.posts SET like_count = like_count - 1 WHERE id = %s', (post_id,))
message = '좋아요가 취소되었습니다.'
else:
cursor.execute('INSERT INTO board.likes (post_id, user_ip) VALUES (%s, %s)', (post_id, user_ip))
cursor.execute('UPDATE board.posts SET like_count = like_count + 1 WHERE id = %s', (post_id,))
message = '좋아요가 등록되었습니다.'
cursor.close()
conn.close()
flash(message)
return redirect(url_for('view_post', post_id=post_id))
if __name__ == '__main__':
app.run(debug=True)
-- board 스키마 생성
CREATE SCHEMA IF NOT EXISTS board;
-- 게시글 테이블
CREATE TABLE IF NOT EXISTS board.posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
view_count INTEGER DEFAULT 0,
like_count INTEGER DEFAULT 0
);
-- 댓글 테이블
CREATE TABLE IF NOT EXISTS board.comments (
id SERIAL PRIMARY KEY,
post_id INTEGER REFERENCES board.posts(id) ON DELETE CASCADE,
author VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 좋아요 테이블 (중복 좋아요 방지)
CREATE TABLE IF NOT EXISTS board.likes (
id SERIAL PRIMARY KEY,
post_id INTEGER REFERENCES board.posts(id) ON DELETE CASCADE,
user_ip VARCHAR(45) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(post_id, user_ip)
);

참고로, SSL 연결은 Azure 연결을 위해서는 required로 해야하지만, local에서는 disabled되어있어야 연결 오류가 나지 않는다.
→required 한 경우 SSL 에러


set FLASK_DEBUG=true

@app.route('/fms/result')
def fms_result():
"""total_result 뷰 데이터를 fms_result.html에 전달"""
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=DictCursor)
cursor.execute("SELECT * FROM fms.total_result ORDER BY 도착일 DESC NULLS LAST")
results = cursor.fetchall()
cursor.close()
conn.close()
return render_template('fms_result.html', results=results)
https://portal.azure.com/#home






















DB_NAME='postgres'
DB_USER='azureuser'
DB_HOST='3dt016-boarddb.postgres.database.azure.com'
DB_PORT=5432
DB_PASSWORD='비번'

https://github.com/RudinP/MicrosoftDataSchool-myboardPractice