Flask电影投票系统全解析

电影投票案列
  • 项目结构说明:
复制代码
movie-voting-app/
├── app.py
├── models.py
├── templates/
│   ├── index.html
│   └── add_movie.html
└── static/
    └── style.css
1. 导入对应的依赖包,并配置数据库链接
python 复制代码
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
import os
from datetime import datetime
​
# 创建应用
app = Flask(__name__)
​
# 配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1/youdb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'pgijeaowir12734y#$^^lefmkng'
​
# 初始化数据库
db = SQLAlchemy(app)
migrate = Migrate(app, db)
​
if __name__ == '__main__':
    with app.app_context():
        app.run(debug=True)
2. 创建电影模型,并添加默认数据
python 复制代码
# 电影模型
class Movie(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    year = db.Column(db.Integer, nullable=False)
    votes = db.Column(db.Integer, default=0)
​
    def __repr__(self):
        return f'<Movie {self.title}>'
    
# 添加数据
if __name__ == '__main__':
    with app.app_context():
        db.create_all()
​
        # 添加初始数据(如果不存在)
        if Movie.query.count() == 0:
            movies = [
                Movie(title="盗梦空间", year=2010, votes=0),
                Movie(title="肖申克的救赎", year=1994, votes=0),
                Movie(title="泰坦尼克号", year=1997, votes=0),
                Movie(title="阿甘正传", year=1994, votes=0),
            ]
            db.session.add_all(movies)
            db.session.commit()
​
        app.run(debug=True)
复制代码
3. 添加电影页面路由,显示初始化数据
  • 准备路由,查询数据并在页面中显示
python 复制代码
@app.route('/index', methods=['GET'])
def index():
    # 获取所有电影
    movies = Movie.query.all()
    return render_template('index.html',
                          current_year=datetime.now().year,
                          movies=movies)
  • 展示首页数据
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>电影投票系统</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <header>
            <h1>🎬 电影投票系统</h1>
            <p class="subtitle">为您喜欢的电影投票</p>
        </header>
​
        {#        闪现消息#}
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <div class="messages">
                    {% for message in messages %}
                        <div class="message">{{ message }}</div>
                    {% endfor %}
                </div>
            {% endif %}
        {% endwith %}
​
        <div class="controls">
            <a href="{{ url_for('add_movie_page') }}" class="button">➕ 添加电影</a>
            <form action="{{ url_for('reset_votes') }}" method="post" class="inline-form">
                <button type="submit" class="button warning">🔄 重置票数</button>
            </form>
        </div>
​
        <div class="movie-list">
            {% if movies %}
                <table>
                    <thead>
                        <tr>
                            <th>电影名称</th>
                            <th>年份</th>
                            <th>票数</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for movie in movies %}
                        <tr>
                            <td class="movie-title">{{ movie.title }}</td>
                            <td class="movie-year">{{ movie.year }}</td>
                            <td class="movie-votes">{{ movie.votes }}</td>
                            <td class="movie-actions">
                                <form action="{{ url_for('vote_movie', movie_id=movie.id) }}" method="post">
                                    <button type="submit" class="small-button">👍 投票</button>
                                </form>
                                <form action="{{ url_for('delete_movie', movie_id=movie.id) }}" method="post" class="inline-form">
                                    <button type="submit" class="small-button danger" onclick="return confirm('确定删除这部电影吗?')">🗑️ 删除</button>
                                </form>
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            {% else %}
                <div class="no-movies">
                    <p>还没有电影,请添加一些!</p>
                    <a href="{{ url_for('add_movie_page') }}" class="button">添加第一部电影</a>
                </div>
            {% endif %}
        </div>
​
        <footer>
            <p>© {{ current_year }} 电影投票系统 | hui函数出品</p>
        </footer>
    </div>
</body>
</html>
4. 投票功能
  • 接收传递过来的id值,得到数据对象,给votes字段数据+1,并提交

  • 使用flash闪现消息,发送操作提示

  • 重定向到首页

python 复制代码
@app.route('/vote/<int:movie_id>', methods=['POST'])
def vote_movie(movie_id):
    movie = Movie.query.get(movie_id)
    if movie:
        movie.votes += 1
        db.session.commit()
        flash(f'已为 {movie.title} 投票成功!')
    return redirect(url_for('index'))
5. 删除功能
  • 获取传递过来的id,执行删除操作

  • 使用flash闪现消息,发送操作提示

  • 重定向到首页

python 复制代码
@app.route('/delete/<int:movie_id>', methods=['POST'])
def delete_movie(movie_id):
    movie = Movie.query.get(movie_id)
    if movie:
        db.session.delete(movie)
        db.session.commit()
        flash(f'已删除电影: {movie.title}')
    return redirect(url_for('index'))
6. 重置票数
  • 使用update方法直接修改票数votes为0
python 复制代码
@app.route('/reset', methods=['POST'])
def reset_votes():
    Movie.query.update({Movie.votes: 0})
    db.session.commit()
    flash('所有票数已重置!')
    return redirect(url_for('index'))
7. 添加数据
  • 准备一个显示添加页面的路由
python 复制代码
@app.route('/add', methods=['GET'])
def add_movie_page():
    return render_template('add_movie.html', current_year=datetime.now().year)
  • 显示页面
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>添加电影</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <header>
            <h1>➕ 添加新电影</h1>
            <a href="{{ url_for('index') }}" class="button back">← 返回首页</a>
        </header>
​
        {#    闪现消息#}
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <div class="messages">
                    {% for message in messages %}
                        <div class="message">{{ message }}</div>
                    {% endfor %}
                </div>
            {% endif %}
        {% endwith %}
​
        <div class="form-container">
            <form action="{{ url_for('add_movie') }}" method="post">
                <div class="form-group">
                    <label for="title">电影名称</label>
                    <input type="text" id="title" name="title" required>
                </div>
​
                <div class="form-group">
                    <label for="year">发行年份</label>
                    <input type="number" id="year" name="year"
                           min="1900" max="{{ current_year }}"
                           value="{{ current_year }}" required>
                </div>
​
                <div class="form-actions">
                    <button type="submit" class="button">添加电影</button>
                    <button type="reset" class="button secondary">重置</button>
                </div>
            </form>
        </div>
​
        <footer>
            <p>© {{ current_year }} 电影投票系统 | hui函数</p>
        </footer>
    </div>
</body>
</html>
  • 设置添加电影的路由
python 复制代码
@app.route('/add', methods=['POST'])
def add_movie():
    title = request.form.get('title', '').strip()
    year = request.form.get('year', '')
​
    if not title or not year:
        flash('电影名称和年份必须填写')
        return redirect(url_for('add_movie_page'))
​
    try:
        year = int(year)
        if year < 1900 or year > datetime.now().year:
            flash('年份不合法')
            return redirect(url_for('add_movie_page'))
    except ValueError:
        flash('请输入数字年份')
        return redirect(url_for('add_movie_page'))
​
    existing = Movie.query.filter_by(title=title).first()
    if existing:
        flash(f'电影 "{title}" 已存在!')
        return redirect(url_for('add_movie_page'))
​
    movie = Movie(title=title, year=year)
    db.session.add(movie)
    db.session.commit()
​
    flash(f'电影 "{title}" 添加成功!')
    return redirect(url_for('index'))
公共样式
  • 在static中创建一个style.css的文件
css 复制代码
/* 基础样式 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
​
body {
    background-color: #f5f7fa;
    color: #333;
    line-height: 1.6;
    padding: 20px;
}
​
.container {
    max-width: 1000px;
    margin: 0 auto;
    padding: 20px;
}
​
header {
    text-align: center;
    margin-bottom: 30px;
    padding-bottom: 20px;
    border-bottom: 1px solid #eaeaea;
}
​
h1 {
    color: #2c3e50;
    font-size: 2.5rem;
    margin-bottom: 10px;
}
​
.subtitle {
    color: #7f8c8d;
    font-size: 1.2rem;
}
​
/* 消息提示 */
.messages {
    margin: 20px 0;
}
​
.message {
    padding: 15px;
    margin-bottom: 10px;
    border-radius: 4px;
    background: #e3f2fd;
    color: #1976d2;
    border-left: 4px solid #1976d2;
}
​
/* 按钮样式 */
.button {
    display: inline-block;
    padding: 10px 20px;
    background: #3498db;
    color: white;
    text-decoration: none;
    border-radius: 4px;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    transition: background 0.3s;
}
​
.button:hover {
    background: #2980b9;
}
​
.button.back {
    background: #95a5a6;
}
​
.button.back:hover {
    background: #7f8c8d;
}
​
.button.warning {
    background: #f39c12;
}
​
.button.warning:hover {
    background: #e67e22;
}
​
.button.secondary {
    background: #95a5a6;
}
​
.button.secondary:hover {
    background: #7f8c8d;
}
​
/* 表单控件 */
.controls, .form-actions {
    margin: 20px 0;
    display: flex;
    gap: 10px;
}
​
.inline-form {
    display: inline-block;
}
​
/* 电影列表 */
.movie-list {
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    padding: 20px;
    margin: 20px 0;
}
​
table {
    width: 100%;
    border-collapse: collapse;
}
​
th, td {
    padding: 12px 15px;
    text-align: left;
    border-bottom: 1px solid #eee;
}
​
th {
    background-color: #f8f9fa;
    color: #34495e;
    font-weight: 600;
}
​
tr:hover {
    background-color: #f9f9f9;
}
​
.movie-title {
    font-weight: 600;
}
​
.movie-votes {
    font-weight: bold;
    color: #e74c3c;
}
​
.movie-actions {
    display: flex;
    gap: 8px;
}
​
.small-button {
    padding: 6px 12px;
    font-size: 0.9rem;
}
​
.small-button.danger {
    background: #e74c3c;
}
​
.small-button.danger:hover {
    background: #c0392b;
}
​
/* 添加电影表单 */
.form-container {
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    padding: 30px;
    margin: 20px 0;
}
​
.form-group {
    margin-bottom: 20px;
}
​
label {
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
    color: #2c3e50;
}
​
input[type="text"],
input[type="number"] {
    width: 100%;
    padding: 10px 15px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 1rem;
}
​
input:focus {
    outline: none;
    border-color: #3498db;
}
​
/* 无电影提示 */
.no-movies {
    text-align: center;
    padding: 40px 20px;
    color: #7f8c8d;
}
​
/* 页脚 */
footer {
    text-align: center;
    margin-top: 40px;
    padding-top: 20px;
    border-top: 1px solid #eaeaea;
    color: #95a5a6;
    font-size: 0.9rem;
}
相关推荐
酷飞飞2 小时前
Python网络与多任务编程:TCP/UDP实战指南
网络·python·tcp/ip
数字化顾问3 小时前
Python:OpenCV 教程——从传统视觉到深度学习:YOLOv8 与 OpenCV DNN 模块协同实现工业缺陷检测
python
学生信的大叔4 小时前
【Python自动化】Ubuntu24.04配置Selenium并测试
python·selenium·自动化
用户21411832636024 小时前
Qwen3-Coder 实战!历史人物短视频一键生成,多分镜人物不崩,魔搭直接玩
后端
追逐时光者5 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 54 期(2025年9.8-9.14)
后端·.net
追逐时光者5 小时前
C#/.NET/.NET Core编程技巧练习集,配套详细的文章教程讲解!
后端·.net
诗句藏于尽头5 小时前
Django模型与数据库表映射的两种方式
数据库·python·django
智数研析社5 小时前
9120 部 TMDb 高分电影数据集 | 7 列全维度指标 (评分 / 热度 / 剧情)+API 权威源 | 电影趋势分析 / 推荐系统 / NLP 建模用
大数据·人工智能·python·深度学习·数据分析·数据集·数据清洗
扯淡的闲人5 小时前
多语言编码Agent解决方案(5)-IntelliJ插件实现
开发语言·python
AD钙奶-lalala5 小时前
SpringBoot实现WebSocket服务端
spring boot·后端·websocket