ChatGPT 웹개발 진행노트 - 7일차

2024. 2. 5. 22:25카테고리 없음

강의 자료 

4주차 강의 자료

4주차

02. [데일리모토] - 프로젝트 세팅

프로젝트 설정

신규 projects 디텍토리 생성 및 기존에 작성한 motto, music.html을 templates 디텍토리도 복사한다.

python venv 설정

터미널에서 다음 명령어로 venv 생성 후 인터프리터에서 필요한 python 버전 선택

python -m venv venv

 

프로젝트에서 다음 명령어로 venv 활성화

source venv/bin/activate

터미널에 (venv)가 출력된다.

 

이후 flask 패키지를 설치한다.

pip install flask

 

04. [데일리모토] - 라우팅 연습

주소에 따른 HTML 파일 렌더링

주소에 따라 html파일이 보여지도록 설정한다. app.py를 다음과 같이 편집한다.

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def home():
    return render_template("motto.html")

@app.route("/music/")
def music():
    return render_template("music.html")

if __name__ == "__main__":
    app.run(debug=True, port=8080)

localhost:8080에서는 다음과 같이 출력되며,

localhost:8080/music 에서는 다음과 같이 출력된다.

 

Python 서버에서 HTML 파일로 데이터 넘겨주기

python 변수에 따라 인사말이 바뀌도록 수정한다. 

app.py을 다음과 같이 수정한다.

def home():
    name = 'sparta'
    return render_template("motto.html", data=name)

motto.html을 다음과 같이 수정한다.

<div class="container">
    <div class="greeting">
        <h1>Hello, {{ data.name }}</h1>
        <h1 id="current-time"></h1>
    </div>

    <div class="motto">
        <h3>My life's motto</h3>
        <h2>{{data.motto}}</h2>
    </div>
</div>

 

다음과 같이 이름과 모토가 출력된다.

05. [데일리모토] - URL 주소에서 데이터 가져오기

주소에 따라 메인 화면 인사말 바꾸기

코드를 다음과 같이 작성한다.

@app.route("/iloveyou/<name>/")
def iloveyou(name):
    motto = f"{name}야 난 너뿐이야..."
    context = {
        "name": name,
        "motto": motto
    }

    return render_template("motto.html", data=context)

route에 <>를 사용하면 URL 주소에 따라 <> 안에 내용을 변수처럼 쓸 수 있다. http://localhost:8080/iloveyou/silee 로 url을 접속하면 name에 silee가 출력된다.

 

06. [데일리모토] - 페이지 이동 기능 만들기

데일리모토 Navbar에 페이지 이동 기능을 구현한다.

Navbar에 메뉴 추가

Bootstrap CSS CDN 추가

head태그 하위에 링크를 추가

<head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
...
</head>

Bootstrap JavaScript CDN 추가

</body> 태그 위에 CDN을 추가한다.

<body>
	...
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
        crossorigin="anonymous"></script>
</body>

 

nav 태그 수정

다음과 같이 nav 태그를 수정한다.

<nav class="navbar border-bottom border-bottom-dark d-flex justify-content-space-between" data-bs-theme="dark">
    <div class="ms-3">
        <img src="https://s3.ap-northeast-2.amazonaws.com/materials.spartacodingclub.kr/webjong/images/sparta-logo.svg"
            alt="" />
    </div>
    <nav class="navbar navbar-expand-lg">
        <div class="container-fluid">
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
                aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Music</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Album</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Movie</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="weather">
        <img src="https://ssl.gstatic.com/onebox/weather/64/partly_cloudy.png" id="weather-icon">
        <p id="weatherTemp">날씨 맑음, 20ºC</p>
    </div>
</nav>

navbar에 페이지 이동 기능 구현하기

{{url_from('이동할 곳')}} 형식으로 수정한다. motto.html, music.html를 각각 다음과 같이 수정한다.

<div class="collapse navbar-collapse" id="navbarNav">
  <ul class="navbar-nav">
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="{{ url_for('home') }}">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="{{ url_for('music') }}">Music</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="#">Album</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="#">Movie</a>
    </li>
  </ul>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
  <ul class="navbar-nav">
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="{{ url_for('home') }}">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="{{ url_for('music') }}">Music</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="#">Album</a>
    </li>
    <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="#">Movie</a>
    </li>
  </ul>
</div>

 

위의 navbar에서 Home, Music에서 페이지 이동이 정상 동작한다.

 

07. Database(DB) 개괄

SQLite Editor VScode Extension을 설치한다.

database.db를 추가하면 화면에 다음과 같이 출력된다.

08. SQLite 시작하기

SQLAlchemy로 Database 연결 & 테이블 만들기

다음 명령어로 SQLAlchemy로 패키지를 설치한다.

pip install Flask-SQLAlchemy

 

다음코드로 SQLAlchemy를 초기화한다.

from flask import Flask
import os
from flask_sqlalchemy import SQLAlchemy

basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')

db = SQLAlchemy(app)

 

이후 app.py에 Song 클래스를 추가 후 다음과 같이 구현한다.

class Song(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, nullable=False)
    artist = db.Column(db.String, nullable=False)
    title = db.Column(db.String, nullable=False)
    image_url = db.Column(db.String, nullable=False)

    def __repr__(self):
        return f'{self.artist} {self.title} 추천 by {self.username}'

 

table을 생성은 다음과 같이 진행한다.

>>> from app import Song, app, db
>>> with app.app_context():
...     db.create_all()

위와 같이 database.db에 song 테이블이 추가된다.

 

table을 drop하기위해서는 다음과 같이 진행한다.

>>> from app import Song, app, db
>>> with app.app_context():
...     db.drop_all()

위와 같이 database.db에 table이 제거된다.

09. SQLAlchemy로 Database 조작하기

여러 데이터 넣기

from app import Song, db, app

song1 = Song(username="추천자", title="노래제목1",
             artist="가수1", image_url="이미지 주소1")

song2 = Song(username="스파르타", title="노래제목2",
             artist="가수2", image_url="이미지 주소2")

song3 = Song(username="스파르타", title="노래제목3",
             artist="가수3", image_url="이미지 주소3")

with app.app_context():
    db.session.add(song1)
    db.session.add(song2)
    db.session.add(song3)

    db.session.commit()

database.db에 데이터가 추가된다.

 

모든 결과 값 조회

다음과 같이 함수를 호출할 경우 def __repr__(self) 함수에서 리턴하는 포맷으로 조회가 된다.

>>> from app import Song, app, db
>>> with app.app_context():
...     Song.query.all()
... 
[가수1 노래제목1 추천 by 추천자, 가수2 노래제목2 추천 by 스파르타, 가수3 노래제목3 추천 by 스파르타]

def __repr__(self):
    return f'{self.artist} {self.title} 추천 by {self.username}'

 

특정 조건으로 데이터 가져오기

Song.query.filter_by(조건).all()을 사용하면 조건에 맞는 데이터를 전부 가져올 수 있다.

>>> with app.app_context():
...     Song.query.filter_by(username='추천자').all()
... 
[가수1 노래제목1 추천 by 추천자]

 

>>> with app.app_context():
...     Song.query.filter_by(id=3).first()
... 
가수3 노래제목3 추천 by 스파르타

 

>>> with app.app_context():
...     Song.query.filter_by(title='노래제목1').first()
... 
가수1 노래제목1 추천 by 추천자

 

데이터 수정하기

다음과 같이 query를 통해 저장된 record를 가져온 후 db.session.add 함수 및 db.session.commit 함수를 호출하여 수정을 진행한다.

from app import Song, db, app

with app.app_context():
    print(Song.query.all())
    song_data = Song.query.filter_by(id=3).first()
    song_data.title = '노래제목수정'
    db.session.add(song_data)
    db.session.commit()
    print(Song.query.all())

다음과 같이 변경된 값으로 출력된다.

데이터 삭제하기

데이터 수정과 동일하게 해당 query로 저장된 record를 가져온 후 db.session.delete 함수 및 db.session.commit 함수를 호출하여 삭제를 진행한다.

from app import Song, db, app

with app.app_context():
    print(Song.query.all())
    delete_data = Song.query.filter_by(id=3).first()
    db.session.delete(delete_data)
    db.session.commit()
    print(Song.query.all())

다음과 같이 해당 값이 삭제된다.

10. Homework

멜론 Top 100차트에서 가수(artist), 노래 제목(title), 앨범 커버(image_url)을 스크래핑해서 카드 형태로 만든다.

http://127.0.0.1:5000/melon 에 접속하면 다음과 같이 출력된다.

 

신규 프로젝트 prac을 추가한후 app.py, templates/index.html을 생성한다.

 

이 후 venv 환경설정을 진행한 후 flask, bs4, requests 패키지를 다운 받는다.

prac % python -m venv venv
prac % source venv/bin/activate
(venv)prac % pip install flask bs4 requests

 

app.py에 다음과 같이 코드를 수정한다.

from flask import Flask, render_template
from bs4 import BeautifulSoup
import requests

app = Flask(__name__)

url = "https://www.melon.com/chart/"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get(url, headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/melon')
def melon():
    data_list = []
    trs = soup.select('.lst50') + soup.select('.lst100')
    for tr in trs:
        title = tr.select_one('.rank01 > span > a').text
        artist = tr.select_one('.rank02 > a').text
        image_url = tr.select_one('img')['src']
        data_list.append({'title' : title, 'artist' : artist, 'image_url' : image_url})

    context = data_list
    return render_template('index.html', data=context)

if __name__ == '__main__':
    app.run(debug=True, port=5000)

 

index.html의 Cards 부분을 다음과 같이 수정한다.

<div class="row row-cols-1 row-cols-md-4 g-4 mx-auto w-75 pb-5">
    {% for melon in data %}
    <div class="col">
        <div class="card h-100">
            <img src="{{melon.image_url}}"
                class="card-img-top" alt="...">
            <div class="card-body">
                <h5 class="card-title">{{melon.title}}</h5>
                <p class="card-text">{{melon.artist}}</p>
                <p class="card-text">추천 by 최지웅</p>
            </div>
        </div>
    </div>
    {% endfor %}
</div>

 

다음과 같이 화면에 앨범 이미지, 타이틀, 아티스트이 출력된다.