Day 064


Udemy Python Bootcamp Day 064


My Top 10 Movies Website


View Movie List Items

from flask import Flask, render_template, redirect, url_for, request
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
import requests

app = Flask(__name__)
app.config['SECRET_KEY'] = '8BYkEfBA6O6donzWlSihBXox7C0sKR6b'
Bootstrap(app)

app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///movie.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


class Movie(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(250), unique=True, nullable=False)
    year = db.Column(db.Integer, nullable=False)
    description = db.Column(db.String(500), nullable=False)
    rating = db.Column(db.Float, nullable=True)
    ranking = db.Column(db.Integer, nullable=True)
    review = db.Column(db.String(250), nullable=True)
    img_url = db.Column(db.String(250), nullable=False)
db.create_all()


@app.route("/")
def home():
    # new_movie = Movie(
    #     title="Phone Booth",
    #     year=2002,
    #     description="Publicist Stuart Shepard finds himself trapped in a phone booth, pinned down by an extortionist's sniper rifle. Unable to leave or receive outside help, Stuart's negotiation with the caller leads to a jaw-dropping climax.",
    #     rating=7.3,
    #     ranking=10,
    #     review="My favourite character was the caller.",
    #     img_url="https://image.tmdb.org/t/p/w500/tjrX2oWRCM3Tvarz38zlZM7Uc10.jpg"
    # )
    # db.session.add(new_movie)
    # db.session.commit()
    all_movies = Movie.query.all()
    return render_template("index.html", movies=all_movies)


if __name__ == '__main__':
    app.run(debug=True)
{% for movie in movies %}
<div class="card" >
  <div class="front" style="background-image: url('{{movie.img_url}}');">
    <p class="large">{{movie.ranking}}</p>
  </div>
  <div class="back">
    <div>
      <div class="title">{{movie.title}} <span class="release_date">({{movie.year}})</span></div>
      <div class="rating">
        <label>{{movie.rating}}</label>
        <i class="fas fa-star star"></i>
      </div>
      <p class="review">"{{movie.review}}"</p>
      <p class="overview">{{movie.description}}</p>

      <a href="#" class="button">Update</a>
      <a href="#" class="button delete-button">Delete</a>

    </div>
  </div>
</div>
{% endfor %}
{% for movie in movies %}が漏れて、少し迷っています.

Edit a Movie's Rating and Review

index.html
<a href="{{url_for('edit', id=movie.id)}}" class="button">Update</a>
edit.html
{{ wtf.quick_form(form, novalidate=True) }}
class EditForm(FlaskForm):
    rating = StringField('Your Rating Out of 10 e.g. 7.5')
    review = StringField('Your review')
    submit = SubmitField('Done')

@app.route('/edit', methods=["GET", "POST"])
def edit():
    form = EditForm()
    movie_id = request.args.get('id')
    movie = Movie.query.get(movie_id)
    if form.validate_on_submit():
        movie.rating = float(form.rating.data)
        movie.review = form.review.data
        db.session.commit()
        return redirect(url_for('home'))
    return render_template('edit.html', form=form, movie=movie)
edit()を書くことが肝心です.

Delete Movies from the Database

<a href="{{url_for('delete', id=movie.id)}}" class="button delete-button">Delete</a>
@app.route('/delete')
def delete():
    movie_id = request.args.get('id')
    movie_delete = Movie.query.get(movie_id)
    db.session.delete(movie_delete)
    db.session.commit()
    return redirect(url_for('home'))

Add New Movies Via the Add Page

class MovieForm(FlaskForm):
    title = StringField("Movie Title", validators=[DataRequired()])
    submit = SubmitField("Add Movie")


@app.route('/add', methods=["GET", "POST"])
def add():
    form = MovieForm()
    if form.validate_on_submit():
        params = {
            "api_key": API_KEY,
            "query": form.title.data,
        }
        response = requests.get(TMDB_endpoint, params=params)
        data = response.json()["results"]
        return render_template('select.html', movies=data)
    return render_template('add.html', form=form)
    

@app.route('/find')
def find():
    movie_api_id = request.args.get('id')
    if movie_api_id:
        movie_api_url = f"{MOVIE_DB_INFO_URL}/{movie_api_id}"
        response = requests.get(movie_api_url, params={"api_key": API_KEY})
        data = response.json()
        new_movie = Movie(
            title=data["title"],
            year=data["release_date"].split('-')[0],
            description=data["overview"],
            img_url=f"{MOVIE_DB_IMAGE_URL}{data['poster_path']}"
        )
        db.session.add(new_movie)
        db.session.commit()
        return redirect(url_for('edit', id=new_movie.id))
select.html
{% for movie in movies %}
<p>
  <a href="{{url_for('find', id=movie.id)}}"> {{movie.title}} - {{movie.release_date}}</a>
</p>
{% endfor %}
TMDBページから値を呼び出し、リストする


いずれかのリストを選択すると、editにリダイレクトされ、値の入力時にホームページに追加されます.
(コードを初めて作成して適切なリストを呼び出すと、感動して、,)
+)dbが最初に作成されると、nullable=Falseとして作成され、nullable=Trueに変更されます.
変更後、最初に作成すると、nullable=Falseに置き換えられ、既存のdbファイルが削除され、再生成されます.find()を記述する場合、url_forからid=new_movie.id値を取得するには、edit()パラメータにidを追加する必要があります.

Sort and Rank the Movies By Rating

@app.route("/")
def home():
    all_movies = Movie.query.order_by(Movie.rating).all()
    for i in range(len(all_movies)):
        all_movies[i].ranking = len(all_movies) - i
    db.session.commit()
    return render_template("index.html", movies=all_movies)

とても同感なのは...
hintがorder_byメソッドを使うのは知っていましたが、all()の前に置くとは思わなかった・・・
加えてランキングをrakingと書くフォントの間違い、、、

FINAL


https://gist.github.com/awesomekimn/d454ce28c10bf7b3c6fb6a14384e65ad