flask注册功能

 一个项目的简单结构划分

首先创建一个新项目

 

 可以正常运行与访问

 

 创建配置文件并添加配置。

 

 将这里拆分到不同的文件中,让启动文件更加简洁。

 

 创建一个apps包,导入配置模块,导入Flask,定义创建app函数,返回app对象。实例化的Flask对象做配置,定义模板位置和静态文件位置。添加app config配置,使用来自对象的方法,将配置模块导入到配置中

 

 然后再来写我们的运行程序。导入创建 app函数,创建app,让app点run运行

 我们将路由和视图函数写到views里面,这样启动文件就简洁了。我们将配置文件写到一个模块里面,这样创建好Flask对象之后,不用app.config往后堆很多配置,简洁很多。使用app点config点来自对象,将模块作为参数传入进去。

一个项目:比如分用户 商品 订单
一个项目分很多部分。我们不可能把所有的路由放到一个文件。
比如用户,就可以有
用户中心 /center
用户注册 /register
用户登录 /login
用户更新 /upgrade
一个用户部分就有很多路由。那么我们可以项目的一个部分就用一个蓝图,把路由划分成不同的部分。其实蓝图也是路由的另一种方式。

 

 我们在apps下创建视图模块,里面写一个蓝图。蓝图里写了两个视图函数,

user_for('')调用register,如果有endpoint,返回的是endpoint的值,如果没有,返回的是函数的名,这是反向解析。就是给我个名我去找到路径,而不是给个路径我去找到函数名。正常的是给个路由,我给你找到函数名,现在反过来了,你给我函数名我给你找到路由,这就是url_for反向解析,

 写完蓝图后导入并注册到app中

 注册完了之后就命令行运行app程序并访问

 

 一访问就报错了

 

 因为原来我们是在app上写路由,现在我们用了蓝图了,多了一层,经过蓝图然后写的路由。所以url_for想要反向解析引用函数名,就需要在前面加上蓝图,指定是哪个蓝图下的函数名,然后我们再访问

 

这样就访问到了默认路由根了。

后端打印出 我们根据字符串反向解析出路径。包括在前端进行反向解析的时候,也要这么写,加上蓝图名称

一个项目

我们这里沿用上面的结构做些修改。

我们将路由和视图函数写到views里面,这样启动文件就简洁了。我们将配置文件写到一个模块里面,这样创建好Flask对象之后,不用app.config往后堆很多配置,简洁很多。使用app点config点来自对象,将模块作为参数传入进去。

项目:比如分用户 商品 订单
一个项目分很多部分。我们不可能把所有的路由放到一个文件。
比如用户,就可以有
用户中心 /center
用户注册 /register
用户登录 /login
用户更新 /upgrade
一个用户部分就有很多路由。那么我们可以项目的一个部分就用一个蓝图,把路由划分成不同的部分。其实蓝图也是路由的另一种方式。

我们可以在apps下创建多个目录,用户目录放用户相关的,商品目录放商品相关,放的可以是蓝图等,比如view模块里面定义蓝图。

 

 现在目录结构如下:

我们根据项目的不同的部分划分。这里创建了三个包,我们现在要写跟用户相关的,所以我们写蓝图在user下面的view模块写蓝图。app,配置还有init文件已经按上面那个写好了。现在只需要把蓝图重新写一下。

 

 程序:

from flask import Flask
import settings
from apps.user.view import user_bp

def create_app():
    app=Flask(__name__,template_folder='../templates',static_folder='../static')
    app.config.from_object(settings)
    app.register_blueprint(user_bp)
    print(app.url_map)
    return app
init文件
from flask import Blueprint

user_bp=Blueprint('user',__name__)

@user_bp.route("/")
def user_center():
    return '用户中心'
@user_bp.route('/register',methods=['GET','POST'])
def register():
    return '用户注册'
@user_bp.route('/login',methods=['GET','POST'])
def login():
    return '用户登录'
@user_bp.route('/logout',methods=['GET','POST'])
def logout():
    return '用户注册'

用户下写的蓝图:

现在我们写了四个路由了。这四个路由绑定在蓝图上的,也就是绑定在user蓝图上的。蓝图需要注册到app中,让蓝图和app产生联系。

在apps下的init里面,导入蓝图,在app对象里面注册我们创建的蓝图,我们可以用url_map查看app里的路由,可以看到我们写的四个路由,已经生效了。

 

 我们访问一下看效果:

 

我们需要定义类,用于与数据库交互用的。在用户目录下创建model模块。写入到这个模块中

 

 

现在我们需要写模板了,模板目录创建子目录user,跟用户相关的模板就放到这个目录中。比如我们先创建三个文件,登录,注册和展示用的页面。因为这些页面都有公共的部分。所以我们需要将公共的部分分出来。我们在templates下创建base页面。

母版的写法:
base母版页面的标题也是可能改的,设置成block,默认是用户中心
我们还需要预留我们的css和js。所以母版中再设置css和js块。然后我们创建三个div,分为header center footer.然后定义三者的样式

 

 刚刚的有点问题,右击模板目录,将目录标记为模板目录,使用jinja2语言。这样下面的block就识别出来了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} 用户中心{% endblock %}</title>
    <style>
        #head {
            height: 50px;
            background-color: bisque;
        }

        #head ul {
            list-style: none;
            height: 50px;
        }

        #head ul li {
            float: left;
            width: 100px;
            text-align: center;
            font-size: 18px;
            height: 50px;
            line-height: 50px;
        }

        #middle {
            height: 900px;
            background-color: azure;
        }

        #foot {
            height: 50px;
            line-height: 50px;
            background-color: darkseagreen;
        }
    </style>
    {% block mycss %}{% endblock %}
</head>
<body>
<div id="head">
    <ul>
        <li><a href="">首页</a></li>
        <li><a href="">秒杀</a></li>
        <li><a href="">超市</a></li>
        <li><a href="">图书</a></li>
        <li><a href="">会员</a></li>
    </ul>
</div>
<div id="middle">
    {% block middle %}

    {% endblock %}
</div>
<div id="foot">

</div>

{% block myjs %}{% endblock %}
</body>
</html>
母版文件

母版展示效果如下

我们要写注册页面。我们需要继承母版。修改标题,

{% extends 'base.html' %}
{% block title %}
    用户注册
{% endblock %}

{% block middle %}
    <form action="/register" method="post">
        <p><input type="text" name="username" placeholder="用户名"></p>
        <p><input type="password" name="password" placeholder="密码"></p>
        <p><input type="password" name="repassword" placeholder="确认密码"></p>
        <p><input type="number" name="phone" placeholder="手机号码"></p>
        <p><input type="submit" value="用户注册"></p>
    </form>
{% endblock %}

 

 我们写好前端页面之后。写后端,让注册视图返回这个模板文件看看效果。因为模板目录能找到,文件在子目录中,所以用相对路径就可以找到文件。

 

 效果如下:

 

 我们在创建flask对象的时候,设置了模板文件位置,静态文件位置了。所以flask能找到模板目录。如果在创建flask对象的时候没有设置传参那么就只能把模板目录放到apps下,和init文件同级目录,因为,创建flask对象的时候,内部有默认设置找到创建对象同级目录下的templates目录作为模板目录。同理,我们也要设置一下静态文件目录、。因为我们要将apps和模板目录独立开来,不放到apps下。

 

 接下来我们写post提交数据。点击注册,然后跳转到用户中页面

目前我们的model这个类,可以封装用户的用户名,密码。打印对象会显示用户名。用户数据封装在init方法下面。

 

 用户数据暂时先保存到一个列表中。有一个就追加一个到列表中。将用户类导入进来,创建用户对象,将用户数据封装进对象中。注册后是将用户对象追加到用户对象列表里面了。

 

 

然后看一下用户注册的逻辑。

  • 如果是get请求,那么不走post下面的程序,直接走到最后的一个return,返回一个注册页面可以让浏览器展示出来。
  • 如果我们在from的框框里输入数据,点击用户注册,那么就是发送post请求,走post下面的程序。
  • 这时,第一步就是获取post提交的数据。获取form数据,是request点form里去get数据。form返回的是个啥字典的形式数据集,虽然展示不是字典的样子,但是用get可以获取到指定键的值。
  • 对密码和确认密码做判断,两次密码相等才能继续往下走,然后循环用户对象列表,查询前端提交的用户名字是否存在用户对象列表中中。如果存在就返回注册页面和一个错误信息,错误信息显示是用户名已存在。并将信息渲染在模板中。否则,就是用户不存在,继续往下走,用户不存在就可以创建用户对象了。将前端form数据封装到用户对象里,然后将用户对象追加到用户对象列表存储起来。这就相当于保存到数据库了。
  • 保存数据之后就跳转到用户展示页面。这里是用户中心,也就是"/"

 

 

 

 查看效果

 

 给我们的注册页面添加上错误显示

<p style="color: red">{{ msg }}</p>

 

 

 

 

 目前缺少很多校验

 

 成功跳转到用户中心页面

 

 接下来写用户中心的页面,用户中心页面是展示用的,那么我们也就返回一个展示模板,因为需要展示用户的,那就将users对象列表传进去。传的方法是变量等于用户对象列表。

 

 用户中心展示页面,我们得知道需要展示哪些新喜,标题,当前用户人数等。然后每个人的信息。这里就做个表格,将后端传进来的用户对象列表做循环。然后点取值

 

 如下,我们进入注册页面,注册后跳转到用户信息页面。这样就将信息都展示出来了。用户信息需要修改和删除按钮、。loop.index应该是循环的索引

 

 

 我们应当还需要添加。一般数据展示页面,需要增改删按钮,查已经实现了、。

 现在我们需要删除

 

 删除一条数据,一个用户。我们需要准确的知道是删除那条数据。点击删除按钮或者是链接,就发送请求,让它请求/del删除路径。这样让它找到删除用户操作的删除视图函数。这个功能的实现需要js来配合实现。前端上是添加一个js点击事件,

下面看下如何添加js点击事件。

在删除a标签上添加点击事件函数传一个字符串用户的名字。这里是根据用户名去删除。下面就添加js代码块。定义js语句。定义js函数,函数是点击事件中调用的函数。function 函数名小括号接收点击事件传给函数的参数,然后花括号定义点击事件发生后的行为。这里暂时是打印在控制台。js函数的调用时,给href链接加上Javascript冒号分号,然后后面接事件类型,事件是点击事件=双引号,双引号里面可以放函数的调用。调用的括号里面可以放给函数的传参。传参这里是传的字符串。传的是一个用户名字这个变量。这样,点击谁,就传参是谁,下面的函数可以定位到对那条数据做删除操作。

 

 点击之后成功打印,说明没有问题。后面再改成删除的行动

 

 删除的逻辑应该是如下:

 

 现在当我们点击删除a链接时,不是打印输出在控制台了。是要发送一个请求。我们这里注释掉a标签的请求,使用调用js函数的方式来做请求。做的是个get请求。也就是删除按钮是个点击事件。当点击这个标签时,调用del函数并传参用户名字给函数。js代码块中定义的del函数接收到传参,知道是哪个用户要被删除,函数要做的动作是想/del路径发送get请求,并拼接上用户名,因为这里是根据用户名来删除,将用户名作为get请求的参数传递给后端视图函数。后端视图函数接收到传参后就可以对该数据做操作了。js中location.href等于一个地址,可以使得函数执行时,对该地址发送一个get请求。拼接键值对用问号,键自己指定,值是js函数传参接收过来的用户名。键值对等号拼接

 

 

删除逻辑如下:前端想del发送一个请求,并将用户传到后端了,视图函数中获取get请求中的数据,然后对用户做判断。循环我的用户列表.如果用户对象列表的每个用户名字和前端传递过了的名字相等,那么就将用户从用户对象列表中删除,然后重定向到用户中心页面。如果循环结束之后发现没有匹配到用户,也就没走到重定向这一步,我们可以else否则给它返回一个删除失败。

 

 这下我们点击删除

 

 发现删除成功

注册模板中我们写action地址,我们要访问的是蓝图user下的/register这个路由,但是这个路由也是可能会被修改的。如果被修改了,前端action地址就访问不到了,所以前端不能写死了,我们应该用动态的反向解析的方法去获取到路由地址,从而正确访问到该路由。{{ url_for('user.register') }} 就是通过字符串,能反向解析出路由地址,然后访问路由从而实现向这条路由发起请求。正常来说我们是通过路径找到函数,而我们这里就是通过函数名或endpoint去找到路径,这就是反向解析

 

 

 

 

 

接下来我们要做修改的程序

 

 前端设计:

  • 用户点击修改,进入修改页面。也就是在用户展示页面可以个修改a标签加个点击事件,调用修改函数。修改函数的动作就是给修改路径/update发送一个请求,并将用户名字传递给后端,这里是发送一个get请求 ,get请求修改页面,然后展示修改页面。
  • 修改页面要继承母版,修改标题,修改中间的div信息。修改的表单action,是去请求更新的路径,我们后端写一个路由和视图函数,作为修改使用。
  • form的action,最好写成反向解析,用变量引用的方式,url_for ,传参蓝图点endpoint或者函数名,让它找到访问路径,并发起请求
  • 我们这里的有三个字段,那修改也要有三个字段。这里是通过用户名来识别用户的,没有设置用户id,所以修改提交操作后我们不知用户改的是谁,这种情况下我们可以在修改页面添加一个隐藏标签,备注上它的名字。然后写上用户,密码手机号三个标签,更新按钮。因为是修改,当我们在用户展示页点击修改后,向修改页面发送get请求,让后端将修改页面和修改用户的数据都传递过来。然后我们可以在模板的input框中设置默认值,value.
  • 当点击修改的时候,这里是通过js从用户展示页向修改页面/update发送一个get请求,后端/update的get请求我们可以返回修改页面的模板,因为是修改,所以修改的框中欧应该携带修改用户的原本数据才对。我们刚刚从用户展示页发送请求的时候,将点击的用户的名字通过参数的方式传给点击事件函数,函数接收参数,发送get请求拼接携带上用户的名字。后端get请求逻辑代码中,从get请求里获取到用户名字,通过用户名字遍历用户对象列表,如果有名字相等的用户对象,就将该用户传到修改页面模板中,也就是返回用户模板和用户对象。而模板中有定义使用用户对象去渲染出修改前的原数据信息的。

 

 下面看下展示效果

 

 

 

 接下来就是写/update路由也就是修改页面的post请求了。

 

 

 

修改逻辑 

  • 修改页面当修改完数据需要向修改页面的路由/update发送一个post请求,我们这里的路径是用url_for反向解析,使用蓝图点endpoint去解析出请求路径,然后向路径发起post请求。
  • 前端向/update发起post请求后,后端视图函数走post请求的程序。post请求中有用户提交的数据,在请求点form中,get通过前端name获取对应填写的值。然后遍历用户对象列表,如果用户对象列表中有用户的名字等于隐藏标签的真实名字,也就是未修改前的名字,那么就让用户对象的名字等于新提交的名字,也就是重新赋值,然后让用户对象的其它属性也等于用户新提交的数据,然后给前端展示返回一个更新成功。我们也可以返回一个重定向,重定向到用户展示页面

 

 

 

 

 

 重定向到用户展示页面效果

 

 

 

 

 

 目前的程序day042 05:

class User:
    def __init__(self, username, password, phone=None):
        self.username = username
        self.password = password
        self.phone = phone

    def __str__(self):
        return self.username
model
from flask import Blueprint,request, render_template, redirect
from apps.user.model import User
user_bp=Blueprint('user',__name__)

# 列表保存的是一个一个的用户对象
users = []

@user_bp.route("/")
def user_center():
    return render_template('user/show.html',users=users)
@user_bp.route('/del')
def del_user():
    # 获取你传递的username
    username = request.args.get('username')
    # 根据username找到列表中的user对象
    for user in users:
        if user.username == username:
            # 删除user
            users.remove(user)
            return redirect('/')
    else:
        return '删除失败'
@user_bp.route('/update', methods=['POST', 'GET'], endpoint='update')
def update_user():
    if request.method == 'POST':
        realname = request.form.get('realname')
        username = request.form.get('username')
        password = request.form.get('password')
        phone = request.form.get('phone')
        for user in users:
            if user.username == realname:
                user.username = username
                user.phone = phone
                return redirect('/')

    else:
        # get请求了
        username = request.args.get('username')
        for user in users:
            if user.username == username:
                return render_template('user/update.html', user=user)

@user_bp.route('/register',methods=['GET','POST'])
def register():
    if request.method=='POST':
        # 获取post提交的数据
        print(request.form)
        print(request.form.get('username'))
        username = request.form.get('username')
        password = request.form.get('password')
        phone = request.form.get('phone')
        repassword = request.form.get('repassword')
        if password == repassword:
            # 用户名唯一
            for user in users:
                if user.username == username:
                    return render_template('user/register.html', msg='用户名已存在')
            # 创建user对象
            user = User(username, password, phone)
            # 添加到用户列表
            users.append(user)
            return redirect('/')
    return render_template('user/register.html')
@user_bp.route('/login',methods=['GET','POST'])
def login():
    return '用户登录'
@user_bp.route('/logout',methods=['GET','POST'])
def logout():
    return '用户注册'
view
from flask import Flask
import settings
from apps.user.view import user_bp

def create_app():
    app=Flask(__name__,template_folder='../templates',static_folder='../static')
    app.config.from_object(settings)
    app.register_blueprint(user_bp)
    return app
init
{% extends 'base.html' %}
{% block title %}
    用户注册
{% endblock %}

{% block middle %}
    <p style="color: red">{{ msg }}</p>
    <form action="{{ url_for('user.register') }}" method="post">
        <p><input type="text" name="username" placeholder="用户名"></p>
        <p><input type="password" name="password" placeholder="密码"></p>
        <p><input type="password" name="repassword" placeholder="确认密码"></p>
        <p><input type="number" name="phone" placeholder="手机号码"></p>
        <p><input type="submit" value="用户注册"></p>
    </form>
{% endblock %}
register
{% extends 'base.html' %}
{% block middle %}
    <h1>用户信息</h1>
    <span>当前用户人数是:{{ users |length }} 人</span>
    <table border="1" cellspacing="0" width="60%">
        {% for user in users %}
            <tr>
                <td>{{ loop.index }}</td>
                <td>{{ user.username }}</td>
                <td>{{ user.password }}</td>
                <td>{{ user.phone }}</td>
                <td><a href="javascript:;" onclick="update('{{ user.username }}')" >修改</a>
                    <a href="javascript:;" onclick="del('{{ user.username }}')">删除</a></td>
            </tr>
        {% endfor %}

    </table>
{% endblock %}

{% block myjs %}
    <script>
        function del(username) {
            {#console.log(username)#}
            {#// location 地址栏对象#}
            location.href = '/del?username=' + username
        }
        //修改的函数
        function update(username) {
            location.href = '/update?username=' + username
        }
    </script>
{% endblock %}
用户展示页
{% extends 'base.html' %}
{% block title %}
    用户信息修改
{% endblock %}
{% block middle %}
<h1>用户信息更新</h1>
    <form action="{{ url_for('user.update') }}" method="post">
    <p><input type="hidden" name="realname" value="{{ user.username }}"></p>
    <p><input type="text" name="username" placeholder="用户名" value="{{ user.username }}"></p>
    <p><input type="password" name="password" placeholder="密码" value="{{ user.password }}" disabled></p>
    <p><input type="number" name="phone" placeholder="手机号码" value="{{ user.phone }}"></p>
    <p><input type="submit" value="用户更新"></p>
    </form>
{% endblock %}
update
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} 用户中心{% endblock %}</title>
    <style>
        #head {
            height: 50px;
            background-color: bisque;
        }

        #head ul {
            list-style: none;
            height: 50px;
        }

        #head ul li {
            float: left;
            width: 100px;
            text-align: center;
            font-size: 18px;
            height: 50px;
            line-height: 50px;
        }

        #middle {
            height: 900px;
            background-color: azure;
        }

        #foot {
            height: 50px;
            line-height: 50px;
            background-color: darkseagreen;
        }
    </style>
    {% block mycss %}{% endblock %}
</head>
<body>
<div id="head">
    <ul>
        <li><a href="">首页</a></li>
        <li><a href="">秒杀</a></li>
        <li><a href="">超市</a></li>
        <li><a href="">图书</a></li>
        <li><a href="">会员</a></li>
    </ul>
</div>
<div id="middle">
    {% block middle %}

    {% endblock %}
</div>
<div id="foot">

</div>

{% block myjs %}{% endblock %}
</body>
</html>
base
from apps import create_app

app=create_app()

if __name__ == '__main__':
    app.run()
app
ENV="development"
DEBUG=True
setting

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章