用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要用的一些相关信息,比较简单。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/3 15:08"""各种配置类"""class BaseConfig(object):"""所有配置类的基类"""SECRET_KEY = "LOVE"DEBUG = TrueTESTING = FalseVISIT_TIME = 0 # 网站访问次数# 数据库配置SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:这里换成自己的MySQL密码@localhost/personalwebsite"SQLALCHEMY_TRACK_MODIFICATIONS = False # 是否追踪数据库的修改class ProductionConfig(BaseConfig):"""生产环境下的配置类"""DEBUG = Falseclass DevelopmentConfig(BaseConfig):"""开发模式下的配置类"""DEBUG = TrueTESTING = 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文件。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/8 23:19"""登录视图的蓝图"""
from flask import Blueprintlogin = Blueprint("login", __name__)
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的时候会看得到。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/6 11:39"""登录的视图函数"""
from flask import request, render_template, redirect, url_for, flash
from flask_login import login_required, login_user, logout_user
from . import login
from app.models import User
from app import login_manager@login_manager.user_loader
def load_user(user_id): # 创建用户加载回调函数,接受用户 ID 作为参数user = User.query.get(int(user_id)) # 用 ID 作为 User 模型的主键查询对应的用户return user # 返回用户对象@login.route('/index', methods=['GET', 'POST'])
@login_required
def index():return render_template('index.html')@login.route('/register', methods=['GET', 'POST'])
def register():# 如果请求为postif request.method == 'POST':count = request.form.get('count')password = request.form.get('password')repassword = request.form.get('repassword')from app import dbif password == repassword:user = User(count, password)user.set_password(password)db.session.add(user)db.session.commit()return redirect(url_for("login.login_"))else:flash("两次密码不一致!")return render_template("register.html")return render_template('register.html')@login.route('/', methods=['GET', 'POST'])
@login.route('/login', methods=['GET', 'POST'])
def login_():if request.method == 'POST':count = request.form['count']password = request.form['password']if not count or not password:flash('请输入账号和密码!')return redirect(url_for('login.login_'))user = User.query.filter_by(count=count).first()if not user:flash("用户不存在")return redirect(url_for('login.login_'))if count == user.count and user.check_password(password):login_user(user) # 登入用户return redirect(url_for('login.index')) # 重定向到主页flash('账号或密码不正确, 请重新登录!') # 如果验证失败,显示错误消息return redirect(url_for('login.login_')) # 重定向回登录页面return render_template('login.html')@login.route('/logout', methods=['GET','POST'])
@login_required
def logout():logout_user()return redirect(url_for('login.login_'))
导入需要的模块和函数后,用login_manager作为修饰器管理用户登录,具体就是从数据库中查询信息判断是否存在用户,可以看其他博客了解详情。然后是分别用对应的修饰器修饰主页、注册页面、登录页面和注销页面。
下面给出要用到的前端文件
index.html
{% extends 'base.html' %}
{% block title %}主页
{% endblock %}{% block div %}
<div class="wenzi_a"><img src="../static/images/background_images/照片墙.png" style="height: 50px; width: 50px"><span><font size="4" color=#000000><b> 我们的相册</b></font></span><div class="wenzi_font"><font size="3"><b>举目望向天空,有说不尽的美好。<br/>夏天来临之前,温暖洒满了一地。<br/>轻轻翻阅发黄的书卷,斑驳往事。<br/>抓住午后跳跃的阳光,锁住流年。<br/>到底是怎样一种繁华创造了永恒?<br/>夏日的夕阳将天空染成了橘色。<br/>我们走过的路上,落满一地的幸福。<br/></b></font></div>
</div>
<div class="wenzi_b"><img src="../static/images/background_images/爱心.png"><span><font size="4" color=#000000><b>我与你</b></font></span><div class="wenzi_font"><font size="3"><b>时光的洪流把每个人的生命印刻成一<br/>枚枚底片。记忆沿着掌心的脉络聚成<br/>一幅幅永恒的画面。这些光怪陆离的<br/>记忆中最令我怀念的就是,最美的你<br/>陪我走过最绚烂的年华。<br/></b></font></div>
</div>
<div class="wenzi_c"><img src="../static/images/background_images/消息.png"><span><font size="4" color=#000000><b>我想说</b></font></span><div class="wenzi_font"><font size="3"><b>呯呯的心跳却总能代表我的情意。<br/>想说爱你其实真的很遥远,傍山 <br/>涉水地追求,可能才是我的目的。<br/>想说爱你只是想真心对待你,<br/>想说爱你只是想真实地表达自己。<br/></b></font></div>
</div>
<div class="wenzi_d"><img src="../static/images/background_images/走.png"><span><font size="4" color=#000000><b>  想去的地方</b></font></span><div class="wenzi_font"><font size="3"><b>前面以上的文字均来自百度, <br/>原谅我即时在这种特殊的日子 <br/>也说不出来一句“像样的”言语。<br/>我平时已经说的够多了,为了 <br/>让记忆永存,我自学了网页语 <br/>言编写了这个网站。制作过程 <br/>过程费尽心血和精力,但一切 <br/>都是得的。<br/></b></font></div>
</div>
{% endblock %}
register.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" type="text/css" href="../static/css/login.css"/><script src="../static/js/register.js" type="text/javascript"></script></head>
<body>
<div class="login-box"><h2>注册</h2><p class="tip">{% for item in get_flashed_messages() %}{{ item }}{% endfor %}</p><form action="/register" method="post"><div class="login-field"><span style="color: aqua; size: 12px">账号</span><input type="text" name="count" required=""/></div><div class="login-field"><spqn style="color: aqua; size: 12px">密码</spqn><input type="password" name="password" required=""/></div><div class="login-field"><spqn style="color: aqua; size: 12px">确认密码</spqn><input type="password" name="repassword" required=""/></div><input type="submit" value="提交" id="myloginlabel"><p style="color: rgba(194,108,108,0.58)">已有账号?<a href="./login" style="color: rgba(22,180,166,0.58)"onclick="topggleForm();">登录</a></p></form>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>榕城与佳人</title><link rel="stylesheet" type="text/css" href="../static/css/login.css"/><script src="../static/js/register.js" type="text/javascript"></script><link rel="shortcut icon" href="../static/images/ico_images/wjr.ico"></head>
<body>
<div class="login-box"><h2 style="color: #ce8483; font-family: 华文彩云">榕城佳人</h2><p class="tip">{% for item in get_flashed_messages() %}{{ item }}{% endfor %}</p><form action="/login" method="post"><div class="login-field"><span style="color: aqua; size: 12px">账号</span><input type="text" name="count" required=""/></div><div class="login-field"><spqn style="color: aqua; size: 12px">密码</spqn><input type="password" name="password" required=""/></div><input type="submit" value="点击进入" id="myloginlabel"><p style="color: rgba(222,112,112,0.58)">没有账号?<a href="./register" style="color: rgba(22,180,166,0.58)"onclick="topggleForm();">注册</a></p></form>
</div>
</body>
</html>
当然其他的css文件,图片等后面会一并给出。
📟4.2 照片墙功能
照片墙功能在app_photo_wall包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/13 16:10"""照片墙的蓝图"""
from flask import Blueprintphoto_wall = Blueprint("photo_wall", __name__)
from . import view
在app_photo_wall/__init__.py文件中我创建了一个照片墙视图的蓝图。接下来看照片墙的视图文件
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/13 16:20"""照片墙的视图函数"""
from flask import render_template
from flask_login import login_required
from . import photo_wall@photo_wall.route('/photo_wall', methods=['GET', 'POST'])
@login_required
def index():return render_template('photo_wall.html')
照片墙后端很简单,主要是靠前端实现的,下面给出前端代码
photo_wall.html
当然大家可以换成自己想换的照片。
{% extends "base.html" %}
{% block title %}照片墙
{% endblock %}{% block div %}<div id="div2"><div id="photo_box"><img src="../static/images/photo_wall_images/wjr%20(1).jpg"><img src="../static/images/photo_wall_images/wjr%20(2).jpg"><img src="../static/images/photo_wall_images/wjr%20(3).jpg"><img src="../static/images/photo_wall_images/wjr%20(4).jpg"><img src="../static/images/photo_wall_images/wjr%20(5).jpg"><img src="../static/images/photo_wall_images/wjr%20(6).jpg"><img src="../static/images/photo_wall_images/wjr%20(7).jpg"><img src="../static/images/photo_wall_images/wjr%20(8).jpg"><img src="../static/images/photo_wall_images/wjr%20(9).jpg"><img src="../static/images/photo_wall_images/wjr%20(10).jpg"><img src="../static/images/photo_wall_images/wjr%20(11).jpg"><img src="../static/images/photo_wall_images/wjr%20(12).jpg"><img src="../static/images/photo_wall_images/wjr%20(13).jpg"><img src="../static/images/photo_wall_images/wjr_%20(1).jpg"><img src="../static/images/photo_wall_images/wjr_%20(2).jpg"><img src="../static/images/photo_wall_images/wjr_%20(3).jpg"><img src="../static/images/photo_wall_images/wjr_%20(4).jpg"><img src="../static/images/photo_wall_images/wjr_%20(5).jpg"><img src="../static/images/photo_wall_images/wjr_%20(6).jpg"><img src="../static/images/photo_wall_images/wjr_%20(7).jpg"></div></div>
{% endblock %}
😛4.3 我说功能
我说功能在app_isay包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/22 8:52""""""
from flask import Blueprintisay = Blueprint("isay", __name__)
from . import view
在app_isay/__init__.py文件中我创建了一个我说视图的蓝图。接下来看我说功能的视图文件
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/22 8:52"""我说的视图函数"""
import time
from . import isay
from flask import request, render_template, session
from flask_login import login_required
from app.models import User, Message@isay.route('/isay', methods=['GET', 'POST'])
@login_required
def isay():from app import dbif request.method == 'POST':return render_template('isay.html')if request.method == 'POST':title = request.form.get("title")text = request.form.get("text")count = session.get('count')print(count)# 获取当前系统时间created_time = time.strftime("%Y-%m-%d %H:%M:%S")user = User.query.filter_by(count=count).first()message = Message(title=title, text=text, created_time=created_time, user_id=user.id)db.session.add(message)db.session.commit()blog = Message.query.filter(Message.created_time == created_time).first()return render_template('blogSuccess.html', title=title, id=message.id)
这个功能其实没开发好,大家可以不用管它或者自行完善也行。
✈4.4 想去的地方功能
想去的地方功能在app_togo包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/23 11:34""""""
from flask import Blueprinttogo = Blueprint("togo", __name__)
from . import view
在app_togo/__init__.py文件中我创建了一个想去的地方视图的蓝图。接下来看看想去的地方功能的视图文件
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/23 11:35"""想去的地方"""
from . import togo
from flask import render_template@togo.route("/togo", methods=['POST', 'GET'])
def togo():return render_template("togo.html")
这个功能主要是在前端导入了谷歌地图的API,下面给出前端页面
togo.html
{% extends "base.html" %}{% block div %}<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"width="800" height="600" class="map" allowfullscreen="" loading="lazy"referrerpolicy="no-referrer-when-downgrade"></iframe>
{% endblock %}
💥4.5 浪漫烟花功能
浪漫烟花功能在app_fireflower包中,里面一共两个文件,分别是__init__.py和view.py视图文件。先看__init__.py文件。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/2/11 20:48""""""
from flask import Blueprintfireflower = Blueprint("fireflower", __name__)
from . import view
在app_fireflower/__init__.py文件中我创建了一个浪漫烟花视图的蓝图。接下来看看浪漫烟花功能的视图文件
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/2/11 20:48""""""
from flask import render_template
from flask_login import login_required
from . import fireflower@fireflower.route('/fireflower', methods=['GET', 'POST'])
@login_required
def index():return render_template('romanticFireFlower.html')
这个功能主要是在前端实现的,下面给出前端页面
romanticFireFlower.html
{% extends "base.html" %}{% block title %}浪漫烟花
{% endblock %}{% block div %}<style>html, body {width: 100%;height: 100%;overflow: hidden;background: rgba(15, 23, 22, 0.8);}</style>
{# <form action="/fireflower" method="post"></form>#}<audio autoplay="autoplay" loop="loop" preload="auto"src="../static/music/Because%20of%20You.mp3"></audio><canvas id="canvas" style="position:relative;width:1500px;height:800px;z-index:9999;top: 100px"></canvas><canvas style="position:absolute;width:100%;height:100%;z-index:9999" class="canvas"></canvas><div class="overlay"><div class="tabs"><div class="tabs-labels"><span class="tabs-label">Commands</span><span class="tabs-label">Info</span><spanclass="tabs-label">Share</span></div><div class="tabs-panels"><ul class="tabs-panel commands"></ul></div></div></div><script>function initVars() {pi = Math.PI;ctx = canvas.getContext("2d");canvas.width = canvas.clientWidth;canvas.height = canvas.clientHeight;cx = canvas.width / 2;cy = canvas.height / 2;playerZ = -25;playerX = playerY = playerVX = playerVY = playerVZ = pitch = yaw = pitchV = yawV = 0;scale = 600;seedTimer = 0;seedInterval = 5, seedLife = 100;gravity = .02;seeds = new Array();sparkPics = new Array();s = "https://cantelope.org/NYE/";for (i = 1; i <= 10; ++i) {sparkPic = new Image();sparkPic.src = s + "spark" + i + ".png";sparkPics.push(sparkPic);}sparks = new Array();pow1 = new Audio(s + "pow1.ogg");pow2 = new Audio(s + "pow2.ogg");pow3 = new Audio(s + "pow3.ogg");pow4 = new Audio(s + "pow4.ogg");frames = 0;}function rasterizePoint(x, y, z) {var p, d;x -= playerX;y -= playerY;z -= playerZ;p = Math.atan2(x, z);d = Math.sqrt(x * x + z * z);x = Math.sin(p - yaw) * d;z = Math.cos(p - yaw) * d;p = Math.atan2(y, z);d = Math.sqrt(y * y + z * z);y = Math.sin(p - pitch) * d;z = Math.cos(p - pitch) * d;var rx1 = -1000, ry1 = 1, rx2 = 1000, ry2 = 1, rx3 = 0, ry3 = 0, rx4 = x, ry4 = z,uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);if (!uc) return {x: 0, y: 0, d: -1};var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;if (!z) z = .000000001;if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {return {x: cx + (rx1 + ua * (rx2 - rx1)) * scale,y: cy + y / z * scale,d: Math.sqrt(x * x + y * y + z * z)};} else {return {x: cx + (rx1 + ua * (rx2 - rx1)) * scale,y: cy + y / z * scale,d: -1};}}function spawnSeed() {seed = new Object();seed.x = -50 + Math.random() * 100;seed.y = 25;seed.z = -50 + Math.random() * 100;seed.vx = .1 - Math.random() * .2;seed.vy = -1.5;//*(1+Math.random()/2);seed.vz = .1 - Math.random() * .2;seed.born = frames;seeds.push(seed);}function splode(x, y, z) {t = 5 + parseInt(Math.random() * 150);sparkV = 1 + Math.random() * 2.5;type = parseInt(Math.random() * 3);switch (type) {case 0:pic1 = parseInt(Math.random() * 10);break;case 1:pic1 = parseInt(Math.random() * 10);do {pic2 = parseInt(Math.random() * 10);} while (pic2 == pic1);break;case 2:pic1 = parseInt(Math.random() * 10);do {pic2 = parseInt(Math.random() * 10);} while (pic2 == pic1);do {pic3 = parseInt(Math.random() * 10);} while (pic3 == pic1 || pic3 == pic2);break;}for (m = 1; m < t; ++m) {spark = new Object();spark.x = x;spark.y = y;spark.z = z;p1 = pi * 2 * Math.random();p2 = pi * Math.random();v = sparkV * (1 + Math.random() / 6)spark.vx = Math.sin(p1) * Math.sin(p2) * v;spark.vz = Math.cos(p1) * Math.sin(p2) * v;spark.vy = Math.cos(p2) * v;switch (type) {case 0:spark.img = sparkPics[pic1];break;case 1:spark.img = sparkPics[parseInt(Math.random() * 2) ? pic1 : pic2];break;case 2:switch (parseInt(Math.random() * 3)) {case 0:spark.img = sparkPics[pic1];break;case 1:spark.img = sparkPics[pic2];break;case 2:spark.img = sparkPics[pic3];break;}break;}spark.radius = 25 + Math.random() * 50;spark.alpha = 1;spark.trail = new Array();sparks.push(spark);}switch (parseInt(Math.random() * 4)) {case 0:pow = new Audio(s + "pow1.ogg");break;case 1:pow = new Audio(s + "pow2.ogg");break;case 2:pow = new Audio(s + "pow3.ogg");break;case 3:pow = new Audio(s + "pow4.ogg");break;}d = Math.sqrt((x - playerX) * (x - playerX) + (y - playerY) * (y - playerY) + (z - playerZ) * (z - playerZ));pow.volume = 1.5 / (1 + d / 10);pow.play();}function doLogic() {if (seedTimer < frames) {seedTimer = frames + seedInterval * Math.random() * 10;spawnSeed();}for (i = 0; i < seeds.length; ++i) {seeds[i].vy += gravity;seeds[i].x += seeds[i].vx;seeds[i].y += seeds[i].vy;seeds[i].z += seeds[i].vz;if (frames - seeds[i].born > seedLife) {splode(seeds[i].x, seeds[i].y, seeds[i].z);seeds.splice(i, 1);}}for (i = 0; i < sparks.length; ++i) {if (sparks[i].alpha > 0 && sparks[i].radius > 5) {sparks[i].alpha -= .01;sparks[i].radius /= 1.02;sparks[i].vy += gravity;point = new Object();point.x = sparks[i].x;point.y = sparks[i].y;point.z = sparks[i].z;if (sparks[i].trail.length) {x = sparks[i].trail[sparks[i].trail.length - 1].x;y = sparks[i].trail[sparks[i].trail.length - 1].y;z = sparks[i].trail[sparks[i].trail.length - 1].z;d = ((point.x - x) * (point.x - x) + (point.y - y) * (point.y - y) + (point.z - z) * (point.z - z));if (d > 9) {sparks[i].trail.push(point);}} else {sparks[i].trail.push(point);}if (sparks[i].trail.length > 5) sparks[i].trail.splice(0, 1);sparks[i].x += sparks[i].vx;sparks[i].y += sparks[i].vy;sparks[i].z += sparks[i].vz;sparks[i].vx /= 1.075;sparks[i].vy /= 1.075;sparks[i].vz /= 1.075;} else {sparks.splice(i, 1);}}p = Math.atan2(playerX, playerZ);d = Math.sqrt(playerX * playerX + playerZ * playerZ);d += Math.sin(frames / 80) / 1.25;t = Math.sin(frames / 200) / 40;playerX = Math.sin(p + t) * d;playerZ = Math.cos(p + t) * d;yaw = pi + p + t;}function rgb(col) {var r = parseInt((.5 + Math.sin(col) * .5) * 16);var g = parseInt((.5 + Math.cos(col) * .5) * 16);var b = parseInt((.5 - Math.sin(col) * .5) * 16);return "#" + r.toString(16) + g.toString(16) + b.toString(16);}function draw() {ctx.clearRect(0, 0, cx * 2, cy * 2);ctx.fillStyle = "#ff8";for (i = -100; i < 100; i += 3) {for (j = -100; j < 100; j += 4) {x = i;z = j;y = 25;point = rasterizePoint(x, y, z);if (point.d != -1) {size = 250 / (1 + point.d);d = Math.sqrt(x * x + z * z);a = 0.75 - Math.pow(d / 100, 6) * 0.75;if (a > 0) {ctx.globalAlpha = a;ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);}}}}ctx.globalAlpha = 1;for (i = 0; i < seeds.length; ++i) {point = rasterizePoint(seeds[i].x, seeds[i].y, seeds[i].z);if (point.d != -1) {size = 200 / (1 + point.d);ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size);}}point1 = new Object();for (i = 0; i < sparks.length; ++i) {point = rasterizePoint(sparks[i].x, sparks[i].y, sparks[i].z);if (point.d != -1) {size = sparks[i].radius * 200 / (1 + point.d);if (sparks[i].alpha < 0) sparks[i].alpha = 0;if (sparks[i].trail.length) {point1.x = point.x;point1.y = point.y;switch (sparks[i].img) {case sparkPics[0]:ctx.strokeStyle = "#f84";break;case sparkPics[1]:ctx.strokeStyle = "#84f";break;case sparkPics[2]:ctx.strokeStyle = "#8ff";break;case sparkPics[3]:ctx.strokeStyle = "#fff";break;case sparkPics[4]:ctx.strokeStyle = "#4f8";break;case sparkPics[5]:ctx.strokeStyle = "#f44";break;case sparkPics[6]:ctx.strokeStyle = "#f84";break;case sparkPics[7]:ctx.strokeStyle = "#84f";break;case sparkPics[8]:ctx.strokeStyle = "#fff";break;case sparkPics[9]:ctx.strokeStyle = "#44f";break;}for (j = sparks[i].trail.length - 1; j >= 0; --j) {point2 = rasterizePoint(sparks[i].trail[j].x, sparks[i].trail[j].y, sparks[i].trail[j].z);if (point2.d != -1) {ctx.globalAlpha = j / sparks[i].trail.length * sparks[i].alpha / 2;ctx.beginPath();ctx.moveTo(point1.x, point1.y);ctx.lineWidth = 1 + sparks[i].radius * 10 / (sparks[i].trail.length - j) / (1 + point2.d);ctx.lineTo(point2.x, point2.y);ctx.stroke();point1.x = point2.x;point1.y = point2.y;}}}ctx.globalAlpha = sparks[i].alpha;ctx.drawImage(sparks[i].img, point.x - size / 2, point.y - size / 2, size, size);}}}function frame() {if (frames > 100000) {seedTimer = 0;frames = 0;}frames++;draw();doLogic();requestAnimationFrame(frame);}window.addEventListener("resize", () => {canvas.width = canvas.clientWidth;canvas.height = canvas.clientHeight;cx = canvas.width / 2;cy = canvas.height / 2;});initVars();frame();</script>{% endblock %}
💻4.6 models.py模型文件
这里创建了User和Message数据库模型,也就是对应数据库里的两张表。其中第一个模型和登录也是有关联的,都是Flask自带的模块。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/4 20:00"""登录需要的数据库模型(用户表)"""
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app import dbclass User(UserMixin, db.Model):# 第一个参数指定字段类型,后面设置属性__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True, autoincrement=True)count = db.Column(db.String(128), nullable=False, unique=True)password = db.Column(db.String(128), nullable=False)def __init__(self, count, password):self.count = countself.password = passworddef set_password(self, password):self.password = generate_password_hash(password)def check_password(self, password):return check_password_hash(self.password, password)class Message(db.Model):__tablename__ = 'messages'id = db.Column(db.Integer, primary_key=True, autoincrement=True)title = db.Column(db.String(128))text = db.Column(db.TEXT)created_time = db.Column(db.String(64))# 关联用户iduser_id = db.Column(db.Integer, db.ForeignKey('users.id'))user = db.relationship('User', backref='user')if __name__ == '__main__':user = User(count='0101', password=2021)db.session.add(user)db.session.commit()
🔧4.7 __init__.py文件
这里完成对整个项目的蓝图的注册,配置信息和初始化数据库。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/3 1:54"""构建app,注册蓝图"""from flask import Flask
from config import BaseConfig
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemylogin_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'login'
db = SQLAlchemy()def register_bp(app):"""注册蓝图:param app::return:"""from .app_login import login as login_blueprintfrom .app_photo_wall import photo_wall as photo_wall_blueprintfrom .app_isay import isay as isay_blueprintfrom .app_togo import togo as togo_blueprintfrom .app_fireflower import fireflower as fireflower_blueprintapp.register_blueprint(login_blueprint)app.register_blueprint(photo_wall_blueprint)app.register_blueprint(isay_blueprint)app.register_blueprint(togo_blueprint)app.register_blueprint(fireflower_blueprint)def database(app, db):"""初始化数据库:param app::return:"""db.init_app(app)db.create_all()db.session.commit()def create_app():my_app = Flask(__name__)with my_app.app_context():# app注册蓝图register_bp(my_app)# app加载配置my_app.config.from_object(BaseConfig)# 数据库管理对象database(my_app, db)# 用于登录验证login_manager.init_app(my_app)login_manager.login_view = 'login.login'return my_app
😃5 manager.py 启动项目
从app/__init__.py导入create()函数用于启动,同时设置了错误页面。
# coding: utf-8
# 作者(@Author): Messimeimei
# 创建时间(@Created_time): 2023/1/3 13:50"""启动文件"""
from app import create_app
from flask import render_template, sessionapp = create_app()# 404页面
@app.errorhandler(404)
def page_not_found(e):return render_template('error.html'), 404# 500页面
@app.errorhandler(500)
def internal_server_error(e):return render_template('error.html'), 500if __name__ == '__main__':app.run(debug=True)
💳6 一些静态文件
下面是要用到的所有静态文件,篇幅原因这里就不全部放出来了,有需要的朋友在评论区扣1我会及时给的。背景图片和照片墙大家可以自己选。

相关文章:

用Python Flask为女朋友做一个简单的网站(附可运行的源码)
🌟所属专栏:献给榕榕🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该专栏系为女友准备的,里面会不定时发一些讨好她的技术作品,感兴趣的小伙伴可以关注一下~👉文章简介…...

vue3+rust个人博客建站日记5-所有界面
没有数据的前端,是没有灵魂的。明明标题是vue3 rust ,但日记撰写至今,似乎只有第一篇提及了Rust,这可不行。是时候一股作气,完成大部分页面绘制工作了! 最后再说一次,时间要加速了。 ——普奇神…...

青少年软件编程C++一级真题(202212)
1、输入一个整数x,输出这个整数加1后的值,即x1的值。 时间限制:1000 内存限制:65536 输入 一个整数x(0 ≤ x ≤ 1000)。 输出 按题目要求输出一个整数。 样例输入 9样例输出 10 #include<iost…...

【Spring】AOP底层原理(动态代理)-》 AOP概念及术语 -》 AOP实现
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ AOP - 面向切面编程一、简述AOP二、AOP底层原理…...

Java8 新特性 之 lambda 表达 和 函数式接口
—— lambda 表达式 概念 lambda 表达式是一个匿名函数,可以把 lambda 表达式理解为是一段可以传递的代码。更简洁、更灵活,使 Java 的语言表达能力得到了提升lambda 表达式是作为接口的实现类的对象(万事万物皆对象) 使用语法…...

Netty服务端和客户端开发实例
一、Netty服务端开发在开始使用 Netty 开发 TimeServer 之前,先回顾一下使用 NIO 进行服务端开发的步骤。(1)创建ServerSocketChannel,配置它为非阻塞模式;(2)绑定监听,配置TCP 参数,例如 backlog 大小;(3)创建一个独立的I/O线程&…...

linux基本指令和权限
目录 一.shell命令以及运行原理 二.Linux常用指令 1. ls 指令 2. pwd命令 3.cd指令 4. touch指令 5.mkdir指令(重要) 6.rmdir指令 && rm 指令(重要) 7.man指令(重要) 8.cp指令(重要&…...

滚蛋吧,正则表达式!
大家好,我是良许。 不知道大家有没有被正则表达式支配过的恐惧?看着一行火星文一样的表达式,虽然每一个字符都认识,但放在一起直接就让人蒙圈了~ 你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」&…...

序列号和反序列化--java--Serializable接口--json序列化普通使用
序列化和反序列化序列化和反序列化作用为什么需要用途Serializable使用serialVersionUID不设置的后果什么时候修改Externalizable序列化的顺序json序列化序列化和反序列化 序列化:把对象转换为字节序列的过程称为对象的序列化。 反序列化:把字节序列恢复为对象的过…...

Java异步任务编排
多线程创建的五种方式: 继承Thread类实现runnable接口。实现Callable接口 FutureTask(可以拿到返回结果,阻塞式等待。)线程池创建。 ExcutorService service Excutors.newFixedThreadPool(10); service.excute(new Runnable01());另外一种创建线程池…...

Hive与HBase的区别及应用场景
当数据量达到一定量级的时候,存储和统计计算查询都会遇到问题,今天了解一下Hive和Hbase的区别和应用场景。 一、定义 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能&am…...

C++之单例模式
目录 1. 请设计一个类,只能在堆上创建对象 2. 请设计一个类,只能在栈上创建对象 3.请设计一个类,不能被拷贝 C98 C11 4. 请设计一个类,不能被继承 C98 C11 5. 请设计一个类,只能创建一个对象(单例模式) 设计…...

Redis十大类型——Set与Zset常见操作
Redis十大类型——Set与Zset常见操作Set命令操作简列基本操作展示删除移动剪切集合运算Zset基本操作简列添加展示反转按分数取值获取分数值删除分数操作下标操作如果我们对Java有所了解,相信大家很容易就明白Set,在Redis中也一样,Set的value值…...

车载雷达实战之Firmware内存优化
内存(Memory)是计算机中最重要的部件之一,计算机运时的程序以及数据都依赖它进行存储。内存主要分为随机存储器(RAM),只读存储器(ROM)以及高速缓存(Cache)。仅仅雷达的原…...

【剑指Offer】JZ14--剪绳子
剪绳子详解1.问题描述2.解题思路3.具体实现1.问题描述 2.解题思路 首先想到的思路:因为是求乘积的最大值,所以如果截取剩下的是1,那还是它本身就没有意义。从此出发,考虑绳子长度是2、3、4、5…通过穷举法来找规律。 值–》拆分–…...

raspberry pi播放音视频
文章目录目的QMediaPlayerGStreamerwhat is GStreamer体系框架优势omxplayerwhat is omxplayercommand Linekey bindings运行过程中错误ALSA目的 实现在树莓派下外接扬声器, 播放某段音频, 进行回音测试。 QMediaPlayer 首先我的安装是5.11版本。 优先…...

【电子学会】2022年12月图形化二级 -- 老鹰捉小鸡
老鹰捉小鸡 小鸡正在农场上玩耍,突然从远处飞来一只老鹰,小鸡要快速回到鸡舍中,躲避老鹰的抓捕。 1. 准备工作 (1)删除默认白色背景,添加背景Farm; (2)删除默认角色小…...

C++的双端队列
双端队列介绍1.双端队列知识需知2.大试牛刀1.双端队列知识需知 由于队列是一种先进先出(FIFO)的数据结构,因此无法直接从队列的底部删除元素。如果希望从队列的底部删除元素,可以考虑使用双端队列(deque)。…...

【独家】华为OD机试 - 拼接 URL(C 语言解题)
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

为什么使用Junit单元测试?Junit的详解
Hi I’m Shendi 为什么使用Junit单元测试?Junit的详解 Junit简介 Junit是一个Java语言的单元测试框架。 单元测试是一个对单一实体(类或方法)的测试 JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression test…...

怎么学好嵌入式Linux系统和驱动
嵌入式专业是一门实践性非常强的学科,只有多动手,多实践,多编程,多调试,多看书,多思考才能真正掌握好嵌入式开发技术。 现在很多同学也意识到了学校培养模式和社会需求脱节问题,有一部分同学也先…...

Spring Aware总结
概述 Spring中Aware到底是什么意思? 我们在看Spring源码的时候,经常可以看到xxxAwarexxx的身影,通常我会很疑惑,Aware到底是什么意思呢? 比如图片中这些包含Aware关键字的类或者接口。 我对下面3个类或接口进行了解…...

【RocketMQ】源码详解:Broker端消息刷盘流程
消息刷盘 同步入口:org.apache.rocketmq.store.CommitLog.GroupCommitService 异步入口:org.apache.rocketmq.store.CommitLog.FlushRealTimeService 刷盘有同步和异步两种,在实例化Commitlog的时候,会根据配置创建不同的服务 p…...

编码器SIQ-02FVS3驱动
一.简介 此编码器可以是功能非常强大,可以检测左右转动,和按键按下,所以说这一个编码器可以抵三个按键,而且体积非常小,使用起来比三个按键要高大尚,而且驱动也简单。唯一不足的点就是价格有点小贵6-8元才…...

【2021.9.7】记一次exe手动添加shellcode
【2021.9.7】记一次exe手动添加shellcode 文章目录【2021.9.7】记一次exe手动添加shellcode0.大致思路1.获取MessageBox的真实地址VA2.通过OD在代码段添加shellcode3.dump出数据,设置程序OEP4.测试dump出来的exe5.方法总结测试的exe和添加了shellcode的exe:链接&…...

常用训练tricks,提升你模型的鲁棒性
目录一、对抗训练FGM(Fast Gradient Method): ICLR2017代码实现二、权值平均1.指数移动平均(Exponential Moving Average,EMA)为什么EMA会有效?代码实现2. 随机权值平均(Stochastic Weight Averaging,SWA&a…...

具有精密内部基准的 DACx0502 简介及驱动应用示例
DACx0502 说明 16 位 DAC80502、14 位 DAC70502 和 12 位DAC60502 (DACx0502) 数模转换器 (DAC) 均为具有电压输出的高精度、低功耗器件。 DACx0502 线性度小于 1LSB。凭借高精度和微型封装特性,DACx0502 非常适合以下 应用: 增益和失调电压校准、电流…...

C语言函数:字符串函数及模拟实现strncpy()、strncat()、strncmp()
C语言函数:字符串函数及模拟实现strncpy()、strncat()、strncmp() 在了解strncpy、strncat()、前,需要先了解strcpy()、strncat(): C语言函数:字符串函数及模拟实现strlen() 、strcpy()、 strcat()_srhqwe的博客-CSDN博客 strncp…...

学术论文插图要求简介
1. 类型 位图和矢量图是两种不同的图像类型,它们在存储和处理图像时使用不同的方法。以下是它们之间的详细区别: 图像构成方式:位图使用像素(或图像的最小单元)来构建图像,每个像素都有自己的颜色和亮度值。…...

【独家】华为OD机试 - 斗地主 2(C 语言解题)
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...