Django3.0+Python3.8+MySQL8.0 個人博客搭建十四|註冊登錄

一、前言

前面我們已經創建好數據模型了,並且在admin後臺中添加了一些測試用戶。下面我們就要設計好站點的url路由、對應的處理視圖函數以及使用的前端模板了。這個登錄註冊使用的是 Bootstrap 雖然 崔慶才 的博客是 Wordpress 主題也是使用的 Bootstrap 但是,抓取網頁源碼時把所有的樣式都變成 style.css 文件了,懶得整理,所有這裏註冊登錄頁面沒有繼承基礎模板 base.html

這裏有推薦一個方便又好用用戶管理包:django-allauth

如果想用django-allauth

推薦閱讀:使用django-allauth實現第三方賬號登錄 django-allauth官方文檔 推薦參考源碼

不過,這裏追求開發速度,就暫時先用着一個原有的註冊登錄代碼,後期視時間再做功能。

二、配置路由

雖然登錄系統屬於站點的一級功能,採用一級路由更直觀和更易於接受,但是這裏採用二級路由的方式,同樣使用反向解析名(name參數),便於以後維護升級用戶中心

一級路由

blog -> blog -> urls.py

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

app_name = 'fswy'
urlpatterns = [
    # 後臺管理應用,django自帶
    path('admin/', admin.site.urls),
    # 用戶
    path('accounts/', include(('apps.user.urls', "apps.user"), namespace="accounts")),
    # fswy 應用
    path('', include(('apps.fswy.urls', "apps.fswy"), namespace="blog")),

]

二級路由

blog -> apps -> user -> urls.py

from django.urls import path,re_path
from .views import login_view, logout_view, register_view, profile_view, change_profile_view

urlpatterns = [
    path(r'login/', login_view, name='login'),
    path(r'logout', logout_view, name='logout'),
    path(r'register/', register_view, name='register'),
    path(r'profile/', profile_view, name='profile'),
    path(r'profile/change/', change_profile_view, name='change_profile'),

]

三、編寫視圖

blog -> apps -> user -> views.py

from django.contrib import auth
from .models import Ouser
from django.contrib.auth import authenticate
from django.contrib.auth.decorators import login_required
from django.contrib import messages
# 第四個是 auth中用戶權限有關的類。auth可以設置每個用戶的權限。
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render, redirect, HttpResponseRedirect
from .forms import UserForm, loginForm, ProfileForm
import re



# Create your views here.

# 註冊
@csrf_exempt
def register_view(request):
    context = {}
    if request.method == 'POST':
        form = UserForm(request.POST)
        next_to = request.POST.get('next', 0)
        if form.is_valid():
            # 獲得表單數據
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            password2 = form.cleaned_data['password2']
            email = form.cleaned_data['email']
            context = {'username': username, 'pwd': password, 'email': email}
            if password.isdigit():
                context['pwd_error'] = 'nums'
                return render(request, 'account/signup.html', context)
            if password != password2:
                context['pwd_error'] = 'unequal'
                return render(request, 'account/signup.html', context)

            # 判斷用戶是否存在
            user = Ouser.objects.filter(username=username)
            Email = Ouser.objects.filter(email=email)
            pwd_length = len(password)
            if pwd_length < 8 or pwd_length > 20:
                context['pwd_error'] = 'length'
                return render(request, 'account/signup.html', context)

            user_length = len(username)

            if user_length < 5 or user_length > 20:
                context['user_error'] = 'length'
                return render(request, 'account/signup.html', context)
            if user:
                context['user_error']='exit'
                return render(request, 'account/signup.html', context)
            if not re.match('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', email):
                context['email_error'] = 'format'
                return render(request, 'account/signup.html', context)
            if Email:
                context['email_error'] = 'exit'
                return render(request, 'account/signup.html', context)
            # 添加到數據庫(還可以加一些字段的處理)
            user = Ouser.objects.create_user(username=username, password=password, email=email)
            user.save()
            user = auth.authenticate(username=username, password=password)

            # 添加到session
            request.session['username'] = username
            request.session['uid'] = user.id
            request.session['nick'] = ''

            # 調用auth登錄
            auth.login(request, user)
            # 重定向到首頁
            if next_to == '':
                next_to = '/'
            return redirect(next_to)
    else:
        next_to = request.GET.get('next', '/')
        context = {'isLogin': False}
        context['next_to'] = next_to
    # 將req 、頁面 、以及context{}(要傳入html文件中的內容包含在字典裏)返回
    return render(request, 'account/signup.html', context)


# 登陸
@csrf_exempt
def login_view(req):
    context = {}
    if req.method == 'POST':
        form = loginForm(req.POST)
        next_to=req.POST.get('next','/')

        remember = req.POST.get('remember', 0)
        if form.is_valid():
            # 獲取表單用戶密碼
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            context={'username':username,'pwd':password}
            # 獲取的表單數據與數據庫進行比較
            user = authenticate(username = username,password = password)
            if next_to=='':
                next_to='/'
            if user:
                if user.is_active:
                    # 比較成功,跳轉index
                    auth.login(req,user)
                    req.session['username'] = username
                    req.session['uid'] = user.id
                    req.session['nick'] = None
                    req.session['tid'] = None
                    reqs = HttpResponseRedirect(next_to)
                    if remember != 0:
                        reqs.set_cookie('username',username)
                    else:
                        reqs.set_cookie('username', '', max_age=-1)
                    return reqs
                else:
                    context['inactive'] = True
                    return render(req, 'account/login.html', context)
            else:
                # 比較失敗,還在login
                context['error'] = True
                return render(req, 'account/login.html', context)
    else:
        next_to = req.GET.get('next', '/')

        context['next_to'] = next_to

    return render(req, 'account/login.html', context)


# 登出
def logout_view(req):
    # 清理cookie裏保存username
    next_to = req.GET.get('next', '/')
    if next_to == '':
        next_to = '/'
    auth.logout(req)
    return redirect(next_to)


@login_required
def profile_view(request):
    return render(request, 'oauth/profile.html')


@login_required
@csrf_exempt
def change_profile_view(request):
    if request.method == 'POST':
        # 上傳文件需要使用request.FILES
        form = ProfileForm(request.POST, request.FILES, instance=request.user)
        if form.is_valid():
            form.save()
            # 添加一條信息,表單驗證成功就重定向到個人信息頁面
            messages.add_message(request, messages.SUCCESS, '個人信息更新成功!')
            return redirect('accounts:profile')
    else:
        # 不是POST請求就返回空表單
        form = ProfileForm(instance=request.user)
    return render(request, 'oauth/change_profile.html', context={'form': form})

注意

在視圖裏使用next_to實現註冊登錄後跳轉到註冊登錄前瀏覽頁面.

四、前端模板

templates文件中添加登錄註冊頁面文件,方便管理頁面accountoauth

blog -> templates -> account -> base.html

{% load static %}
<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="referrer" content="origin">
    <!-- TDK and ICO -->
    {% block title %}{% endblock %}

    <meta name="description" content="用戶賬號管理,使用django-allauth社交用戶系統,支持微博、Github等社交賬號登錄,加入TendCode,查看更多信息。">
    <meta name="keywords" content="django-allauth,社交用戶系統,OAuth 2.0">


    <!-- Bootstrap and font-awesome CSS -->
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type='text/css'>
    <link href="{% static 'font-awesome-4.7.0/css/font-awesome.min.css' %}" rel="stylesheet">

</head>
<body>

<!--主要內容塊-->
{% block main %}
{% endblock %}


<footer class="container-fluid mt-4">
    <div class="card-body text-center px-0 f-16">
        <p class="card-text mb-1">Copyright&nbsp;&copy;&nbsp;2017-<span id="year-info"></span>
            <script>function getnewYear(){var d = new Date();var x = document.getElementById("year-info");
            x.innerHTML=d.getFullYear();}getnewYear()</script>
            <a href="https://github.com/fswy" target="_blank" title="博客作者的Github">fswy</a>.&nbsp;Powered&nbsp;by&nbsp;Django.
        </p>
        <p class="mb-0">
            <a href="http://www.miibeian.gov.cn/" target="_blank">粵ICP備17114114號-3</a>&nbsp;|
            <a href="/sitemap.xml" target="_blank">網站地圖</a>Sha
        </p>
        <!--站長統計-->
        <div>
            <script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");
            document.write(unescape("%3Cspan id='cnzz_stat_icon_1276375952'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s96.cnzz.com/z_stat.php%3Fid%3D1276375952%26online%3D1%26show%3Dline' type='text/javascript'%3E%3C/script%3E"));</script>
        </div>
        <!--站長統計結束-->
    </div>
</footer>
</body>
</html>

blog -> templates -> account -> login.html

{% extends 'account/base.html' %}

{% block title %}
<title>登錄</title>
{% endblock %}
<!--主要內容塊-->
{% block main %}
    <main>
<div class="container">
    <div class="row">
        <div class="col-12 col-sm-8 col-md-6 offset-sm-2 offset-md-3 px-xl-5">
            <div class="card rounded-0 px-3 px-lg-4">
                <div class="card-header text-center bg-white py-2">
                    <h3 class="my-1 text-info">登錄</h3>
                </div>
                <div class="card-body card-login">
<form class="login" method="POST" action="{% url 'accounts:login' %}">
    {% csrf_token %}
    {% if error %}
<div class="alert alert-block alert-danger"> <ul> <li>您提供的用戶名或密碼不正確。</li> </ul> </div>
    {% endif %}
{% if inactive %}
<div class="alert alert-block alert-danger"> <ul> <li>您的賬號已被封禁。</li> </ul> </div>
    {% endif %}
<div id="div_id_login" class="form-group"> <label for="id_login" class="form-control-label  requiredField">
                賬號<span class="asteriskField">*</span> </label> <div class=""> <input type="text" name="username" placeholder="用戶名或e-mail" autofocus="autofocus" value="{{ username }}" class="textinput textInput form-control" required id="id_login" /> </div> </div> <div id="div_id_password" class="form-group"> <label for="id_password" class="form-control-label  requiredField">
                密碼<span class="asteriskField">*</span> </label> <div class=""> <input type="password" value="{{ pwd }}" name="password" placeholder="密碼" class="textinput textInput form-control" required id="id_password" /> </div> </div> <div class="form-group"> <div id="div_id_remember" class="checkbox"> <label for="id_remember" class=""> <input type="checkbox" name="remember" class="checkboxinput" id="id_remember" />
                    記住我
                </label> </div> </div>


    <input type="hidden" name="next" value="{{ next_to }}"/>

    <a class="secondaryAction" href="{% url 'accounts:register' %}">忘記密碼了?</a>

    <button class="pull-right btn btn-info btn-sm rounded-0" type="submit">登錄</button>
    <div class="login-title">
                        <span><a  href="{% url 'accounts:register' %}">還沒賬號?去註冊</a></span>
    </div>
</form>

</div>

            </div>
        </div>
    </div>
</div>
</main>
{% endblock %}

blog -> templates -> base.html

<!--登錄-->
<!--目前登錄功能只有註冊登錄其它沒必要沒做-->
 <div class="pull-right">
     {% if request.session.username|default:'' == '' %}
             <i class="fa fa-power-off"></i>
             <a href="{% url 'accounts:login' %}?next={{ request.path }}">登錄</a>
     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <i class="fa fa-user-plus"></i>
             <a href="{% url 'accounts:register' %}?next={{ request.path }}">註冊</a>
     {% else %}
             &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i class="fa fa-user"></i>
             <a href="/">投稿</a>
             &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i class="fa fa-user-circle-o" aria-hidden="true"></i>
             <a href="{% url 'accounts:profile' %}?next={{ request.path }}">{{ request.session.username }}</a>

             &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i class="fa fa-sign-out" aria-hidden="true"></i>
             <a href="{% url 'accounts:logout' %}?next={{ request.path }}">退出</a>
     {% endif %}
 </div>
 <!--登錄註冊結束-->

其餘頁面不再展示,可以去拷貝源碼研究 blog

注意

由於新增的頁面使用了bootstrap所以需要在從源碼裏拷貝bootstrap.min.cssblog -> static -> css 文件下

提示

用戶中心,可以上傳用戶頭像需要創建一個存儲用戶上傳的文件的文件夾 media

blog->blog->settings.py

# 媒體文件收集
MEDIA_URL = "/media/"   # 媒體文件別名(相對路徑) 和 絕對路徑
MEDIA_ROOT = (
    os.path.join(BASE_DIR, 'media')
)

五、目前項目結構

.
|-- blog
|   |-- fswy                   # 博客應用
|   |   |-- migrations          # 數據庫映射文件
|   |   |-- templatetags        # 自定義模板標籤文件
|   |   |   |-- __init__.py     # 聲明模塊,內容默認爲空
|   |   |   |-- blog_tags.py    # 自定義數據篩選函數
|   |   |-- __init__.py         # 聲明模塊,內容默認爲空
|   |   |-- admin.py            # 該應用的後臺管理系統
|   |   |-- apps.py             # 應用配置,Django-1.9以後自動生成
|   |   |-- models.py           # 數據模塊,使用ORM框架
|   |   |-- tests.py            # 自動化測試的模塊  
|   |   |-- urls.py   
|   |   |-- views.py            # 執行響應的代碼所在模塊,是代碼邏輯處理的主要地點,項目中大部分代碼在這裏編寫    
|   |-- user                    # 用戶應用	
|   |   |-- migrations  
|   |   |-- templatetags        # 自定義模板標籤文件
|   |   |   |-- __init__.py     # 聲明模塊,內容默認爲空
|   |   |   |-- oauth_tags.py   # 自定義數據篩選函數 	
|   |   |-- __init__.py     
|   |   |-- admin.py        
|   |   |-- apps.py   
|   |   |-- forms.py   
|   |   |-- models.py       
|   |   |-- tests.py
|   |   |-- urls.py          
|   |   |-- views.py        
|   |-- blog                # 項目的容器
|   |   |-- __init__.py     # 聲明模塊,內容默認爲空
|   |   |-- settings.py     # 該 Django 項目的設置/配置。
|   |   |-- urls.py         # 該 Django 項目的 URL 聲明; 一份由 Django 驅動的網站"目錄"。
|   `-- wsgi.py             # 一個 WSGI 兼容的 Web 服務器的入口,以便運行你的項目
|   |-- static              # 靜態文件
|   |   |-- css
|   |   |-- fonts
|   |   |-- images
|   |   |-- js
|   |-- media               # 用戶上傳的文件
|   |   |-- avatar          # 用戶頭頭像
|   |-- templates               # 模板文件
|   |   |-- account             # 登錄註冊頁面文件
|   |   |   |-- base.html       # 登錄註冊基礎模板
|   |   |   |-- login.html      # 登陸頁面
|   |   |   |-- signup.html     # 註冊頁面
|   |   |-- oauth               # 用戶中心頁面文件夾	
|   |   |   |-- tags            # 用戶
|   |   |   |   |-- user_avatar.html
|   |   |   |-- change_profile.html # 修改個人信息頁面
|   |   |   |-- profile.html        # 個人中心
|   |   |-- about.html
|   |   |-- donate.html
|   |   |-- exchange.html
|   |   |-- index.html
|   |   |-- message.html
|   |   |-- project.html
|   |   |-- question.html
|   |   |-- resources.html
|   |   |-- technique.html
|   |   |-- wp-login.html
`-- manage.py

六、運行效果

在這裏插入圖片描述
在這裏插入圖片描述

教程目錄

Django3.0+Python3.8+MySQL8.0 個人博客搭建一|前言
Django3.0+Python3.8+MySQL8.0 個人博客搭建二|創建虛擬環境
Django3.0+Python3.8+MySQL8.0 個人博客搭建三|創建博客項目
Django3.0+Python3.8+MySQL8.0 個人博客搭建四|創建第一個APP
Django3.0+Python3.8+MySQL8.0 個人博客搭建五|makemigrations連接MySQL數據庫的坑
Django3.0+Python3.8+MySQL8.0 個人博客搭建六|數據庫結構設計
Django3.0+Python3.8+MySQL8.0 個人博客搭建七|makemigrations創建數據庫的坑(第二彈)
Django3.0+Python3.8+MySQL8.0 個人博客搭建八|通過admin管理後臺
Django3.0+Python3.8+MySQL8.0 個人博客搭建九|博客首頁開發(一)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十|整理項目結構
Django3.0+Python3.8+MySQL8.0 個人博客搭建十一|博客首頁開發(二)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十二|博客首頁開發(三)
Django3.0+Python3.8+MySQL8.0 個人博客搭建十三|博客詳情頁面

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