基于Python Mysql Html5的用户注册,帖子发布

本文介绍了基于VSCode平台使用Flask构建的后端服务器项目,详细阐述了部署模块,包括blueprints蓝图、migrations目录、静态文件、模板、app.py、config.py等关键文件及其作用。代码实现部分涉及app.py、config.py、装饰器、数据库模型等,实现了用户注册、登录、问答发布等功能。同时,文章提到了使用Flask-SQLAlchemy存储用户信息、Flask-Mail发送邮箱验证码以及WTForms进行表单验证。最后展示了登录页面,并提供了项目成果的阿里云盘链接。

目录

一、部署模块

1、blueprints蓝图目录 

2、migrations目录

3、static目录 -- 静态文件默认文件夹

4、templates目录 -- html文件默认文件夹

5、 app.py文件

6、config.py文件 -- 配置文件

7、decorators.py -- 装饰器文件

8、exts.py -- 第三方插件

9、models.py -- 数据表文件

二、代码实现

1、app.py 

2、config.py -- 配置文件

 3、decorators.py -- 装饰器文件

 4、exts.py

5、models.py -- 数据库表单文件

 三、templates静态文件

1、base.html  -- 模板通用文件

 2、register.html -- 注册目录

四、成果展示

​登录页面 

五、总结

阿里云盘


前言:本项目基于vscode平台,使用flask搭建后端服务器,html,css,js编写前端用户登录以及问答发布页面,flask_sqlalchemy存储用户登录信息,flask_mail用于发送邮箱验证码进行用户注册,wtforms.validators进行登录注册等表单验证。最后实现用户注册,登录,发布问答,评论等功能,下面是一些具体部署和代码。

一、部署模块

这一部分主要介绍,该项目下有哪些文件,为什么需要这样部署文件,以及各个文件具体实现的功能。 

文件结构如图:

1、blueprints蓝图目录 

blueprints目录下存放模块化的路由文件,方便阅读以及后期维护,主要文件:

1)auth.py

存放用户登录注册的相关路由

2)qa.py

存放用户问答相关的路由

3)forms.py

验证表单,存放前两个文件中验证所需要的独立的类。验证的对象:

a.用户注册的用户名,邮箱等的格式是否符合类中规定的

b.用户注册验证码是否正确

2、migrations目录

用于存放数据库相关配置文件,刚修改models.py中的数据表单时,需要手动在终端执行

映射,映射三部曲如下:

1)flask db init 只需要在终端执行一次--生成一个文件夹,即migrations

2)flask db migrate  识别ORM模型,生成迁移脚本

3)flask db upgrade 运行迁移脚本,同步到数据库中

注:

每修改一次数据表的格式都需要手动执行后面两个代码

在数据库中会自动生成一个alembic_version库,用来记录迁移脚本版本号

3、static目录 -- 静态文件默认文件夹

用于存放css,js,图片等文件

4、templates目录 -- html文件默认文件夹

包括用户注册,登录,发布问答,发布评论的静态页面的书写。

5、 app.py文件

搭建服务器框架, 主执行文件

6、config.py文件 -- 配置文件

一般只需要写一次,配置文件,配置各种加密文件,服务器地址等等

1)mysql配置

2)email配置

7、decorators.py -- 装饰器文件

装饰器,验证用户是否登录,登陆了可以发布问答,反之跳转到登录页面

8、exts.py -- 第三方插件

放置一些可能会造成循环引用的代码,避免循环引用

9、models.py -- 数据表文件

创建数据库表单类,方便管理用户数据

总结:以上就是第一部分的模块部署,虽然前期部署花费了很长时间,但很显然,对于后期书写这很有必要,因为项目所需要的代码繁多,每一模块都有各自的作用,实现哪一方面的功能就去对应的目录文件下修改即可,会在无形中省下很多功夫。

二、代码实现

1、app.py 

from flask import Flask, session, g     # g 存储全部变量
from exts import db,mail
from models import UserModel         # 导入模型
from blueprints.qa import bp as qes_bp # 导入蓝图对象
from blueprints.auth import bp as auth_bp
from flask_migrate import Migrate       # 用于映射
import config

app = Flask(__name__)
app.debug = True

# 绑定配置文件
app.config.from_object(config)

# 绑定app
db.init_app(app)
mail.init_app(app)

# 映射关系
migrate = Migrate(app,db)

# 注册蓝图,绑定
app.register_blueprint(qes_bp)
app.register_blueprint(auth_bp)


@app.before_request # 钩子函数,在请求之前
def my_before():
    user_id = session.get("user_id")
    # 登录之后才有user_id
    if user_id:
        user = UserModel.query.get(user_id)
        # 给g设置一个属性user,user上的值就是user
        setattr(g,'user',user)
    else:   # 没有user_id,设置None,防止报错
        setattr(g,'user',None)

# 上下文处理器,在所有模板当中都可访问其中的数据,user == g.user
@app.context_processor
def my_context_processor():
    return {"user":g.user}

if __name__ == '__main__':
    app.run('0.0.0.0',9527)

2、config.py -- 配置文件

mysql配置文件,需要修改,密码和自己建立的数据库名称

email配置文件,需要修改邮箱地址,邮箱授权密码,如何获取,往后看

SECRET_KEY = 'ndcinsidniveviniewos'

#encoding:utf8
USERNAME = 'root'       # 账号
PASSWORD = ''     # 密码,需要填写你自己的数据库密码
HOST = '127.0.0.1'  # 服务器地址
PORT = '3306'           # 默认端口号
DATABASE = ''   # 使用的数据库,需要填写你自己的数据库名称
# 准备创建数据库连接实例,其中mysql和pymysql必须为小写形式
DB_URI = "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4".format(USERNAME,PASSWORD,HOST,PORT,DATABASE)
# 创建数据连接实例
SQLALCHEMY_DATABASE_URI = DB_URI    

# 动态追踪必须设置,否则会报错,False或者True
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 查询时会显示原始的SQL语句
# SQLALCHEMY_ECHO = True


# QQ邮箱配置密码 
# 邮箱配置--开启了自己的邮箱
MAIL_SERVER = "smtp.qq.com"
MAIL_USE_SSL = True # 是否加密
MAIL_PORT = 465
MAIL_USERNAME = ""    # 邮箱
MAIL_PASSWORD = ""    # 邮箱密码
MAIL_DEFAULT_SENDER = ""    # 同MAIL_USERNAME

如何获取邮箱密码,完成配置,使自己的邮箱可以作为邮箱服务器,完成这个项目:

1、打开qq邮箱,点击设置进入


 
 2、切换到账户

 3、开启下面的这个服务,获得的授权码就是password,我这里是已经开启了的

 3、decorators.py -- 装饰器文件

from functools import wraps
from flask import g, redirect, url_for

# 装饰器,验证用户是否登录,登陆了可以发布问答,反之跳转到登录页面
def login_required(func):
    # 保留func的信息,也就是传过来的public_question函数的信息,使得最后返回inner不会改变原函数
    @wraps(func)
    def inner(*args,**kwargs):
        if g.user:
            return func(*args,**kwargs)
        else:
            return redirect(url_for("auth.login"))
    return inner

 4、exts.py

from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail
  

db = SQLAlchemy()
mail = Mail()

5、models.py -- 数据库表单文件

from datetime import datetime
from exts import db

class UserModel(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(100),nullable=False)
    password = db.Column(db.String(200),nullable=False)
    email = db.Column(db.String(100),nullable=False,unique=True)
    # default制定了一个默认值,关联一个函数,获取当时创建的时间
    join_time = db.Column(db.DateTime,default=datetime.now)


class EmailCaptchaModel(db.Model):
    __tablename__ = "email_captcha"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    email = db.Column(db.String(100),nullable=False)
    # default制定了一个默认值,关联一个函数,获取当时创建的时间
    captcha = db.Column(db.String(100),nullable=False)

# 创建问题表单
class QuestionModel(db.Model):
    __tablename__ = "question"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    content = db.Column(db.Text,nullable=True)
    create_time = db.Column(db.DateTime,default=datetime.now)

    # 外键
    author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
    # 添加一个反向引用,back
    author = db.relationship(UserModel,backref = "questions")

# 创建评论表单
class AnswerModel(db.Model):
    __tablename__ = "answer"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    content = db.Column(db.Text,nullable=True)
    create_time = db.Column(db.DateTime,default=datetime.now)

    # 外键
    question_id = db.Column(db.Integer,db.ForeignKey("question.id"))
    author_id = db.Column(db.Integer,db.ForeignKey("user.id"))

    # 关系,添加反向引用,并排序,新发的评论显示在上面
    question = db.relationship(QuestionModel,backref=db.backref("answers",order_by=create_time.desc()))
    author = db.relationship(UserModel,backref="answers")

 三、templates静态文件

templates文件夹中配置html静态文件,使用base.html作为基础模板,将所有代码公用部分写在其中,其他的html文件使用block继承公用的,在编程自己特有的,这样代码看起来也更灵活清楚。这里作为示例,有如下base.html与register.html代码。

1、base.html  -- 模板通用文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{{ url_for('static',filename='bootstrap/bootstrap.4.6.min.css')}}">
    <link rel="stylesheet" href="{{ url_for('static',filename='css/init.css')}}">
    {% block head %}{% endblock %}
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container">
            <a class="navbar-brand" href="#">知了问答</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="/">首页 <span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('qa.public_question') }}">发布问答</a>
                    </li>
                    <li class="nav-item ml-2">
                        <form class="form-inline my-2 my-lg-0" method="GET" action="{{ url_for('qa.search') }}">
                            <input class="form-control mr-sm-2" type="search" placeholder="关键字" aria-label="Search" name="q">
                            <button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button>
                        </form>
                    </li>
                </ul>
                <ul class="navbar-nav">
                    {% if user %}
                        <li class="nav-item">
                            <span class="nav-link">{{ user.username }}</span>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for("auth.logout") }}">退出登录</a>
                        </li>
                    {% else %}
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for("auth.login") }}">登录</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="{{ url_for("auth.register") }}">注册</a>
                        </li>
                    {% endif %}
                    
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        {% block body %}{% endblock %}
    </div>
</body>
</html>

 2、register.html -- 注册目录

{% extends "base.html" %}

{% block title %}知了传课-注册{% endblock %}

{% block head %}
<script src="{{ url_for('static',filename='jquery/jquery.3.6.min.js')}}"></script>
<script src="{{ url_for('static',filename='js/register.js') }}"></script>
{% endblock %}

{% block body %}
<div class="row mt-4">
    <div class="col"></div>
    <div class="col">
        <form method="POST">
            <div class="form-group">
                <label for="exampleInputEmail1">邮箱</label>
                <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="email">
                <small id="emailHelp" class="form-text text-muted">我们不会把邮箱用于其他用户</small>
            </div>
            <div class="form-group">
                <label for="exampleInputEmail1">验证码</label>
                <div class="input-group">
                    <input type="text" class="form-control" name="captcha">
                    <div class="input-group-append">
                        <button class="btn btn-outline-secondary" type="button" id="captcha-btn">获取验证码</button>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <label for="exampleInputEmail1">用户名</label>
                <input type="text" class="form-control" name="username">
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">密码</label>
                <input type="password" class="form-control" id="exampleInputPassword1" name="password">
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">确认密码</label>
                <input type="password" class="form-control" name="password_confirm">
            </div>
            <button type="submit" class="btn btn-primary btn-block">立即注册</button>
        </form>
    </div>
    <div class="col"></div>
</div>
{% endblock %}

四、成果展示

  

五、总结

作为新手项目,这个项目还有难度的,其中涉及到的知识点很多,要一一去了解很难。下面是整个项目的阿里云盘代码链接。因为还需要配置很多东西,即使有了完整代码也运行不了,还需要自己去修改配置文件config.py。还有更多问题,大家可以留言讨论。如果发现代码有什么问题,希望不吝指出,一起加油!

阿里云盘

MySQL02 https://www.aliyundrive.com/s/W1rNYemLqQo 提取码: 03vw 点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城南邶风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值