天天看點

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

Django 項目實踐 —— 可重用注冊登入系統 (1)

目錄

可重用注冊登入系統

可重用注冊登入系統

搭建項目環境

建立應用

安裝ignore 插件

git送出項目代碼到本地倉庫

設計資料庫模型

使用者表分析

檔案的配置

生成遷移腳本并寫入資料庫

資料庫模型背景管理

路由與視圖函數架構搭建

路由設計

通路政策

路由配置

模闆template的配置

前端界面設計與優化

完善登入的視圖函數

html和視圖函數互動的完善

session會話與登入的視圖函數

可重用注冊登入系統

  • 注冊(郵箱注冊,手機,微信,QQ)
  • 登入
  • 登出

搭建項目環境

建立應用

  • 建立Django項目
  • 設定時區和語言
  • 建立app
python manage.py startapp login           
  • 資料庫表生成
python manage.py makemigrations           
python manage.py migrate           
python manage.py createsuperuser           
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
  • 啟動開發伺服器
# 啟動服務,指定8080 端口
python manage.py runserver 8080           
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
  • 浏覽器通路,檢測是否成功?(第一步完美搞定)

通路網址: http://127.0.0.1:8080/

通路網址: http://127.0.0.1:8080/admin/

安裝ignore 插件

過濾某些不想送出到git 本地庫的檔案

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

git送出項目代碼到本地倉庫

$ git init
# 安裝插件.ignore, 并生成python上傳git項目需要忽略内容的檔案.gitignore
$ git add * # 添加修改到暫存區
$ git commit -m "搭建項目開發環境" # 将暫存區的代碼送出到本地git倉庫
$ git log # 檢視曆史送出記錄           
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

設計資料庫模型

使用者表分析

作為一個使用者登入和注冊項目,需要儲存的都是各種使用者的相關資訊。很顯然,我們至少需要一張使用者 表User,在使用者表裡需要儲存下面的資訊:

  • 使用者名(name): 必填,最長不超過128個字元且唯一(unique)
  • 密碼(password): 必填,最長不超過256個字元
  • 郵箱位址(email): 使用Django内置的郵箱類型且唯一
  • 性别(gender): 性别, 使用choice,隻能選擇男或者女或者未知,預設為未知;
  • 建立時間(create_time): 使用者建立時間

注意點: auto_now_add=True時為添加時的時間,更新對象時不會有變動。

  • 修改時間(modify_time):使用者最後一次修改時間

注意點: auto_now=True無論是你添加還是修改對象,時間為你添加或者修改的時間。

  • 最後一次登入時間(last_login_time): 最後一次登入時間

注意點:null=True的話,資料庫中該字段是NULL,即允許空值

注意點:blank=False(預設)的話,字段沒被指派則會抛錯;和資料驗證(表單驗證等)有 關

檔案的配置

資料庫模型檔案(login/models.py)

from django.db import models
# 定義資料庫模型

# Create your models here.

# appname_siteuser
class SiteUser(models.Model):
    """使用者的資料庫模型,注冊/登陸需要"""
    # gender_choice 性别
    gender_choice = (
        (0, "未知"),
        (1, "男"),
        (2, "女"),
    )
    # 姓名,字元串類型, unique=True (唯一辨別)
    name = models.CharField(max_length=128, unique=True, verbose_name="使用者名")
    # 密碼
    password = models.CharField(max_length=256, verbose_name="密碼")
    # 郵件
    email = models.EmailField(unique=True, verbose_name="電子郵件")
    # 性别,預設0,未知
    gender = models.IntegerField(choices=gender_choice, default=0, verbose_name="性别")
    # 建立時間,
    # auto_now_add=True時為添加時的時間,更新對象時不會有變動。
    # auto_now=True無論是你添加還是修改對象,時間為你添加或者修改的時間。
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="建立時間")
    # 最後一次更改時間
    modify_time = models.DateTimeField(auto_now=True, verbose_name="最後一次修改時間")
    # 最後一次登入時間
    # null針對資料庫層面的, blank針對表單的
    last_login_time = models.DateTimeField(null=True, blank=True, verbose_name="最後一次登陸時間")

    # 友好展示
    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "網站使用者管理"
        verbose_name_plural = verbose_name
           

儲存到本地 git 庫

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

設定資料庫後端

Django支援MySQL, Sqlite, oracle等資料庫, 此處選擇預設的sqlite,不做修改。

注冊app(loginRegister/setting.py)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'login',    # 修改的内容
]           

生成遷移腳本并寫入資料庫

生成遷移腳本并寫入資料庫

python manage.py makemigrations   # 生成遷移檔案           
python manage.py migrate   # 将遷移腳本的内容寫入資料庫并建立資料庫表           
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

 測試是否成功 打開資料庫檔案db.sqlite3, 檢視是否有資料庫表login_siteuser,如果有,則操作成功。

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

資料庫模型背景管理

資料庫模型背景管理(login/admin.py)

from django.contrib import admin

# Register your models here.

from login.models import SiteUser


class SiteUseradmin(admin.ModelAdmin):
    list_display = ['id', 'name', 'gender']
    list_filter = ['gender', 'create_time']
    search_fields = ['name']


admin.site.register(SiteUser, SiteUseradmin)
           

儲存到本地 git庫

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

檢視本地 git 庫送出日志

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

浏覽器通路,檢測是否成功?(完美搞定)

通路網址: http://127.0.0.1:8080/admin/

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

路由與視圖函數架構搭建

路由設計

URL 視圖views 模闆 功能
/index/ login.views.index index.html 首頁
/login/ login.views.login login.html 登陸頁面
/register/ login.views.register register.html 注冊界面
/logout/ login.views.logout 無需傳回頁面 登出界面

通路政策

  • 未登入人員,不論是通路index還是login和logout,全部跳轉到login界面
  • 已登入人員,通路login會自動跳轉到index頁面
  • 已登入人員,不允許直接通路register頁面,需先logout
  • 登出後,自動跳轉到login界面

路由配置

主路由配置檔案(loginRegister/urls.py)

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('login.urls')),
]
           

子路由配置檔案(login子應用的)(login/urls.py  (建立))

from django.contrib import admin
from django.urls import path, include
from login import views

urlpatterns = [
    path('index/', views.index, name='index'),
    path('login/', views.login, name='login'),
    path('register/', views.register, name='register'),
    path('logout/', views.logout, name='logout'),
]           

視圖函數的配置(login/views.py)

# login/views.py
from django.shortcuts import render, redirect
# Create your views here.

def index(request):
    pass
    return render(request, 'login/index.html')

def login(request):
    pass
    return render(request, 'login/login.html')

def register(request):
    pass
    return render(request, 'login/register.html')

def logout(request):
    pass
    # redirect: 重定向(跳轉)
    return redirect('/login/')
           

模闆template的配置

templates/login/index.html(建立)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
</head>
<body>
<h1>這是首頁的模拟界面</h1>
</body>
</html>
           

templates/login/login.html(建立)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用者登入</title>
</head>
<body>
<h1>使用者登入</h1>
<form>
    使用者名: <input type="text" placeholder="username"><br/>
    密碼: <input type="password" placeholder="password"><br/>
    <input type="submit" value="登入">
</form>
</body>
</html>           

templates/login/register.html(建立)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注冊界面</title>
</head>
<body>
<h1>使用者注冊</h1>
<form>
    使用者名: <input type="text" placeholder="username"><br/>
    電子郵箱: <input type="email" placeholder="email"><br/>
    密碼: <input type="password" placeholder="password"><br/>
    确認密碼: <input type="password" placeholder="password"><br/>
    <input type="submit" value="注冊">
</form>
</body>
</html>
           

儲存到本地git 庫

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

測試是否成功

浏覽器通路,檢測是否成功?(第一步完美搞定)

  • 通路網址: http://127.0.0.1:8080/index/
  • 通路網址: http://127.0.0.1:8080/login/
  • 通路網址: http://127.0.0.1:8080/register/

前端界面設計與優化

在顔值即正義的年代,但沒有CSS和JS,樣子真的令人無法接受。 然而,大多數使用Django的人都不具備多高的前端水準,通常也沒有專業的前端工程師配合,自己寫的 CSS和JS卻又往往慘不忍睹。怎麼辦?沒關系,我們有現成的開源前端CSS架構!Bootstrap4就是最好 的CSS架構之一!

Bootstrap核心彙總:

  • Bootstrap入門模闆
  • Bootstrap栅格系統
  • Boostrap表單元件
  • Bootstrap警告框

首頁美化

# template/login/index.html



<!doctype html>
<html lang="zh-CN">
<head>
    <!-- 必須的 meta 标簽 -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap 的 CSS 檔案 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" target="_blank" rel="external nofollow" 
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>首頁</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <a class="navbar-brand" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >首頁</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="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >Link</a>
            </li>
            <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  id="navbarDropdown" role="button" data-toggle="dropdown"
                   aria-haspopup="true" aria-expanded="false">
                    Dropdown
                </a>
                <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                    <a class="dropdown-item" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >Action</a>
                    <a class="dropdown-item" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >Another action</a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >Something else here</a>
                </div>
            </li>
            <li class="nav-item">
                <a class="nav-link disabled" href="#" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  tabindex="-1" aria-disabled="true">Disabled</a>
            </li>
        </ul>
        <form class="form-inline my-2 my-lg-0">
            <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
        </form>
        <ul class="navbar-nav">
            <li class="nav-item">
                <a class="nav-link" href="/logout/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >登出</a>
            </li>

            <li class="nav-item">
                <a class="nav-link" href="/index/" target="_blank" rel="external nofollow" >{{ request.session.username }}</a>
            </li>
        </ul>
    </div>
</nav>

<h1>你好, {{ request.session.username }}, 這是首頁的模拟界面</h1>


<!-- JavaScript 檔案是可選的。從以下兩種建議中選擇一個即可! -->

<!-- 選項 1:jQuery 和 Bootstrap 內建包(內建了 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-LCPyFKQyML7mqtS+4XytolfqyqSlcbB3bvDuH9vX2sdQMxRonb/M3b9EmhCNNNrV"
        crossorigin="anonymous"></script>

<!-- 選項 2:Popper 和 Bootstrap 的 JS 插件各自獨立 -->
<!--
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-gRC4eoaRyQ8xv2X6Mnf+eOIrtON3wId3dAkwO0HQX26OrFBoLpjX/XWOJacSiZhL" crossorigin="anonymous"></script>
-->
</body>
</html>           
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

完善登入的視圖函數

html和視圖函數互動的完善

  • 修改1. 有message資訊則顯示, 沒有就不顯示。
  • 修改2: 送出登入資訊時, 以post方法送出給/login/對應的是視圖函數處理。
  • 修改3: Django提供了csrf防攻擊的機制, 添加該資訊則可順利通路登陸界面
  • 修改4:name="username"指定表單内容存儲的key值名稱, eg: {"username":"你填的使用者 名","password":"你填的密碼" }

templates/login/login.html

<div class="col-sm">
    <h3 style="text-align: center">使用者登入</h3>
    # 修改1. 有message資訊則顯示, 沒有就不顯示。
    {% if message %}
    <div class="alert alert-warning" role="alert">
    <    strong>登入失敗!</strong> {{ message }}

    </div>
    {% endif %}
    # 修改2: 送出登入資訊時, 以post方法送出給/login/對應的是視圖函數處理。
    <form action="/login/" method="post">
        # 修改3: Django提供了csrf防攻擊的機制, 添加該資訊則可順利通路登陸界面
        {% csrf_token %}
        <div class="form-group">
            <label>使用者名</label>
            # 修改4:name="username"指定表單内容存儲的key值名稱, eg:{"username":"你填的使用者名"}
            <input type="text" class="form-control" name="username">
        </div>
        <div class="form-group">
            <label>Password</label>
            <input type="password" class="form-control" name="password">
            <small class="form-text text-muted">密碼必須是字母、數字或者特殊符号組成</small>
        </div>
        <a href="/register/" target="_blank" rel="external nofollow"  class="text-success">
            <ins>新使用者注冊</ins>
        </a>
        <button type="submit" class="btn btn-primary float-right">登入</button>
    </form>
</div>           

視圖函數的完善(login/views.py)

# login/views.py
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username').strip()
        password = request.POST.get('password').strip()
        # print(username, password)
        if username and password:
            user = SiteUser.objects.filter(name=username,password=password).first()
            if user:
                return redirect('/index/')
            else:
                message = "使用者名或者密碼錯誤"
                return render(request, 'login/login.html',{'message':message})
        else:
            message = "非法的資料資訊"
            return render(request, 'login/login.html', {'message': message})
    return render(request, 'login/login.html')           

儲存到本地git 庫

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)

浏覽器通路,檢測是否成功?

  • 通路網址: http://127.0.0.1:8080/login/
  • 填寫正确的使用者名和密碼/錯誤的使用者名和密碼測試是否為期待的效果。

session會話與登入的視圖函數

登入成功, 存儲登入的使用者資訊到session中(login/views.py)

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username').strip()
        password = request.POST.get('password').strip()
        # print(username, password)
        if username and password:
            user = SiteUser.objects.filter(name=username,password=password).first()
            if user:
                # ------------核心修改的内容開始
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['username'] = user.name
                # --------------核心修改的内容結束
                return redirect('/index/')
            else:
                message = "使用者名或者密碼錯誤"
                return render(request, 'login/login.html',{'message':message})
        else:
            message = "非法的資料資訊"
            return render(request, 'login/login.html', {'message': message})
    return render(request, 'login/login.html')
           

登出時,清空session資訊(login/views.py)

def logout(request):
    # 如果狀态不是登入狀态,則無法登出。
    if request.session.get('is_login'):
        request.session.flush() # 清空session資訊
    return redirect('/login/')
           

在首頁添加登出的超連結并測試(templates/login/index.html)

# 核心代碼如下:
    <h1>你好, {{ request.session.username }}, 這是首頁的模拟界面</h1>
    <a href="/logout/" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" ><strong style="font-size: 20px">登出</strong></a>           

浏覽器通路,檢測是否成功?

通路網址: http://127.0.0.1:8080/index/

項目位址: https://gitee.com/half-summer/loginregister

Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)
Django 項目實踐 —— 可重用注冊登入系統 (1)Django 項目實踐 —— 可重用注冊登入系統 (1)