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

news2024/11/19 1:41:51
🌟 所属专栏:献给榕榕
🐔 作者简介: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 = True
    TESTING = False
    VISIT_TIME = 0  # 网站访问次数
    # 数据库配置
    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:这里换成自己的MySQL密码@localhost/personalwebsite"
    SQLALCHEMY_TRACK_MODIFICATIONS = False  # 是否追踪数据库的修改


class ProductionConfig(BaseConfig):
    """生产环境下的配置类"""
    DEBUG = False


class DevelopmentConfig(BaseConfig):
    """开发模式下的配置类"""
    DEBUG = True
    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文件。

# coding:   utf-8
# 作者(@Author):   Messimeimei
# 创建时间(@Created_time): 2023/1/8 23:19

"""登录视图的蓝图"""
from flask import Blueprint

login = 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():
    # 如果请求为post
    if request.method == 'POST':
        count = request.form.get('count')
        password = request.form.get('password')
        repassword = request.form.get('repassword')
        from app import db
        if 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>&nbsp;我们的相册</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>&nbsp;&emsp;想去的地方</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 Blueprint

photo_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 Blueprint

isay = 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 db
    if 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 Blueprint

togo = 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 Blueprint

fireflower = 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><span
                    class="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 db


class 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 = count
        self.password = password

    def 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))
    # 关联用户id
    user_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 SQLAlchemy

login_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_blueprint
    from .app_photo_wall import photo_wall as photo_wall_blueprint
    from .app_isay import isay as isay_blueprint
    from .app_togo import togo as togo_blueprint
    from .app_fireflower import fireflower as fireflower_blueprint
    app.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, session

app = 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'), 500


if __name__ == '__main__':
    app.run(debug=True)

💳6 一些静态文件

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序原生开发功能合集四:复选框组件的封装

本章实现小程序复选框组件的封装,使用check及check-group组件实现复选框,封装数据加载过程,并自动实现数据解析及生成,实现相应方法。   另外还提供小程序开发基础知识讲解课程,包括小程序开发基础知识、组件封装、常用接口组件使用及常用功能实现等内容,具体如下:  …

k-Medoids 聚类系列算法:PAM, CLARA, CLARANS

前言 如果你对这篇文章可感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 kkk-Means 作为一种经典聚类算法&#xff0c;相信大家都比较熟悉&#xff0c;其将簇中所有的点的均值作为簇中心&#xf…

JavaScript- Map、Set、WeakMap、WeakSet、简单模拟Map

文章目录Map常见方法set常见方法WeakMapWeakSet如何实现一个Map?(简单模仿)Map Map是一种键值对的结构 常见方法 Map.prototype.set()Map.prototype.has()Map.prototype.get()Map.prototype.delete() set 常见方法 Set类似于数组&#xff0c;但是里面成员的值都是唯一的…

【Java】Spring MVC程序开发

文章目录Spring MVC程序开发1. 什么是Spring MVC&#xff1f;1.1 MVC定义1.2 MVC 和 Spring MVC 的关系2. 为什么学习Spring MVC&#xff1f;3. 怎么学习Spring MVC&#xff1f;3.1 Spring MVC的创建和连接3.1.1 创建Spring MVC项目3.1.2 RequestMapping 注解介绍3.1.3 Request…

OpenCV实战(12)——图像滤波详解

OpenCV实战&#xff08;12&#xff09;——图像滤波详解0. 前言1. 频域分析2. 低通滤波器3. 图像下采样3.1 使用低通滤波器下采样图像3.2 内插像素值4. 中值滤波器5. 完整代码小结系列链接0. 前言 滤波是信号和图像处理中的基本任务之一&#xff0c;其旨在有选择地提取图像的某…

【Linux】CentOS7操作系统安装nginx实战(多种方法,超详细)

文章目录前言一. 实验环境二. 使用yum安装nginx2.1 添加yum源2.1.1 使用官网提供的源地址&#xff08;方法一&#xff09;2.1.2 使用epel的方式进行安装&#xff08;方法二&#xff09;2.2 开始安装nginx2.3 启动并进行测试2.4 其他的一些用法&#xff1a;三. 编译方式安装ngin…

Angular快速入门

Angular1.框架背景2.Angular CLI2.1 安装2.2 主要特性2.3 创建module&#xff0c;component&#xff0c;service&#xff0c;class3.架构3.1 模块3.2 组件3.2.1 创建组件3.2.2 组件生命周期3.2.3 组件交互3.3 模板3.3.1 插值语法3.3.2 属性绑定3.3.3 条件判断3.3.4 循环语句3.3…

22. linux系统基础

递归遍历指定文件下所有的文件&#xff0c;而且你还可以统计一下普通文件的总个数&#xff0c;既然能统计普通文件&#xff0c;能统计其他文件吗&#xff1f;比如目录文件&#xff0c; 这个是main函数里面我们调用了 &#xff0c;这个checkdird这个函数&#xff0c;需要传递一个…

垃圾收集器以及三色标记

分代收集理论当前虚拟机的垃圾收集采用分代收集算法&#xff0c;只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适的垃圾收集算法新生代:每次收集都会有大量对象(近99%)死去&#xff0c;所以可…

教资教育知识与能力中学教学

目录 3.1 教学概述 3.2 教学过程 3.3 教学原则*【简答/辨析重点】 3.4 教学方法 3.5 教学组织形式 3.6 教学工作基本环节 3.7 教学评价 3.1 教学概述 1、教学的意义【14/18辨析】 教学是传授系统知识、促进学生发展的最有效形式&#xff1b; 教学是学校进行全面发展教…

MSTP多域实验配置

目录 实验配置 配置MSTP MSTP参数修改 查看每个设备的生成树 配置MSTP安全 实验配置 放行相关Vlan MST1域内的交换机互联接口放行Vlan 30、40 MST2域内的交换机互联接口放行Vlan 10、20、40 MST1域和MST2域之间交换机互联端口放行Vlan 40 配置MSTP 全网交换机都开启MSTP&a…

【SpringMVC】springMVC介绍

参考资料 视频资料 03_尚硅谷_SpringMVC_SpringMVC简介_哔哩哔哩_bilibili 笔记资料 第一节 SpringMVC概述 (wolai.com)链接&#xff1a;https://pan.baidu.com/s/1A7BX2TNfbGTpYene4x3Mew 提取码&#xff1a;a8d5 一、SpringMVC简介 1、什么是MVC MVC是一种软件架构的思…

React(五):受控组件、高阶组件、Portals、Fragment、CSS的编写方式

React&#xff08;五&#xff09;一、受控组件1.什么是受控组件&#xff08;v-model&#xff09;2.收集表单数据:input和单选框3.收集表单数据:下拉框二、非受控组件三、高阶组件1.什么是高阶组件2.高阶组件的应用13.高阶组件的应用2-注入Context4.高阶组件的应用3-登录鉴权5.高…

十一、GoF之代理模式

1 对代理模式的理解 【在程序中&#xff0c;对象A和对象B无法直接交互时。】 【在程序中&#xff0c;功能需要增强时。】 【在程序中&#xff0c;目标需要被保护时】 业务场景&#xff1a;系统中有A、B、C三个模块&#xff0c;使用这些模块的前提是需要用户登录&#xff0c;也…

HTML的表单标签

&#x1f31f;所属专栏&#xff1a;HTML只因变凤凰之路&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该系列将持续更新HTML的相关学习笔记&#xff0c;欢迎和我一样的小白订阅&#xff0c;一起学习共同进步~&#x1f449;文章简…

将对象或数组存在 dom元素的属性上,最后取不到完整数据,只取到 [{

目录 一、问题 二、问题及解决方法 三、总结 一、问题 1.我需要在dom元素里面添加了一个属性test存一个对象数组temp&#xff0c;以便我下一次找到这个dom元素时可以直接拿到属性里面的数据来渲染页面。 2.dom 属性上存 对象和数组&#xff0c;必须先JSON.stringify(arr),转…

开发手册——一、编程规约_8.注释规约

这篇文章主要梳理了在java的实际开发过程中的编程规范问题。本篇文章主要借鉴于《阿里巴巴java开发手册终极版》 下面我们一起来看一下吧。 1. 【强制】类、类属性、类方法的注释必须使用 Javadoc 规范&#xff0c;使用 /**内容*/ 格式&#xff0c;不得使用 // xxx 方式。 说…

C++ 线程库

文章目录thread 创建mutexmutexrecursive_mutextimed_mutexlock_guard原子操作atomic条件变量condition_variable其他线程安全问题shared_ptr单例模式C 线程库是 C11 标准中引入的一个特性&#xff0c;它使得 C 在语言级别上支持多线程编程&#xff0c;不需要依赖第三方库或操作…

unity开发知识点小结01

unity对象生命周期函数 Awake():最早调用&#xff0c;所以可以实现单例模式 OnEnable&#xff08;&#xff09;&#xff1a;组件激活后调用&#xff0c;在Awake后调用一次 Stat&#xff08;&#xff09;&#xff1a;在Update&#xff08;&#xff09;之前&#xff0c;OnEnable…

【C++知识点】位运算

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;C/C知识点 &#x1f4e3;专栏定位&#xff1a;整理一下 C 相关的知识点&#xff0c;供大家学习参考~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;…