当前位置:  首页>> 技术小册>> Flask框架入门指南

实战项目二:开发在线投票系统

引言

在Flask框架的学习旅程中,通过实际项目来巩固知识是不可或缺的一环。本章节将带领你构建一个完整的在线投票系统,该系统允许用户创建投票、参与投票并查看投票结果。通过这个项目,你将深入理解Flask的路由、模板渲染、表单处理、数据库操作(使用SQLite为例)、会话管理以及用户认证等核心概念。

项目概述

在线投票系统主要由以下几个模块组成:

  1. 用户管理:支持用户注册、登录、登出及基本信息管理。
  2. 投票管理:管理员或特定用户能够创建新的投票,设定投票选项,并设置投票结束时间。
  3. 投票参与:注册用户可参与已发布的投票,为每个选项投票一次。
  4. 结果展示:展示每个投票的当前结果,包括每个选项的票数及投票者总数。
  5. 投票结束处理:投票结束后,系统自动锁定投票,防止进一步投票,并允许用户查看最终投票结果。

环境准备

在开始编码之前,请确保你的开发环境已经安装了Python和Flask。此外,还需要安装Flask-SQLAlchemy(用于数据库操作)、Flask-Login(用于用户认证)和Flask-WTF(用于表单处理)等扩展库。可以通过pip安装这些库:

  1. pip install Flask Flask-SQLAlchemy Flask-Login Flask-WTF

数据库设计

首先,设计数据库模型。我们需要至少三个表:User(用户)、Vote(投票)和Choice(投票选项)。

  1. from flask_sqlalchemy import SQLAlchemy
  2. from flask_login import UserMixin
  3. from datetime import datetime
  4. db = SQLAlchemy()
  5. class User(db.Model, UserMixin):
  6. id = db.Column(db.Integer, primary_key=True)
  7. username = db.Column(db.String(64), unique=True, nullable=False)
  8. email = db.Column(db.String(120), unique=True, nullable=False)
  9. password_hash = db.Column(db.String(128), nullable=False)
  10. def __repr__(self):
  11. return f'<User {self.username}>'
  12. class Vote(db.Model):
  13. id = db.Column(db.Integer, primary_key=True)
  14. title = db.Column(db.String(255), nullable=False)
  15. start_time = db.Column(db.DateTime, default=datetime.utcnow)
  16. end_time = db.Column(db.DateTime, nullable=True)
  17. active = db.Column(db.Boolean, default=True)
  18. choices = db.relationship('Choice', backref='vote', lazy=True)
  19. def __repr__(self):
  20. return f'<Vote {self.title}>'
  21. class Choice(db.Model):
  22. id = db.Column(db.Integer, primary_key=True)
  23. vote_id = db.Column(db.Integer, db.ForeignKey('vote.id'), nullable=False)
  24. choice_text = db.Column(db.String(255), nullable=False)
  25. votes = db.Column(db.Integer, default=0)
  26. def __repr__(self):
  27. return f'<Choice {self.choice_text}>'

用户认证与登录

使用Flask-Login来处理用户认证。首先,配置Flask-Login并创建用户加载器函数:

  1. from flask_login import LoginManager, login_user, logout_user, login_required, current_user
  2. login_manager = LoginManager()
  3. login_manager.login_view = 'auth.login'
  4. login_manager.init_app(app)
  5. @login_manager.user_loader
  6. def load_user(user_id):
  7. return User.query.get(int(user_id))
  8. # 示例登录函数
  9. @app.route('/login', methods=['GET', 'POST'])
  10. def login():
  11. # 省略表单处理和验证逻辑
  12. user = User.query.filter_by(username=form.username.data).first()
  13. if user is None or not check_password_hash(user.password_hash, form.password.data):
  14. flash('Invalid username or password')
  15. return redirect(url_for('login'))
  16. login_user(user, remember=form.remember_me.data)
  17. return redirect(url_for('main.index'))

投票系统核心功能实现

创建投票

  • 管理员通过表单提交投票标题、选项及结束时间。
  • 表单验证后,将数据存储至数据库。
  1. from flask import Blueprint, render_template, request, redirect, url_for, flash
  2. from .forms import VoteForm
  3. vote_bp = Blueprint('vote', __name__)
  4. @vote_bp.route('/create', methods=['GET', 'POST'])
  5. @login_required
  6. def create_vote():
  7. form = VoteForm()
  8. if form.validate_on_submit():
  9. vote = Vote(title=form.title.data, start_time=datetime.utcnow())
  10. db.session.add(vote)
  11. db.session.commit()
  12. for choice in form.choices.data:
  13. new_choice = Choice(vote_id=vote.id, choice_text=choice)
  14. db.session.add(new_choice)
  15. db.session.commit()
  16. flash('Vote created successfully!')
  17. return redirect(url_for('vote.view_vote', vote_id=vote.id))
  18. return render_template('create_vote.html', form=form)

参与投票

  • 用户选择投票后,展示投票选项。
  • 用户选择选项并提交,系统验证后更新数据库中的票数。
  1. @vote_bp.route('/<int:vote_id>/vote', methods=['GET', 'POST'])
  2. @login_required
  3. def vote_on_vote(vote_id):
  4. vote = Vote.query.get_or_404(vote_id)
  5. if not vote.active:
  6. flash('This vote is not active.')
  7. return redirect(url_for('vote.view_vote', vote_id=vote_id))
  8. # 假设我们使用简单的单选逻辑
  9. choice_id = request.form.get('choice')
  10. if choice_id:
  11. choice = Choice.query.get(choice_id)
  12. if choice and current_user.id not in [v.user_id for v in choice.votes]:
  13. choice.votes += 1
  14. # 这里可以添加额外的逻辑来记录投票用户
  15. db.session.commit()
  16. flash('Your vote has been cast!')
  17. else:
  18. flash('You have already voted for this option or you are not allowed to vote again.')
  19. return redirect(url_for('vote.view_vote', vote_id=vote_id))
  20. # 省略view_vote等函数实现,以展示投票结果

安全性与错误处理

  • 确保所有输入都经过适当的验证和清理,防止SQL注入等安全漏洞。
  • 使用会话和CSRF保护来增强表单提交的安全性。
  • 对于错误处理,使用Flask的flash消息和适当的HTTP状态码来通知用户操作结果。

总结

通过开发这个在线投票系统,你不仅掌握了Flask框架的基本用法,还深入理解了Web应用开发中常见的模式和挑战,如用户认证、表单处理、数据库操作及安全性考虑。这个项目可以作为你进一步学习Flask和Web开发的坚实基础,激发你探索更多高级特性和最佳实践的兴趣。


该分类下的相关小册推荐: