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
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL0cmaNBTR650MRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyczNwMjM0QTM2AzMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
- 啟動開發伺服器
# 啟動服務,指定8080 端口
python manage.py runserver 8080
- 浏覽器通路,檢測是否成功?(第一步完美搞定)
通路網址: http://127.0.0.1:8080/
通路網址: http://127.0.0.1:8080/admin/
安裝ignore 插件
過濾某些不想送出到git 本地庫的檔案
git送出項目代碼到本地倉庫
$ git init
# 安裝插件.ignore, 并生成python上傳git項目需要忽略内容的檔案.gitignore
$ git add * # 添加修改到暫存區
$ git commit -m "搭建項目開發環境" # 将暫存區的代碼送出到本地git倉庫
$ git log # 檢視曆史送出記錄
設計資料庫模型
使用者表分析
作為一個使用者登入和注冊項目,需要儲存的都是各種使用者的相關資訊。很顯然,我們至少需要一張使用者 表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支援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 # 将遷移腳本的内容寫入資料庫并建立資料庫表
測試是否成功 打開資料庫檔案db.sqlite3, 檢視是否有資料庫表login_siteuser,如果有,則操作成功。
資料庫模型背景管理
資料庫模型背景管理(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庫
檢視本地 git 庫送出日志
浏覽器通路,檢測是否成功?(完美搞定)
通路網址: http://127.0.0.1:8080/admin/
路由與視圖函數架構搭建
路由設計
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 庫
測試是否成功
浏覽器通路,檢測是否成功?(第一步完美搞定)
- 通路網址: 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>
完善登入的視圖函數
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 庫
浏覽器通路,檢測是否成功?
- 通路網址: 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