1. 程式人生 > >Django專案-個人網站之登入註冊模組

Django專案-個人網站之登入註冊模組

Django專案之個人網站

感興趣的可以fork或star一下
這裡寫圖片描述

功能模組一:登入/註冊

一、說明

功能:使用者名稱、密碼、驗證碼輸入、頭像上傳

技術:檔案上傳、驗證碼、密碼加密、會話技術

二、介面
1、登入

這裡寫圖片描述

2、註冊

這裡寫圖片描述

三、程式碼
1、前端(T)
1.1 base.html
{#    父模板base.html#}
{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"
>
{# 響應式web設計,自適應瀏覽器大小#} <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="save" content="history"> {% block title %} <title>首頁</title> {% endblock %} {% block link %} {% endblock %} <link href="{% static 'SitesApp/css/reset.css' %}"
rel="stylesheet">
<link href="{% static 'SitesApp/css/sitesAppCss.css' %}" rel="stylesheet"> {# <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">#} {# <script src="https://cdn.bootcss.com/jquery/1.12.0/jquery.min.js"></script>#} {# <script
src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js">
</script>#} <link href="/static/SitesApp/css/bootstrap.min.css" rel="stylesheet"> {% block style %} {% endblock %} <script src="/static/SitesApp/js/jquery.min.js"></script> <script src="/static/SitesApp/js/bootstrap.min.js"></script> {% block script %} <script type="text/javascript"></script> {% endblock %} </head> <body style="background-color: #E6E6FA;"> <a href="{% url 'sitesApp:vote' 1 %}">hhhhh</a> <div class="box"> <div class="header"> <ul class="nav nav-pills navbar faq-tabbable"> <li role="presentation" class="active"><a href="{% url 'sitesApp:home' %}">首頁</a></li> <li role="presentation"><a href="{% url 'sitesApp:vote' 1 %}">投票</a></li> <li role="presentation"><a href="{% url 'sitesApp:grade' %}">打分</a></li> <li role="presentation"><a href="{% url 'sitesApp:review' %}">回顧</a></li> <li role="presentation"><a href="{% url 'sitesApp:blog' %}">部落格</a></li> <li role="presentation"><a href="{% url 'sitesApp:dataBank' %}">資料</a></li> <li role="presentation"><a href="{% url 'sitesApp:forum' %}">論壇</a></li> <li role="presentation"><a href="{% url 'sitesApp:mine' %}">我的</a></li> <li role="presentation"><a href="{% url 'sitesApp:login' %}">登入</a></li> <li role="presentation"><a href="{% url 'sitesApp:register' %}">註冊</a></li> </ul> </div> <div class="time" > <span id="mytime"></span> </div> <div class="content" style="position: relative;"> {% block content %} 這傢伙很懶,還沒開始開發...~_~ {% endblock %} </div> <div class="footer"> {% block footer %} 開發者 LDC {% endblock %} </div> </div> <script type="text/javascript"> $(function ($) { {# 導航欄按鈕渲染#}   $(".faq-tabbable").find("li").each(function () {     var a = $(this).find("a:first")[0];      if ($(a).attr("href") === location.pathname) {       $(this).addClass("active");     } else {        $(this).removeClass("active");     }   }); }); {#實時顯示時間#} function showTime(){ nowtime=new Date(); year=nowtime.getFullYear(); month=nowtime.getMonth()+1; date=nowtime.getDate(); document.getElementById("mytime").innerText=year+"年"+month+"月"+date+" "+nowtime.toLocaleTimeString(); } <!--定時重新整理時間--> setInterval("showTime()",1000); </script> </body> </html>
1.2 login.html
{% extends 'SitesApp/base.html' %}

{% block title %}
    <title>登入</title>
{% endblock %}
{% block content %}
    {#   檔案上傳、驗證碼、密碼加密、會話技術#}
    <form id="formLogin" method="post" action="{% url 'sitesApp:login' %}"
          onkeydown="if(event.keyCode==13) return focusNextInput(this);">
        {% csrf_token %}
        <div class="login">
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">使用者名稱</span>
                <input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1"
                       name="uname" onkeyup="if(event.keyCode==13) focusNextInput(this);">
            </div>

            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">密&nbsp;&nbsp;&nbsp;&nbsp;碼</span>
                <input type="password" class="form-control" placeholder="Password" aria-describedby="basic-addon1"
                       name="upwd" onkeyup="if(event.keyCode==13) focusNextInput(this);">
            </div>
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">驗證碼</span>
                <input type="text" class="form-control" placeholder="Auth code" aria-describedby="basic-addon1"
                       name="vcode" onkeyup="if(event.keyCode==13) focusNextInput(this);">
            </div>
            <div class="vcode">
                <img src="/app/getvcode/" id="vcode">
            </div>
            <input id="submit" type="submit" class="loginBtn" value="登  錄">
        </div>
    </form>
{% endblock %}
{% block script %}
    <script src="/static/SitesApp/js/jquery-form.js"></script>
    <script type="text/javascript">
        $(function () {
            {#            驗證碼點選時生成隨機的路由請求#}
            $('#vcode').click(function () {
                $(this).attr('src', "/app/getvcode" + Math.random())
            })
        });
        {#        表單提交後,處理伺服器返回的資料#}
        $(document).ready(function () {
            $("#formLogin").ajaxForm(function (data) {
                {#                 alert("post success." + data);#}
                data = $.parseJSON(data);
                if (data['status'] == '1') {
                    {#                        alert('登入成功');#}
                    {#          跳轉到我的主頁           #}
                    window.location.href = "{% url 'sitesApp:mine' %}";
                } else {
                    alert(data['ret']);
                }
            });
        });
        //jQuery實現在一個輸入框按回車鍵後游標跳到下一個輸入框
        function focusNextInput(thisInput) {
            var inputs = document.getElementsByTagName("input");
            for (var i = 0; i < inputs.length; i++) {
                // 如果是最後一個,則焦點回到第一個
                if (i == (inputs.length - 1)) {
                    inputs[0].focus();
                    break;
                } else if (thisInput == inputs[i]) {
                    inputs[i + 1].focus();
                    break;
                }
            }
            return false;
        }
    </script>
{% endblock %}
1.3 register.html
{% extends 'SitesApp/base.html' %}

{% block title %}
    <title>註冊</title>
{% endblock %}
{% block content %}
    {#   檔案上傳、驗證碼、密碼加密、會話技術#}
    {# enctype="multipart/form-data" 上傳支援 #}
    <form id="formLogin" method="post" action="{% url 'sitesApp:register' %}" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="login" style="height: 380px">
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">使用者名稱</span>
                <input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1"
                       id="uname" name="uname" >
            </div>
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">暱&nbsp;&nbsp;&nbsp;&nbsp;稱</span>
                <input type="text" class="form-control" placeholder="Nickname" aria-describedby="basic-addon1"
                       id="unick" name="unick" >
            </div>
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">密&nbsp;&nbsp;&nbsp;&nbsp;碼</span>
                <input type="password" class="form-control" placeholder="Password" aria-describedby="basic-addon1"
                       id="upwd" name="upwd" >
            </div>
            <div class="input-group">
                {# 用於上傳頭像的表單控制元件 #}
                <span class="input-group-addon" id="basic-addon1">頭&nbsp;&nbsp;&nbsp;&nbsp;像</span>
                <input type="file" class="form-control" aria-describedby="basic-addon1" style="height: 37px;"
                       id="uicon" name="uicon" onchange="check()">
            </div>
            <div class="input-group">
                <span class="input-group-addon" id="basic-addon1">驗證碼</span>
                <input type="text" class="form-control" placeholder="Auth code" aria-describedby="basic-addon1"
                       id="vcod" name="vcode" onchange="check()">
            </div>
            <div class="vcode" style="margin: 0;height: 65px;">
                <img src="/app/getvcode/" id="vcode">
            </div>
            <input type="submit" class="loginBtn" value="注  冊">
        </div>
    </form>

{% endblock %}
{% block script %}
    <script src="/static/SitesApp/js/jquery-form.js"></script>
    <script type="text/javascript">
        {#    驗證碼點選事件    #}
        $(function () {
            $('#vcode').click(function () {
                $(this).attr('src', "/app/getvcode" + Math.random())
            });

        });
        {#        表單資料提交後對伺服器返回的資料進行處理#}
        $(document).ready(function () {
            $("#formLogin").ajaxForm(function (data) {
                {#                 alert("post success." + data['status']);#}
                if (data['status'] == '1') {
                    alert('註冊成功');
                    window.location.href = "{% url 'sitesApp:login' %}";
                } else {
                    alert("註冊失敗,請檢查輸入資訊!!!");
                }
            });
        });
        {#        檢查上傳的檔案是否為圖片#}
        function check() {
            var icon = document.getElementById("icon").value.toLowerCase().split('.');//以“.”分隔上傳檔案字串

            if (icon[icon.length - 1] == 'gif' || icon[icon.length - 1] == 'jpg' || icon[icon.length - 1] == 'bmp'
                || icon[icon.length - 1] == 'png' || icon[icon.length - 1] == 'jpeg')//判斷圖片格式
            {
                var imagSize = document.getElementById("icon").files[0].size;
                {#                alert("圖片大小:" + imagSize + "B");#}
                if (imagSize < 1024 * 1024 * 3) {
                    return true;
                }
                alert("圖片大小在3M以內,您選中的圖片大小為:" + (imagSize / (1024 * 1024)).toFixed(2) + "M");

            }
            else {
                alert('請選擇格式為*.jpg、*.gif、*.bmp、*.png、*.jpeg 的圖片');
            }
            {#                檔案選擇錯就把原檔案清空#}
            var obj = document.getElementById('icon');
            obj.outerHTML = obj.outerHTML;
        }
    </script>
{% endblock %}
2 路由處理(V)
2.1 專案下的總路由
urlpatterns = [
    url('^app/',include('SitesApp.urls',namespace='sitesApp'))
]
2.2 子應用下的路由
    # 登入
    url(r'^login/', views.login, name='login'),
    # 註冊
    url(r'^register/', views.register, name='register'),
3、檢視函式處理(Views)
3.1 登入
# 登入
def login(request):
    if request.method == 'GET':
        return render(request, 'SitesApp/login.html')
    else:
        # 預定義一個最終返回的Response物件(可以動態地為其配置內容,要想勒令客戶端做事情必須要有一個Response物件)
        resp = HttpResponse()
        respData = {'status': '0', 'ret': '登入失敗,輸入資訊有誤!!!'}
        # 獲取使用者輸入的使用者名稱、密碼、驗證碼
        uname = request.POST.get('uname', None)
        upwd = request.POST.get('upwd', None)
        vcode = request.POST.get('vcode', None)
        # 校驗驗證碼
        # 從session中獲取正確的驗證碼
        sessVcode = request.session.get('vcode', None)
        # 比較使用者輸入的驗證碼與正確的驗證碼是否匹配
        # 事先全部轉換為小寫形式,這樣使用者可以忽略大小寫
        if vcode and sessVcode and vcode.lower() == sessVcode.lower():
            # 對密碼做訊息摘要
            upwd = useMd5(upwd)
            # 查詢名稱為uname的使用者
            user = User.uManager.filter(uName=uname).first()
            if not user:
                respData = {'status': '0', 'ret': '使用者不存在!!!'}
            # 檢查密碼、驗證碼是否匹配
            if user and upwd == user.uPwd :
                # # 勒令客戶端(通過cookie)自己將狀態儲存起來,過期時間為60秒
                # resp.set_cookie('uname',uname,max_age=60*1)

                # # 讓服務端通過session儲存使用者狀態
                # 向客戶端端要session其實是要儲存在cookie中的sessionid
                # request.session的言下之意是"request.getSessionBySessionid"
                # request.session['uname'] = uname
                # request.session['upwd'] = upwd

                '''
                token相當於手動實現的session
                session將使用者狀態儲存在django_session的表中
                token將使用者狀態儲存在何處完全取決於程式媛自己,例如:User表
                但務必使儲存使用者狀態的這張表中有用於作為[id/key/信物]的欄位(該欄位必須唯一),例如:utoken
                和session一樣,必須在客戶端的cookie中存一個相同的[id/key/信物],例如:utoken
                如何獲取儲存的使用者狀態:先從cookie中拿出utoken,進而查詢User表中utoken為xxx的記錄,就可以拿到uname了
                '''
                # 將使用者狀態儲存在token中,讓客戶端持有一個token,將該token儲存在某個表中
                # 生成令牌/信物
                token = str(uuid.uuid4())
                # 將該令牌/信物儲存在客戶端的cookie中,過期時間一天
                resp.set_cookie('utoken', token,expires=60*60*24)
                # 將同樣的信物存一份在服務端的表中
                user.uToken = token
                try:
                    user.save()
                    respData = {'status': '1', 'ret': 'login success!'}
                except BaseException as e:
                    print(e)
                    respData = {'status': '0', 'ret': '登入失敗,輸入資訊有誤!!!'}
                pass
        resp.content = json.dumps(respData)
        return resp
3.2 註冊
# 註冊
def register(request):
    if request.method == 'GET':
        return render(request, 'SitesApp/register.html')
    else:
        # 獲取使用者輸入的使用者名稱、暱稱、密碼、驗證碼、上傳的頭像
        uname = request.POST.get('uname', None)
        unick = request.POST.get('unick', None)
        upwd = request.POST.get('upwd', None)
        vcode = request.POST.get('vcode', None)
        uip = getUserIP(request)
        # 拿到使用者上傳的檔案資料,型別是框架類InMemoryUploadedFile
        uiconFile = request.FILES.get('uicon', None)
        # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
        print(uname,unick, upwd, vcode, uiconFile, type(uiconFile))

        # 手動儲存上傳的檔案
        # 自定義檔案位置
        # if uiconFile:
        #   fp = os.path.join(MEDIA_ROOT, 'x-' + uiconFile.name)
        #   # 寫入檔案
        #   with open(fp, 'wb') as file:
        #       # 逐"桶"讀取上傳的檔案資料,並寫入本地檔案
        #       for buffer in uiconFile.chunks():
        #           file.write(buffer)

        # 校驗驗證碼
        # 從session中獲取正確的驗證碼
        sessVcode = request.session.get('vcode', None)
        # 比較使用者輸入的驗證碼與正確的驗證碼是否匹配
        # 事先全部轉換為小寫形式,這樣使用者可以忽略大小寫
        if vcode and sessVcode and vcode.lower() == sessVcode.lower():
            user = User()
            user.uName = uname
            user.uNickName = unick
            user.uIP = uip
            # 對密碼做訊息摘要(目的是避免明文儲存)
            user.uPwd = useMd5(upwd)

            # 將上傳過來的檔案直接賦值給使用者的ImageField欄位uicon
            # 框架會自動將圖片儲存在MEDIA_ROOT中
            if uiconFile:
                user.uIcon = uiconFile
            # 把資料寫進資料庫
            try:
                user.save()
                return JsonResponse({'status': 1, 'ret': 'register success!'})
            except BaseException as e:
                print(e)

        return JsonResponse({'status':0,'ret':'輸入資訊有誤!'})