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

 

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