0


用Python Flask为女朋友做一个简单的网站(附可运行的源码)

🌟
所属专栏:献给榕榕

🐔
作者简介:rchjr——五带信管菜只因一枚

😮
前言:该专栏系为女友准备的,里面会不定时发一些讨好她的技术作品,感兴趣的小伙伴可以关注一下~

👉
文章简介:献给女友的简单网站源代码

😃0 前言与开发环境

前言

这篇文章把自己今年寒假花了20天做的一个网站放出来。这个网站就是用来练练手感的,接下来会重新做一个属于我的个人网站,主题还没有想好,但是应该是类似于一个个人博客吧。后面做网站时会一直更新进度,感兴趣的小伙伴可以关注我了解后续,这个送给女朋友的就不详解了,直接放置源码,可以直接运行,当做一个参考。

开发环境

开发语言:python 3.8

开发框架:Flask

开发工具:PyCharm专业版

虚拟环境工具:Anaconda

浏览器:谷歌浏览器

😃1 运行结果图

主页

登录界面

注册界面

照片墙

想去的地方(挪威)

留言(无法提交)

浪漫烟花(带背景音乐)

注销

😃2 代码结构

一个app文件夹用来存放各个功能(忘记术语叫啥了),对应上面展示的几个功能。static文件夹存放静态文件,具体包括css文件,js文件和html文件以及图片和背景音乐。当然还有模型文件models.py存放数据库模型。

然后是config.py存放一些要用的配置类,manager.py作为主文件用于启动整个项目。

😃3 config.py配置文件

先从配置信息开始讲起吧。这个网站我用到的配置信息只有连接MySQL要用的一些相关信息,比较简单。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/3 15:08
  4. """各种配置类"""
  5. class BaseConfig(object):
  6. """所有配置类的基类"""
  7. SECRET_KEY = "LOVE"
  8. DEBUG = True
  9. TESTING = False
  10. VISIT_TIME = 0 # 网站访问次数
  11. # 数据库配置
  12. SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:这里换成自己的MySQL密码@localhost/personalwebsite"
  13. SQLALCHEMY_TRACK_MODIFICATIONS = False # 是否追踪数据库的修改
  14. class ProductionConfig(BaseConfig):
  15. """生产环境下的配置类"""
  16. DEBUG = False
  17. class DevelopmentConfig(BaseConfig):
  18. """开发模式下的配置类"""
  19. DEBUG = True
  20. TESTING = True

然后我是使用的Navicat这个工具用来可视化操作MySQL的。就是下面这个家伙啦,可以在网上找到破解版的,如果想和我用一样的话,这里也有百度网盘的下载链接:

链接:
https://pan.baidu.com/s/1WqS8H2fHAwkPm76O-7OClg?pwd=9rlv

提取码:9rlv

--来自百度网盘超级会员V3的分享

打开Navicat可以看到我创建了一个名为personalwebsite的数据库,双击它可以看到

我创建了两个表,一个是存放用户登录信息的,另一个message本来打算存放留言的,但是后面没用到大家可以不用管。

😃4 app包详解

这个包里面包含了整个网页代码,因此是本次项目的大头,我将按照登录注册功能、照片墙功能、我说功能、我想去的地方功能和浪漫烟花功能的顺序进行讲解。另外项目采用蓝图的方式开发,每次搞定完一个功能,就会在app包下面的__init__.py文件中添加相应的信息。这样方便管理整个项目结构,使之整洁、易于修改,可扩展性也很好。

📜4.1 登录注册功能

登录注册功能在app_login包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/8 23:19
  4. """登录视图的蓝图"""
  5. from flask import Blueprint
  6. login = Blueprint("login", __name__)
  7. from . import view

在app_login/init.py文件中我创建了一个登录视图的蓝图。接下来看登录注册的视图文件

首先导入了实现登录要用的一些Flask提供的模块,比如login_required, login_user, logout_user。具体功能我就不细讲了。然后导入了跳转网页要用的request, render_template, redirect, url_for, flash,还导入了数据库模型User和刚刚创建的蓝图login,最后从app包下的__init__.py中导入了管理登录用的login_manager,这个等会展示app/init.py的时候会看得到。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/6 11:39
  4. """登录的视图函数"""
  5. from flask import request, render_template, redirect, url_for, flash
  6. from flask_login import login_required, login_user, logout_user
  7. from . import login
  8. from app.models import User
  9. from app import login_manager
  10. @login_manager.user_loader
  11. def load_user(user_id): # 创建用户加载回调函数,接受用户 ID 作为参数
  12. user = User.query.get(int(user_id)) # 用 ID 作为 User 模型的主键查询对应的用户
  13. return user # 返回用户对象
  14. @login.route('/index', methods=['GET', 'POST'])
  15. @login_required
  16. def index():
  17. return render_template('index.html')
  18. @login.route('/register', methods=['GET', 'POST'])
  19. def register():
  20. # 如果请求为post
  21. if request.method == 'POST':
  22. count = request.form.get('count')
  23. password = request.form.get('password')
  24. repassword = request.form.get('repassword')
  25. from app import db
  26. if password == repassword:
  27. user = User(count, password)
  28. user.set_password(password)
  29. db.session.add(user)
  30. db.session.commit()
  31. return redirect(url_for("login.login_"))
  32. else:
  33. flash("两次密码不一致!")
  34. return render_template("register.html")
  35. return render_template('register.html')
  36. @login.route('/', methods=['GET', 'POST'])
  37. @login.route('/login', methods=['GET', 'POST'])
  38. def login_():
  39. if request.method == 'POST':
  40. count = request.form['count']
  41. password = request.form['password']
  42. if not count or not password:
  43. flash('请输入账号和密码!')
  44. return redirect(url_for('login.login_'))
  45. user = User.query.filter_by(count=count).first()
  46. if not user:
  47. flash("用户不存在")
  48. return redirect(url_for('login.login_'))
  49. if count == user.count and user.check_password(password):
  50. login_user(user) # 登入用户
  51. return redirect(url_for('login.index')) # 重定向到主页
  52. flash('账号或密码不正确, 请重新登录!') # 如果验证失败,显示错误消息
  53. return redirect(url_for('login.login_')) # 重定向回登录页面
  54. return render_template('login.html')
  55. @login.route('/logout', methods=['GET','POST'])
  56. @login_required
  57. def logout():
  58. logout_user()
  59. return redirect(url_for('login.login_'))

导入需要的模块和函数后,用login_manager作为修饰器管理用户登录,具体就是从数据库中查询信息判断是否存在用户,可以看其他博客了解详情。然后是分别用对应的修饰器修饰主页、注册页面、登录页面和注销页面。

下面给出要用到的前端文件

index.html

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 主页
  4. {% endblock %}
  5. {% block div %}
  6. <div class="wenzi_a">
  7. <img src="../static/images/background_images/照片墙.png" style="height: 50px; width: 50px">
  8. <span><font size="4" color=#000000><b>&nbsp;我们的相册</b></font></span>
  9. <div class="wenzi_font">
  10. <font size="3"><b>
  11. 举目望向天空,有说不尽的美好。<br/>
  12. 夏天来临之前,温暖洒满了一地。<br/>
  13. 轻轻翻阅发黄的书卷,斑驳往事。<br/>
  14. 抓住午后跳跃的阳光,锁住流年。<br/>
  15. 到底是怎样一种繁华创造了永恒?<br/>
  16. 夏日的夕阳将天空染成了橘色。<br/>
  17. 我们走过的路上,落满一地的幸福。<br/>
  18. </b></font>
  19. </div>
  20. </div>
  21. <div class="wenzi_b">
  22. <img src="../static/images/background_images/爱心.png">
  23. <span><font size="4" color=#000000><b>我与你</b></font></span>
  24. <div class="wenzi_font">
  25. <font size="3"><b>
  26. 时光的洪流把每个人的生命印刻成一<br/>
  27. 枚枚底片。记忆沿着掌心的脉络聚成<br/>
  28. 一幅幅永恒的画面。这些光怪陆离的<br/>
  29. 记忆中最令我怀念的就是,最美的你<br/>
  30. 陪我走过最绚烂的年华。<br/>
  31. </b></font>
  32. </div>
  33. </div>
  34. <div class="wenzi_c">
  35. <img src="../static/images/background_images/消息.png">
  36. <span><font size="4" color=#000000><b>我想说</b></font></span>
  37. <div class="wenzi_font">
  38. <font size="3"><b>
  39. 呯呯的心跳却总能代表我的情意。<br/>
  40. 想说爱你其实真的很遥远,傍山 <br/>
  41. 涉水地追求,可能才是我的目的。<br/>
  42. 想说爱你只是想真心对待你,<br/>
  43. 想说爱你只是想真实地表达自己。<br/>
  44. </b></font>
  45. </div>
  46. </div>
  47. <div class="wenzi_d">
  48. <img src="../static/images/background_images/走.png">
  49. <span><font size="4" color=#000000><b>&nbsp;&emsp;想去的地方</b></font></span>
  50. <div class="wenzi_font">
  51. <font size="3">
  52. <b>
  53. 前面以上的文字均来自百度, <br/>
  54. 原谅我即时在这种特殊的日子 <br/>
  55. 也说不出来一句“像样的”言语。<br/>
  56. 我平时已经说的够多了,为了 <br/>
  57. 让记忆永存,我自学了网页语 <br/>
  58. 言编写了这个网站。制作过程 <br/>
  59. 过程费尽心血和精力,但一切 <br/>
  60. 都是得的。<br/>
  61. </b>
  62. </font>
  63. </div>
  64. </div>
  65. {% endblock %}

register.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" type="text/css" href="../static/css/login.css"/>
  7. <script src="../static/js/register.js" type="text/javascript"></script>
  8. </head>
  9. <body>
  10. <div class="login-box">
  11. <h2>注册</h2>
  12. <p class="tip">
  13. {% for item in get_flashed_messages() %}
  14. {{ item }}
  15. {% endfor %}
  16. </p>
  17. <form action="/register" method="post">
  18. <div class="login-field">
  19. <span style="color: aqua; size: 12px">账号</span>
  20. <input type="text" name="count" required=""/>
  21. </div>
  22. <div class="login-field">
  23. <spqn style="color: aqua; size: 12px">密码</spqn>
  24. <input type="password" name="password" required=""/>
  25. </div>
  26. <div class="login-field">
  27. <spqn style="color: aqua; size: 12px">确认密码</spqn>
  28. <input type="password" name="repassword" required=""/>
  29. </div>
  30. <input type="submit" value="提交" id="myloginlabel">
  31. <p style="color: rgba(194,108,108,0.58)">已有账号?<a href="./login" style="color: rgba(22,180,166,0.58)"
  32. onclick="topggleForm();">登录</a></p>
  33. </form>
  34. </div>
  35. </body>
  36. </html>

login.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>榕城与佳人</title>
  6. <link rel="stylesheet" type="text/css" href="../static/css/login.css"/>
  7. <script src="../static/js/register.js" type="text/javascript"></script>
  8. <link rel="shortcut icon" href="../static/images/ico_images/wjr.ico">
  9. </head>
  10. <body>
  11. <div class="login-box">
  12. <h2 style="color: #ce8483; font-family: 华文彩云">榕城佳人</h2>
  13. <p class="tip">
  14. {% for item in get_flashed_messages() %}
  15. {{ item }}
  16. {% endfor %}
  17. </p>
  18. <form action="/login" method="post">
  19. <div class="login-field">
  20. <span style="color: aqua; size: 12px">账号</span>
  21. <input type="text" name="count" required=""/>
  22. </div>
  23. <div class="login-field">
  24. <spqn style="color: aqua; size: 12px">密码</spqn>
  25. <input type="password" name="password" required=""/>
  26. </div>
  27. <input type="submit" value="点击进入" id="myloginlabel">
  28. <p style="color: rgba(222,112,112,0.58)">没有账号?<a href="./register" style="color: rgba(22,180,166,0.58)"
  29. onclick="topggleForm();">注册</a></p>
  30. </form>
  31. </div>
  32. </body>
  33. </html>

当然其他的css文件,图片等后面会一并给出。

📟4.2 照片墙功能

照片墙功能在app_photo_wall包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/13 16:10
  4. """照片墙的蓝图"""
  5. from flask import Blueprint
  6. photo_wall = Blueprint("photo_wall", __name__)
  7. from . import view

在app_photo_wall/init.py文件中我创建了一个照片墙视图的蓝图。接下来看照片墙的视图文件

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/13 16:20
  4. """照片墙的视图函数"""
  5. from flask import render_template
  6. from flask_login import login_required
  7. from . import photo_wall
  8. @photo_wall.route('/photo_wall', methods=['GET', 'POST'])
  9. @login_required
  10. def index():
  11. return render_template('photo_wall.html')

照片墙后端很简单,主要是靠前端实现的,下面给出前端代码

photo_wall.html

当然大家可以换成自己想换的照片。

  1. {% extends "base.html" %}
  2. {% block title %}
  3. 照片墙
  4. {% endblock %}
  5. {% block div %}
  6. <div id="div2">
  7. <div id="photo_box">
  8. <img src="../static/images/photo_wall_images/wjr%20(1).jpg">
  9. <img src="../static/images/photo_wall_images/wjr%20(2).jpg">
  10. <img src="../static/images/photo_wall_images/wjr%20(3).jpg">
  11. <img src="../static/images/photo_wall_images/wjr%20(4).jpg">
  12. <img src="../static/images/photo_wall_images/wjr%20(5).jpg">
  13. <img src="../static/images/photo_wall_images/wjr%20(6).jpg">
  14. <img src="../static/images/photo_wall_images/wjr%20(7).jpg">
  15. <img src="../static/images/photo_wall_images/wjr%20(8).jpg">
  16. <img src="../static/images/photo_wall_images/wjr%20(9).jpg">
  17. <img src="../static/images/photo_wall_images/wjr%20(10).jpg">
  18. <img src="../static/images/photo_wall_images/wjr%20(11).jpg">
  19. <img src="../static/images/photo_wall_images/wjr%20(12).jpg">
  20. <img src="../static/images/photo_wall_images/wjr%20(13).jpg">
  21. <img src="../static/images/photo_wall_images/wjr_%20(1).jpg">
  22. <img src="../static/images/photo_wall_images/wjr_%20(2).jpg">
  23. <img src="../static/images/photo_wall_images/wjr_%20(3).jpg">
  24. <img src="../static/images/photo_wall_images/wjr_%20(4).jpg">
  25. <img src="../static/images/photo_wall_images/wjr_%20(5).jpg">
  26. <img src="../static/images/photo_wall_images/wjr_%20(6).jpg">
  27. <img src="../static/images/photo_wall_images/wjr_%20(7).jpg">
  28. </div>
  29. </div>
  30. {% endblock %}

😛4.3 我说功能

我说功能在app_isay包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/22 8:52
  4. """"""
  5. from flask import Blueprint
  6. isay = Blueprint("isay", __name__)
  7. from . import view

在app_isay/init.py文件中我创建了一个我说视图的蓝图。接下来看我说功能的视图文件

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/22 8:52
  4. """我说的视图函数"""
  5. import time
  6. from . import isay
  7. from flask import request, render_template, session
  8. from flask_login import login_required
  9. from app.models import User, Message
  10. @isay.route('/isay', methods=['GET', 'POST'])
  11. @login_required
  12. def isay():
  13. from app import db
  14. if request.method == 'POST':
  15. return render_template('isay.html')
  16. if request.method == 'POST':
  17. title = request.form.get("title")
  18. text = request.form.get("text")
  19. count = session.get('count')
  20. print(count)
  21. # 获取当前系统时间
  22. created_time = time.strftime("%Y-%m-%d %H:%M:%S")
  23. user = User.query.filter_by(count=count).first()
  24. message = Message(title=title, text=text, created_time=created_time, user_id=user.id)
  25. db.session.add(message)
  26. db.session.commit()
  27. blog = Message.query.filter(Message.created_time == created_time).first()
  28. return render_template('blogSuccess.html', title=title, id=message.id)

这个功能其实没开发好,大家可以不用管它或者自行完善也行。

✈4.4 想去的地方功能

想去的地方功能在app_togo包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/23 11:34
  4. """"""
  5. from flask import Blueprint
  6. togo = Blueprint("togo", __name__)
  7. from . import view

在app_togo/init.py文件中我创建了一个想去的地方视图的蓝图。接下来看看想去的地方功能的视图文件

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/23 11:35
  4. """想去的地方"""
  5. from . import togo
  6. from flask import render_template
  7. @togo.route("/togo", methods=['POST', 'GET'])
  8. def togo():
  9. return render_template("togo.html")

这个功能主要是在前端导入了谷歌地图的API,下面给出前端页面

togo.html

  1. {% extends "base.html" %}
  2. {% block div %}
  3. <iframe src="https://www.google.com/maps/embed?pb=!1m14!1m12!1m3!1d11329513.820172088!2d14.194477459720666!3d61.318977221270224!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!5e0!3m2!1szh-CN!2s!4v1674447168409!5m2!1szh-CN!2s"
  4. width="800" height="600" class="map" allowfullscreen="" loading="lazy"
  5. referrerpolicy="no-referrer-when-downgrade"></iframe>
  6. {% endblock %}

💥4.5 浪漫烟花功能

浪漫烟花功能在app_fireflower包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/2/11 20:48
  4. """"""
  5. from flask import Blueprint
  6. fireflower = Blueprint("fireflower", __name__)
  7. from . import view

在app_fireflower/init.py文件中我创建了一个浪漫烟花视图的蓝图。接下来看看浪漫烟花功能的视图文件

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/2/11 20:48
  4. """"""
  5. from flask import render_template
  6. from flask_login import login_required
  7. from . import fireflower
  8. @fireflower.route('/fireflower', methods=['GET', 'POST'])
  9. @login_required
  10. def index():
  11. return render_template('romanticFireFlower.html')

这个功能主要是在前端实现的,下面给出前端页面

romanticFireFlower.html

  1. {% extends "base.html" %}
  2. {% block title %}
  3. 浪漫烟花
  4. {% endblock %}
  5. {% block div %}
  6. <style>
  7. html, body {
  8. width: 100%;
  9. height: 100%;
  10. overflow: hidden;
  11. background: rgba(15, 23, 22, 0.8);
  12. }
  13. </style>
  14. {# <form action="/fireflower" method="post"></form>#}
  15. <audio autoplay="autoplay" loop="loop" preload="auto"
  16. src="../static/music/Because%20of%20You.mp3"></audio>
  17. <canvas id="canvas" style="position:relative;width:1500px;height:800px;z-index:9999;top: 100px"></canvas>
  18. <canvas style="position:absolute;width:100%;height:100%;z-index:9999" class="canvas"></canvas>
  19. <div class="overlay">
  20. <div class="tabs">
  21. <div class="tabs-labels"><span class="tabs-label">Commands</span><span class="tabs-label">Info</span><span
  22. class="tabs-label">Share</span></div>
  23. <div class="tabs-panels">
  24. <ul class="tabs-panel commands">
  25. </ul>
  26. </div>
  27. </div>
  28. </div>
  29. <script>
  30. function initVars() {
  31. pi = Math.PI;
  32. ctx = canvas.getContext("2d");
  33. canvas.width = canvas.clientWidth;
  34. canvas.height = canvas.clientHeight;
  35. cx = canvas.width / 2;
  36. cy = canvas.height / 2;
  37. playerZ = -25;
  38. playerX = playerY = playerVX = playerVY = playerVZ = pitch = yaw = pitchV = yawV = 0;
  39. scale = 600;
  40. seedTimer = 0;
  41. seedInterval = 5, seedLife = 100;
  42. gravity = .02;
  43. seeds = new Array();
  44. sparkPics = new Array();
  45. s = "https://cantelope.org/NYE/";
  46. for (i = 1; i <= 10; ++i) {
  47. sparkPic = new Image();
  48. sparkPic.src = s + "spark" + i + ".png";
  49. sparkPics.push(sparkPic);
  50. }
  51. sparks = new Array();
  52. pow1 = new Audio(s + "pow1.ogg");
  53. pow2 = new Audio(s + "pow2.ogg");
  54. pow3 = new Audio(s + "pow3.ogg");
  55. pow4 = new Audio(s + "pow4.ogg");
  56. frames = 0;
  57. }
  58. function rasterizePoint(x, y, z) {
  59. var p, d;
  60. x -= playerX;
  61. y -= playerY;
  62. z -= playerZ;
  63. p = Math.atan2(x, z);
  64. d = Math.sqrt(x * x + z * z);
  65. x = Math.sin(p - yaw) * d;
  66. z = Math.cos(p - yaw) * d;
  67. p = Math.atan2(y, z);
  68. d = Math.sqrt(y * y + z * z);
  69. y = Math.sin(p - pitch) * d;
  70. z = Math.cos(p - pitch) * d;
  71. var rx1 = -1000, ry1 = 1, rx2 = 1000, ry2 = 1, rx3 = 0, ry3 = 0, rx4 = x, ry4 = z,
  72. uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);
  73. if (!uc) return {x: 0, y: 0, d: -1};
  74. var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;
  75. var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;
  76. if (!z) z = .000000001;
  77. if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
  78. return {
  79. x: cx + (rx1 + ua * (rx2 - rx1)) * scale,
  80. y: cy + y / z * scale,
  81. d: Math.sqrt(x * x + y * y + z * z)
  82. };
  83. } else {
  84. return {
  85. x: cx + (rx1 + ua * (rx2 - rx1)) * scale,
  86. y: cy + y / z * scale,
  87. d: -1
  88. };
  89. }
  90. }
  91. function spawnSeed() {
  92. seed = new Object();
  93. seed.x = -50 + Math.random() * 100;
  94. seed.y = 25;
  95. seed.z = -50 + Math.random() * 100;
  96. seed.vx = .1 - Math.random() * .2;
  97. seed.vy = -1.5;//*(1+Math.random()/2);
  98. seed.vz = .1 - Math.random() * .2;
  99. seed.born = frames;
  100. seeds.push(seed);
  101. }
  102. function splode(x, y, z) {
  103. t = 5 + parseInt(Math.random() * 150);
  104. sparkV = 1 + Math.random() * 2.5;
  105. type = parseInt(Math.random() * 3);
  106. switch (type) {
  107. case 0:
  108. pic1 = parseInt(Math.random() * 10);
  109. break;
  110. case 1:
  111. pic1 = parseInt(Math.random() * 10);
  112. do {
  113. pic2 = parseInt(Math.random() * 10);
  114. } while (pic2 == pic1);
  115. break;
  116. case 2:
  117. pic1 = parseInt(Math.random() * 10);
  118. do {
  119. pic2 = parseInt(Math.random() * 10);
  120. } while (pic2 == pic1);
  121. do {
  122. pic3 = parseInt(Math.random() * 10);
  123. } while (pic3 == pic1 || pic3 == pic2);
  124. break;
  125. }
  126. for (m = 1; m < t; ++m) {
  127. spark = new Object();
  128. spark.x = x;
  129. spark.y = y;
  130. spark.z = z;
  131. p1 = pi * 2 * Math.random();
  132. p2 = pi * Math.random();
  133. v = sparkV * (1 + Math.random() / 6)
  134. spark.vx = Math.sin(p1) * Math.sin(p2) * v;
  135. spark.vz = Math.cos(p1) * Math.sin(p2) * v;
  136. spark.vy = Math.cos(p2) * v;
  137. switch (type) {
  138. case 0:
  139. spark.img = sparkPics[pic1];
  140. break;
  141. case 1:
  142. spark.img = sparkPics[parseInt(Math.random() * 2) ? pic1 : pic2];
  143. break;
  144. case 2:
  145. switch (parseInt(Math.random() * 3)) {
  146. case 0:
  147. spark.img = sparkPics[pic1];
  148. break;
  149. case 1:
  150. spark.img = sparkPics[pic2];
  151. break;
  152. case 2:
  153. spark.img = sparkPics[pic3];
  154. break;
  155. }
  156. break;
  157. }
  158. spark.radius = 25 + Math.random() * 50;
  159. spark.alpha = 1;
  160. spark.trail = new Array();
  161. sparks.push(spark);
  162. }
  163. switch (parseInt(Math.random() * 4)) {
  164. case 0:
  165. pow = new Audio(s + "pow1.ogg");
  166. break;
  167. case 1:
  168. pow = new Audio(s + "pow2.ogg");
  169. break;
  170. case 2:
  171. pow = new Audio(s + "pow3.ogg");
  172. break;
  173. case 3:
  174. pow = new Audio(s + "pow4.ogg");
  175. break;
  176. }
  177. d = Math.sqrt((x - playerX) * (x - playerX) + (y - playerY) * (y - playerY) + (z - playerZ) * (z - playerZ));
  178. pow.volume = 1.5 / (1 + d / 10);
  179. pow.play();
  180. }
  181. function doLogic() {
  182. if (seedTimer < frames) {
  183. seedTimer = frames + seedInterval * Math.random() * 10;
  184. spawnSeed();
  185. }
  186. for (i = 0; i < seeds.length; ++i) {
  187. seeds[i].vy += gravity;
  188. seeds[i].x += seeds[i].vx;
  189. seeds[i].y += seeds[i].vy;
  190. seeds[i].z += seeds[i].vz;
  191. if (frames - seeds[i].born > seedLife) {
  192. splode(seeds[i].x, seeds[i].y, seeds[i].z);
  193. seeds.splice(i, 1);
  194. }
  195. }
  196. for (i = 0; i < sparks.length; ++i) {
  197. if (sparks[i].alpha > 0 && sparks[i].radius > 5) {
  198. sparks[i].alpha -= .01;
  199. sparks[i].radius /= 1.02;
  200. sparks[i].vy += gravity;
  201. point = new Object();
  202. point.x = sparks[i].x;
  203. point.y = sparks[i].y;
  204. point.z = sparks[i].z;
  205. if (sparks[i].trail.length) {
  206. x = sparks[i].trail[sparks[i].trail.length - 1].x;
  207. y = sparks[i].trail[sparks[i].trail.length - 1].y;
  208. z = sparks[i].trail[sparks[i].trail.length - 1].z;
  209. d = ((point.x - x) * (point.x - x) + (point.y - y) * (point.y - y) + (point.z - z) * (point.z - z));
  210. if (d > 9) {
  211. sparks[i].trail.push(point);
  212. }
  213. } else {
  214. sparks[i].trail.push(point);
  215. }
  216. if (sparks[i].trail.length > 5) sparks[i].trail.splice(0, 1);
  217. sparks[i].x += sparks[i].vx;
  218. sparks[i].y += sparks[i].vy;
  219. sparks[i].z += sparks[i].vz;
  220. sparks[i].vx /= 1.075;
  221. sparks[i].vy /= 1.075;
  222. sparks[i].vz /= 1.075;
  223. } else {
  224. sparks.splice(i, 1);
  225. }
  226. }
  227. p = Math.atan2(playerX, playerZ);
  228. d = Math.sqrt(playerX * playerX + playerZ * playerZ);
  229. d += Math.sin(frames / 80) / 1.25;
  230. t = Math.sin(frames / 200) / 40;
  231. playerX = Math.sin(p + t) * d;
  232. playerZ = Math.cos(p + t) * d;
  233. yaw = pi + p + t;
  234. }
  235. function rgb(col) {
  236. var r = parseInt((.5 + Math.sin(col) * .5) * 16);
  237. var g = parseInt((.5 + Math.cos(col) * .5) * 16);
  238. var b = parseInt((.5 - Math.sin(col) * .5) * 16);
  239. return "#" + r.toString(16) + g.toString(16) + b.toString(16);
  240. }
  241. function draw() {
  242. ctx.clearRect(0, 0, cx * 2, cy * 2);
  243. ctx.fillStyle = "#ff8";
  244. for (i = -100; i < 100; i += 3) {
  245. for (j = -100; j < 100; j += 4) {
  246. x = i;
  247. z = j;
  248. y = 25;
  249. point = rasterizePoint(x, y, z);
  250. if (point.d != -1) {
  251. size = 250 / (1 + point.d);
  252. d = Math.sqrt(x * x + z * z);
  253. a = 0.75 - Math.pow(d / 100, 6) * 0.75;
  254. if (a > 0) {
  255. ctx.globalAlpha = a;
  256. ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
  257. }
  258. }
  259. }
  260. }
  261. ctx.globalAlpha = 1;
  262. for (i = 0; i < seeds.length; ++i) {
  263. point = rasterizePoint(seeds[i].x, seeds[i].y, seeds[i].z);
  264. if (point.d != -1) {
  265. size = 200 / (1 + point.d);
  266. ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);
  267. }
  268. }
  269. point1 = new Object();
  270. for (i = 0; i < sparks.length; ++i) {
  271. point = rasterizePoint(sparks[i].x, sparks[i].y, sparks[i].z);
  272. if (point.d != -1) {
  273. size = sparks[i].radius * 200 / (1 + point.d);
  274. if (sparks[i].alpha < 0) sparks[i].alpha = 0;
  275. if (sparks[i].trail.length) {
  276. point1.x = point.x;
  277. point1.y = point.y;
  278. switch (sparks[i].img) {
  279. case sparkPics[0]:
  280. ctx.strokeStyle = "#f84";
  281. break;
  282. case sparkPics[1]:
  283. ctx.strokeStyle = "#84f";
  284. break;
  285. case sparkPics[2]:
  286. ctx.strokeStyle = "#8ff";
  287. break;
  288. case sparkPics[3]:
  289. ctx.strokeStyle = "#fff";
  290. break;
  291. case sparkPics[4]:
  292. ctx.strokeStyle = "#4f8";
  293. break;
  294. case sparkPics[5]:
  295. ctx.strokeStyle = "#f44";
  296. break;
  297. case sparkPics[6]:
  298. ctx.strokeStyle = "#f84";
  299. break;
  300. case sparkPics[7]:
  301. ctx.strokeStyle = "#84f";
  302. break;
  303. case sparkPics[8]:
  304. ctx.strokeStyle = "#fff";
  305. break;
  306. case sparkPics[9]:
  307. ctx.strokeStyle = "#44f";
  308. break;
  309. }
  310. for (j = sparks[i].trail.length - 1; j >= 0; --j) {
  311. point2 = rasterizePoint(sparks[i].trail[j].x, sparks[i].trail[j].y, sparks[i].trail[j].z);
  312. if (point2.d != -1) {
  313. ctx.globalAlpha = j / sparks[i].trail.length * sparks[i].alpha / 2;
  314. ctx.beginPath();
  315. ctx.moveTo(point1.x, point1.y);
  316. ctx.lineWidth = 1 + sparks[i].radius * 10 / (sparks[i].trail.length - j) / (1 + point2.d);
  317. ctx.lineTo(point2.x, point2.y);
  318. ctx.stroke();
  319. point1.x = point2.x;
  320. point1.y = point2.y;
  321. }
  322. }
  323. }
  324. ctx.globalAlpha = sparks[i].alpha;
  325. ctx.drawImage(sparks[i].img, point.x - size / 2, point.y - size / 2, size, size);
  326. }
  327. }
  328. }
  329. function frame() {
  330. if (frames > 100000) {
  331. seedTimer = 0;
  332. frames = 0;
  333. }
  334. frames++;
  335. draw();
  336. doLogic();
  337. requestAnimationFrame(frame);
  338. }
  339. window.addEventListener("resize", () => {
  340. canvas.width = canvas.clientWidth;
  341. canvas.height = canvas.clientHeight;
  342. cx = canvas.width / 2;
  343. cy = canvas.height / 2;
  344. });
  345. initVars();
  346. frame();
  347. </script>
  348. {% endblock %}

💻4.6 models.py模型文件

这里创建了User和Message数据库模型,也就是对应数据库里的两张表。其中第一个模型和登录也是有关联的,都是Flask自带的模块。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/4 20:00
  4. """登录需要的数据库模型(用户表)"""
  5. from werkzeug.security import generate_password_hash, check_password_hash
  6. from flask_login import UserMixin
  7. from app import db
  8. class User(UserMixin, db.Model):
  9. # 第一个参数指定字段类型,后面设置属性
  10. __tablename__ = 'users'
  11. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  12. count = db.Column(db.String(128), nullable=False, unique=True)
  13. password = db.Column(db.String(128), nullable=False)
  14. def __init__(self, count, password):
  15. self.count = count
  16. self.password = password
  17. def set_password(self, password):
  18. self.password = generate_password_hash(password)
  19. def check_password(self, password):
  20. return check_password_hash(self.password, password)
  21. class Message(db.Model):
  22. __tablename__ = 'messages'
  23. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  24. title = db.Column(db.String(128))
  25. text = db.Column(db.TEXT)
  26. created_time = db.Column(db.String(64))
  27. # 关联用户id
  28. user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
  29. user = db.relationship('User', backref='user')
  30. if __name__ == '__main__':
  31. user = User(count='0101', password=2021)
  32. db.session.add(user)
  33. db.session.commit()

🔧4.7 init.py文件

这里完成对整个项目的蓝图的注册,配置信息和初始化数据库。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/3 1:54
  4. """构建app,注册蓝图"""
  5. from flask import Flask
  6. from config import BaseConfig
  7. from flask_login import LoginManager
  8. from flask_sqlalchemy import SQLAlchemy
  9. login_manager = LoginManager()
  10. login_manager.session_protection = 'strong'
  11. login_manager.login_view = 'login'
  12. db = SQLAlchemy()
  13. def register_bp(app):
  14. """
  15. 注册蓝图
  16. :param app:
  17. :return:
  18. """
  19. from .app_login import login as login_blueprint
  20. from .app_photo_wall import photo_wall as photo_wall_blueprint
  21. from .app_isay import isay as isay_blueprint
  22. from .app_togo import togo as togo_blueprint
  23. from .app_fireflower import fireflower as fireflower_blueprint
  24. app.register_blueprint(login_blueprint)
  25. app.register_blueprint(photo_wall_blueprint)
  26. app.register_blueprint(isay_blueprint)
  27. app.register_blueprint(togo_blueprint)
  28. app.register_blueprint(fireflower_blueprint)
  29. def database(app, db):
  30. """
  31. 初始化数据库
  32. :param app:
  33. :return:
  34. """
  35. db.init_app(app)
  36. db.create_all()
  37. db.session.commit()
  38. def create_app():
  39. my_app = Flask(__name__)
  40. with my_app.app_context():
  41. # app注册蓝图
  42. register_bp(my_app)
  43. # app加载配置
  44. my_app.config.from_object(BaseConfig)
  45. # 数据库管理对象
  46. database(my_app, db)
  47. # 用于登录验证
  48. login_manager.init_app(my_app)
  49. login_manager.login_view = 'login.login'
  50. return my_app

😃5 manager.py 启动项目

从app/init.py导入create()函数用于启动,同时设置了错误页面。

  1. # coding: utf-8
  2. # 作者(@Author): Messimeimei
  3. # 创建时间(@Created_time): 2023/1/3 13:50
  4. """启动文件"""
  5. from app import create_app
  6. from flask import render_template, session
  7. app = create_app()
  8. # 404页面
  9. @app.errorhandler(404)
  10. def page_not_found(e):
  11. return render_template('error.html'), 404
  12. # 500页面
  13. @app.errorhandler(500)
  14. def internal_server_error(e):
  15. return render_template('error.html'), 500
  16. if __name__ == '__main__':
  17. app.run(debug=True)

💳6 一些静态文件

下面是要用到的所有静态文件,篇幅原因这里就不全部放出来了,有需要的朋友在评论区扣1我会及时给的。背景图片和照片墙大家可以自己选。


本文转载自: https://blog.csdn.net/weixin_62588253/article/details/129336758
版权归原作者 rchjr 所有, 如有侵权,请联系我们删除。

“用Python Flask为女朋友做一个简单的网站(附可运行的源码)”的评论:

还没有评论