first commit

This commit is contained in:
attojeon 2023-11-14 20:50:38 +09:00
commit 5caf16bb9c
11 changed files with 554 additions and 0 deletions

132
.gitignore vendored Normal file
View File

@ -0,0 +1,132 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
dist/
eggs/
*.egg-info/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.coverage
.tox/
.nox/
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# CFFI
.cffi_cache/
# pycache
__pycache__/

27
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,27 @@
{
// IntelliSense .
// .
// https://go.microsoft.com/fwlink/?linkid=830387() .
"version": "0.2.0",
"configurations": [
{
"name": "Python: 현재 파일",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "Python: Streamlit",
"type": "python",
"request": "launch",
"module": "streamlit",
"justMyCode": true,
"args": ["run", "${file}"],
"env": {
"STATION_BUS_API_KEY1": "jEN2Laz4w1"
}
}
]
}

160
main.py Normal file
View File

@ -0,0 +1,160 @@
############################
# 데이터베이스 사용 이해하기
############################
# from tinydb import TinyDB, Query
import pandas as pd
from datetime import datetime
from pprint import pprint
from userdblib import fetch_user_by_email, fetch_user_by_id, fetch_users, insert_user, update_user, delete_user, create_table, get_new_id
# # 데이터베이스 생성 및 연결
# db = TinyDB('db.json')
# ###########################################
# # 데이터베이스 쿼리 함수들 #
# ###########################################
# # 데이터가 없으면 샘플 데이터 추가
# def create_table():
# if len(db.all()) == 0:
# users = [
# {'id': 1, 'name': '전 John', 'email': 'john@gmail.com', 'age': 20, 'created_at': '2021-01-01 00:00:00'},
# {'id': 2, 'name': '오 Jane', 'email': 'jane@gmail.com', 'age': 25, 'created_at': '2021-01-02 00:00:00'},
# {'id': 3, 'name': '방 Bob', 'email': 'bob@gmail.com', 'age': 30, 'created_at': '2021-01-03 00:00:00'},
# {'id': 4, 'name': '윤 Alice', 'email': 'alice@gmail.com', 'age': 35, 'created_at': '2021-01-04 00:00:00'},
# {'id': 5, 'name': '김 Bill', 'email': 'bill@gmail.com', 'age': 40, 'created_at': '2021-01-05 00:00:00'},
# ]
# db.insert_multiple(users)
# def get_new_id():
# users = fetch_users()
# new_id = users[-1]['id'] + 1
# return new_id
# def fetch_users():
# return db.all()
# def fetch_user_by_id(id):
# users = db.search(Query().id == id)
# if len(users) == 0:
# return []
# else:
# return users.pop()
# def fetch_user_by_email(email):
# users = db.search(Query().email == email)
# if len(users) == 0:
# return []
# else:
# return users.pop()
# def insert_user(user):
# # new_user = user_from_input()
# db.insert(user)
# def update_user(user):
# db.update(user, Query().id == user['id'])
# def delete_user(id):
# db.remove(Query().id == id)
###########################################
# 화면 기능 함수들 #
###########################################
def user_from_input():
print("#"*30 + " 사용자 정보 입력 " + "#"*30)
name = input("이름: ")
email = input("이메일: ")
age = int(input("나이: "))
created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
user = {'id': get_new_id(), 'name': name, 'email': email, 'age': age, 'created_at': created_at}
return user
def user_from_input_update(user):
print("#"*30 + " 사용자 정보 업데이트 " + "#"*30)
name = input(f"이름({user['name']}): ")
email = input(f"이메일({user['email']}): ")
age = int(input(f"나이({user['age']}): "))
# created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
user = {'id': user["id"], 'name': name, 'email': email, 'age': age, 'created_at': user["created_at"]}
return user
# Function to display all users
def display_users():
users = fetch_users()
for user in users:
print(f"ID:{user['id']}\n이름:{user['name']}\n전자메일:{user['email']}\n나이:{user['age']}\n가입날짜:{user['created_at']}\n")
def add_new_user():
user = user_from_input()
insert_user(user)
print("새 사용자가 추가되었습니다.")
def update_existing_user():
print("#"*30 + " 사용자 정보 수정 " + "#"*30)
id = int(input("수정할 사용자의 ID를 입력하세요: "))
user = fetch_user_by_id(id)
if len(user) == 0:
print("해당 ID의 사용자가 없습니다.")
else:
user = user_from_input_update(user)
user['id'] = id
update_user(user)
print("사용자 정보가 수정되었습니다.")
def delete_existing_user():
print("#"*30 + " 사용자 정보 삭제 " + "#"*30)
id = int(input("삭제할 사용자의 ID를 입력하세요: "))
user = fetch_user_by_id(id)
if len(user) == 0:
print("해당 ID의 사용자가 없습니다.")
else:
delete_user(id)
print("사용자 정보가 삭제되었습니다.")
def search_user_by_email():
print("#"*30 + " 사용자 정보 검색 " + "#"*30)
email = input("검색할 사용자의 이메일을 입력하세요: ")
user = fetch_user_by_email(email)
if len(user) == 0:
print("해당 이메일의 사용자가 없습니다.")
else:
print(f"ID:{user['id']}\n이름:{user['name']}\n전자메일:{user['email']}\n나이:{user['age']}\n가입날짜:{user['created_at']}\n")
###########################################
# main 함수
create_table()
while True:
print("#"*30 + " 사용자 관리 프로그램 " + "#"*30)
print("1. 사용자 전체 조회")
print("2. 사용자 추가")
print("3. 사용자 수정")
print("4. 사용자 삭제")
print("5. 이메일로 사용자 검색")
print("6. 종료")
print("#"*80)
menu = int(input("메뉴를 선택하세요: "))
if menu == 1:
display_users()
elif menu == 2:
add_new_user()
elif menu == 3:
update_existing_user()
elif menu == 4:
delete_existing_user()
elif menu == 5:
search_user_by_email()
elif menu == 6:
print("프로그램을 종료합니다.")
break
else:
print("잘못된 메뉴입니다. 다시 선택하세요.")

39
readme.md Normal file
View File

@ -0,0 +1,39 @@
[]: # BEGIN: 1c3f3c8f7c7d
# 데이터베이스와 스트림잇 웹앱!
* 스트림잇 기반의 웹앱 프로젝트를 수행하면서
## main.py 미리보기
* 터미널환경으로 구현한 '사용자관리'하기
<video width="100%" controls>
<source src="streamlit_tinydb1_1.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
## webapp.py
* 웹앱으로 구현한 '사용자관리' 프로그램
<video width="100%" controls>
<source src="streamlit_tinydb1_2.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
## userdblib.py
* tinydb를 직접 액세스하는 라이브러리 모듈
* 기본적인 CRUD 기능 구현
* fetch
* update
* delete
* create
## userdb.json
* 사용자DB 파일
* tinydb 형식으로 저장된 json데이터베이스
* utf-8 인코딩 자체적으로 사용함.
* 직접 파일을 수정하는 것은 권하지 않음.
* 참조 https://github.com/msiemens/tinydb.git
## 설치
```bash
pip install streamlit --upgrade
```

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
streamlit
tinydb

BIN
streamlit_tinydb1_1.mp4 Normal file

Binary file not shown.

BIN
streamlit_tinydb1_2.mp4 Normal file

Binary file not shown.

1
userdb.json Normal file
View File

@ -0,0 +1 @@
{"_default": {"1": {"id": 1, "name": "\uc804\uc0c1\ud6042", "email": "john@gmail.com", "age": 22, "created_at": "2021-01-01 00:00:00"}, "2": {"id": 2, "name": "\uc624 Jane", "email": "jane@gmail.com", "age": 25, "created_at": "2021-01-02 00:00:00"}, "3": {"id": 3, "name": "\ubc29 Bob", "email": "bob@gmail.com", "age": 30, "created_at": "2021-01-03 00:00:00"}, "4": {"id": 4, "name": "\uc724 Alice", "email": "alice@gmail.com", "age": 35, "created_at": "2021-01-04 00:00:00"}, "15": {"id": 15, "name": "\uc804\uc0c1\ud604", "email": "john@gmail.com", "age": 20, "created_at": "2023-11-09 17:47:20"}, "16": {"id": 16, "name": "\uc724\uc2e0\uc6d0", "email": "yoon@gmail.com", "age": 40, "created_at": "2023-11-09 18:58:49"}, "17": {"id": 17, "name": "\ud64d\uae38\ub3d9", "email": "hong@korea.com", "age": 29, "created_at": "2023-11-09 18:59:09"}, "18": {"id": 18, "name": "\uc720\uad00\uc21c", "email": "gw.ryu@korea.net", "age": 24, "created_at": "2023-11-09 18:59:38"}, "19": {"id": 19, "name": "\uae40\uad6c", "email": "goo.kim@korea.com", "age": 50, "created_at": "2023-11-09 20:18:45"}, "21": {"id": 21, "name": "\uc138\uc885\ub300\uc655", "email": "kingofchosun@korea.com", "age": 30, "created_at": "2023-11-10 10:45:54"}, "22": {"id": 22, "name": "\uac15\uac10\ucc2c", "email": "kang.gc@korea.com", "age": 50, "created_at": "2023-11-10 10:58:53"}}}

54
userdblib.py Normal file
View File

@ -0,0 +1,54 @@
from tinydb import TinyDB, Query
from datetime import datetime
from pprint import pprint
# 데이터베이스 생성 및 연결
db = TinyDB('userdb.json')
###########################################
# 데이터베이스 쿼리 함수들 #
###########################################
# 데이터가 없으면 샘플 데이터 추가
def create_table():
if len(db.all()) == 0:
users = [
{'id': 1, 'name': '전 John', 'email': 'john@gmail.com', 'age': 20, 'created_at': '2021-01-01 00:00:00'},
{'id': 2, 'name': '오 Jane', 'email': 'jane@gmail.com', 'age': 25, 'created_at': '2021-01-02 00:00:00'},
{'id': 3, 'name': '방 Bob', 'email': 'bob@gmail.com', 'age': 30, 'created_at': '2021-01-03 00:00:00'},
{'id': 4, 'name': '윤 Alice', 'email': 'alice@gmail.com', 'age': 35, 'created_at': '2021-01-04 00:00:00'},
{'id': 5, 'name': '김 Bill', 'email': 'bill@gmail.com', 'age': 40, 'created_at': '2021-01-05 00:00:00'},
]
db.insert_multiple(users)
def get_new_id():
users = fetch_users()
new_id = users[-1]['id'] + 1
return new_id
def fetch_users():
return db.all()
def fetch_user_by_id(id):
users = db.search(Query().id == id)
if len(users) == 0:
return []
else:
return users.pop()
def fetch_user_by_email(email):
users = db.search(Query().email == email)
if len(users) == 0:
return []
else:
return users.pop()
def insert_user(user):
# new_user = user_from_input()
db.insert(user)
def update_user(user):
db.update(user, Query().id == user['id'])
def delete_user(id):
db.remove(Query().id == id)

138
webapp.py Normal file
View File

@ -0,0 +1,138 @@
import pandas as pd
from datetime import datetime
from pprint import pprint
import streamlit as st
from userdblib import fetch_user_by_email, fetch_user_by_id, fetch_users, insert_user, update_user, delete_user, create_table, get_new_id
import extra_streamlit_components as stx
###########################################
# 화면 함수들 #
###########################################
def init_router():
return stx.Router({"/": home, "/home": home, "/add": add_new_user, "/update": update_userinfo, "/delete": delete_userinfo, "/search": search_userinfo})
def selection_changed(df):
st.write(df)
def show_header():
st.title("사용자 관리 시스템")
def home():
show_header()
col1, col2, col3, col4 = st.columns(4)
if col3.button("사용자 추가", use_container_width=True):
router.route("/add")
if col4.button("사용자 검색", use_container_width=True):
router.route("/search")
users = fetch_users()
df = pd.DataFrame(users, columns=['id', 'name', 'email', 'age', 'created_at'])
st.dataframe(df, use_container_width=True, hide_index=True)
# df에서 df["id"] + df["name"] => df["id_name"] 컬럼을 추가
df["id_name"] = df["id"].astype(str) + ":" + df["name"]
selected = st.selectbox("사용자 선택", df["id_name"])
# st.write("선택된 id_name:", selected)
st.session_state["selected"] = selected
col1, col2 = st.columns(2)
if col1.button("사용자 수정", use_container_width=True):
router.route("/update")
if col2.button("사용자 삭제",use_container_width=True):
router.route("/delete")
def add_new_user():
show_header()
st.subheader("사용자 정보 입력")
with st.form(key='user_form'):
name = st.text_input(label="이름")
email = st.text_input(label="이메일")
age = st.number_input(label="나이", min_value=0, max_value=150)
submitted = st.form_submit_button(label='저장하기', use_container_width=True)
if submitted:
created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
user = {'id': get_new_id(), 'name': name, 'email': email, 'age': age, 'created_at': created_at}
insert_user(user)
st.success("저장되었습니다.")
if st.button("사용자 목록", use_container_width=True):
router.route("/home")
def update_userinfo():
show_header()
st.subheader("사용자 정보 수정")
selected = st.session_state["selected"] # "1:전상현"
user = fetch_user_by_id(int(selected.split(":")[0]))
with st.form(key='user_form'):
id = st.text_input(label="ID", value=user["id"], disabled=True)
name = st.text_input(label="이름", value=user["name"])
email = st.text_input(label="이메일", value=user["email"])
age = st.number_input(label="나이", min_value=0, max_value=150, value=user["age"])
created_at = user["created_at"]
submitted = st.form_submit_button(label='저장하기', use_container_width=True)
if submitted:
user = {'id': int(id), 'name': name, 'email': email, 'age': age, 'created_at': created_at}
update_user(user)
st.success("저장되었습니다.")
if st.button("사용자 목록", use_container_width=True):
router.route("/home")
def delete_userinfo():
show_header()
st.subheader("사용자 정보 삭제")
selected = st.session_state["selected"] # "1:전상현"
user = fetch_user_by_id(int(selected.split(":")[0]))
with st.form(key='user_form'):
id = st.text_input(label="ID", value=user["id"], disabled=True)
name = st.text_input(label="이름", value=user["name"])
email = st.text_input(label="이메일", value=user["email"])
age = st.number_input(label="나이", min_value=0, max_value=150, value=user["age"])
created_at = user["created_at"]
submitted = st.form_submit_button(label='삭제하기', use_container_width=True)
if submitted:
delete_user(int(id))
st.success("삭제되었습니다.")
router.route("/home")
if st.button("사용자 목록", use_container_width=True):
router.route("/home")
def search_userinfo():
show_header()
st.subheader("사용자 정보 검색")
# users = fetch_users()
# df = pd.DataFrame(users, columns=['id', 'name', 'email', 'age', 'created_at'])
with st.form(key='user_form'):
search_type = st.selectbox(label="검색 유형", options=["이름", "전자메일"])
search = st.text_input(label="검색어")
submitted = st.form_submit_button(label='검색하기', use_container_width=True)
if submitted:
users = fetch_users()
df = pd.DataFrame(users, columns=['id', 'name', 'email', 'age', 'created_at'])
if search_type == "이름":
df = df[df["name"].str.contains(search, case=False)]
st.dataframe(df, use_container_width=True, hide_index=True)
elif search_type == "전자메일":
df = df[df["email"].str.contains(search, case=False)]
st.dataframe(df, use_container_width=True, hide_index=True)
# df에서 df["id"] + df["name"] => df["id_name"] 컬럼을 추가
df["id_name"] = df["id"].astype(str) + ":" + df["name"]
selected = st.selectbox("사용자 선택", df["id_name"])
# st.write("선택된 id_name:", selected)
st.session_state["selected"] = selected
col1, col2 = st.columns(2)
if col1.button("사용자 수정", use_container_width=True):
router.route("/update")
if col2.button("사용자 삭제",use_container_width=True):
router.route("/delete")
if st.button("사용자 목록", use_container_width=True):
router.route("/home")
# main 함수
create_table()
if "selected" not in st.session_state:
st.session_state["selected"] = None
router = init_router()
router.show_route_view()

1
youtubedb.json Normal file
View File

@ -0,0 +1 @@
{"_default": {"1": {"category": "\uc0c8\uc18c\uc2dd", "title": "8\uc6d4 1\uc77c \ubd80\ud130..\uc6b0\uc774\uc2e0\uc124\uc120 \ud0c8 \ub54c \uad50\ud1b5\uce74\ub4dc \uc548 \ucc0d\uc5b4\ub3c4 \uc790\ub3d9\uacb0\uc81c", "date": "2023-07-01", "url": "https://youtu.be/Qvhukbs2pmc"}, "2": {"category": "\ud56b\ud074\ub9bd", "title": "\uc6b0\uc8fc \uccb4\ub958 \uae30\uac04\uc774 \uae38\uc5b4\uc9c0\uba70 \uc2dc\uc791\ub41c \ub204\uc6cc \uc9c0\ub0b4\uae30 \uc2e4\ud5d8", "date": "2023-07-10", "url": "https://youtu.be/URhpRjJgWlc"}, "3": {"category": "\uc778\ud130\ubdf0", "title": "\uce74\uc774\uc2a4\ud2b8\uc640 \uacf5\ub3d9\uac1c\ubc1c\ud55c '\ub2e4\ud06c \uc6f9' \uc804\uc6a9 AI '\ub2e4\ud06c\ubc84\ud2b8'", "date": "2023-06-01", "url": "https://youtu.be/6LMKuWYQCYs"}, "4": {"category": "\uc0ac\uc774\uc5b8\uc2a4", "title": "\uc6b0\uc8fc\uccad, \uc0ac\uc2e4\uc0c1 \uc5f0\ub0b4 \uac1c\uccad \ubd88\uac00..\ud56d\uc6b0\uc5f0 \ub0b4\ubd80\uc5d0\uc11c\ub3c4 \uc124\ub9bd \uc758\uacac \uc5c7\uac08\ub824", "date": "2023-05-01", "url": "https://youtu.be/7mIHv7bayMw"}}}