from flask import Flask,redirect,render_template,request,url_for
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField,SelectField,SearchField,TextAreaField,DateTimeField,FloatField,IntegerField,URLField
from wtforms.validators import DataRequired,URL,NumberRange
from flask_bootstrap import Bootstrap5
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import desc
from datetime import datetime
#建立資料庫與綁定flask
app = Flask(__name__)
Bootstrap5(app)
#建立bootstrap5
#建立密鑰,防止CSRF
app.secret_key="jdklasjdosaudioasudoaskk;k;jdsauiudwq"
#建立一個SQLAlchemy實例
db =SQLAlchemy()
#配置給Flask,如果不存在就會建立這個db
app.config['SQLALCHEMY_DATABASE_URI']="sqlite:///movie.db"
#將db綁定給Flask使用
db.init_app(app)
#init_app方法主要作用是將擴展配置綁定到Flask應用程式
#建立模式
class Movie(db.Model):
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
name = db.Column(db.String(256),unique=True,nullable=False)
msg = db.Column(db.String(256),nullable=False)
ranking = db.Column(db.Integer,unique=True,nullable=False)
rating = db.Column(db.String(256),nullable=False)
img_url = db.Column(db.String(256),nullable=False)
# created_at = db.Column(db.DateTime, default=datetime.utcnow,nullable=False)
created_at = db.Column(db.DateTime,nullable=False)
#這邊得default 接受可呼叫的對象, 而不是實際的函數調用
#建立上面定義的模型建立資料表
with app.app_context():
db.create_all()
class MyForm(FlaskForm):
name = StringField("電影名稱",validators=[DataRequired()])
msg = TextAreaField("劇情大綱:",validators=[DataRequired()])
ranking = SelectField("排名",choices=[str(i) for i in range(1,11)],validators=[DataRequired()])
rating = SelectField("評分",choices=['⭐','⭐⭐','⭐⭐⭐','⭐⭐⭐⭐','⭐⭐⭐⭐⭐'],validators=[DataRequired()])
date = DateTimeField("上映日期 (YYYY-MM-DD)",format='%Y-%m-%d',validators=[DataRequired()])
img_url = URLField('電影圖片網址',validators=[DataRequired(),URL()])
sumbit = SubmitField("新增電影")
#每次選擇排名後就排除選項
def __init__(self,*args,**kwargs):
#這邊因為重新定義子類別__init__,但我需要父類別邏輯,所以使用super()
'''
在上述代碼中,super(MyForm, self).__init__(*args, **kwargs) 調用了 FlaskForm 類的 __init__ 方法,並傳遞了 *args 和 **kwargs。
這麼做確保了 FlaskForm 中的初始化邏輯得以執行,同時允許 MyForm 在其自己的 __init__ 方法中添加額外的初始化邏輯。
'''
super(MyForm, self).__init__(*args, **kwargs)
used_rankings=[str(movie.ranking) for movie in Movie.query.all()]
print(f'used={used_rankings}')
available_ranking = [str(i) for i in range(1,11) if str(i) not in used_rankings]
print(f'我可以用={available_ranking}')
# Update the 'ranking' field choices
self.ranking.choices = available_ranking
@app.route('/')
def home():
#讀取db
with app.app_context():
db_rows = Movie.query.order_by(desc(Movie.ranking)).all()
return render_template('index.html',rows=db_rows)
@app.route('/add',methods=['POST','GET'])
def add():
form=MyForm()
print(f'ranking={form.ranking.choices}')
if form.validate_on_submit():
new_movie = Movie(
name=form.name.data,
msg=form.msg.data,
ranking=form.ranking.data,
rating=form.rating.data,
created_at=form.date.data,
img_url=form.img_url.data)
db.session.add(new_movie)
db.session.commit()
return redirect(url_for('home'))
return render_template('add_movie.html',form=form)
@app.route('/edit',methods=['GET','POST'])
def edit():
id = request.args.get('id')
with app.app_context():
result=db.session.execute(db.select(Movie).where(Movie.id==id)).scalar()
print(f'result= {result.name}')
if request.method=='POST':
action = request.form.get('action')
print(f"action={action}")
if action == 'del_movie':
moive_del=db.get_or_404(Movie,id)
db.session.delete(moive_del)
db.session.commit()
return redirect(url_for('home'))
print('表單提交')
new_rating =request.form.get('new_rating')
if not new_rating.strip() :
print("沒有輸入表單,使用預設值⭐")
new_rating='⭐'
movie_update=db.get_or_404(Movie,id)
movie_update.rating = new_rating
db.session.commit()
request.form.get('action')
return render_template('edit.html',row=result)
if __name__ =='__main__':
app.run(debug=True,port=5050)