一、修改的部分css
二、上代碼html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <!-- 根據屏幕自動響應佈局 --> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title> {# 用來放標題 #} {% block title %} {% endblock %} </title> {# 加載css代碼 #} <link rel="stylesheet" href="{% static 'bootstrap4.1/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static 'css/base.css' %}"> {# js代碼放在後面能夠增長性能 #} <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script> <script src="{% static 'bootstrap4.1/popper.min.js' %}"></script> <script src="{% static 'bootstrap4.1/bootstrap.min.js' %}"></script> {% block header_extends %} {# 用來作頭部擴展,如加載某些靜態文件 #} {% endblock %} </head> <body> {# 導航欄 #} <nav class="navbar navbar-expand-lg navbar-light bg-light sticky-top"> <a class="navbar-brand" href="{% url 'home' %}">Felix Blog</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 nav-home"><a href="{% url 'home' %}" class="nav-link">首頁</a></li> <li class="nav-item nav-blog"><a href="{% url 'blog_list' %}" class="nav-link">博客</a></li> </ul> <ul class="navbar-nav"> {% if not user.is_authenticated %} <li class="nav-item"> <a class="nav-link" href="{% url 'login' %}?from={{ request.get_full_path }}">登陸</a> </li> <li class="nav-item"> <a class="nav-link" href="{% url 'register' %}?from={{ request.get_full_path }}">註冊</a> </li> {% else %} <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ user.username }} {% if user.has_nickname %} ({{ user.get_nickname }}) {% endif %} </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="{% url 'user_info' %}">我的資料</a> <a class="dropdown-item" href="{% url 'change_password' %}">修改密碼</a> {% if user.is_staff or user.is_superuser %} <a class="dropdown-item" href="{% url 'admin:index' %}">後臺管理</a> {% endif %} <div class="dropdown-divider"></div> <a class="dropdown-item" href="{% url 'logout' %}?from={{ request.get_full_path }}">登出</a> </div> </li> {% endif %} </ul> </div> </nav> {# 用來放內容 #} {% block content %} {% endblock %} <!-- Modal 登陸模態框 --> <div class="modal fade" id="login_model" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <form id="login_model_form" action="" method="post"> <div class="modal-header"> <h5 class="modal-title">登陸</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> {% csrf_token %} {% for field in login_model_form %} <label for="{{ field.id_for_label }}">{{ field.label }}</label> {{ field }} {% endfor %} <span id="login_model_tip" class="text-danger"></span> </div> <div class="modal-footer"> <button type="submit" class="btn btn-primary">登陸</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">關閉</button> </div> </form> </div> </div> </div> <script> $('#login_model_form').submit(function (event) { $('#login_model_tip').text(''); event.preventDefault(); // 阻止原事件提交 $.ajax({ url: '{% url 'login_for_model' %}', type: 'POST', data: $(this).serialize(), cache: false, success: function (data) { if (data['status'] === 'SUCCESS') { window.location.reload(); } else { $('#login_model_tip').text('用戶名或密碼不正確') } } }); }) </script> {# 導入資源建議放在js代碼前 #} {# 用來放js代碼 #} {% block js %} {% endblock %} </body> </html>
{% extends 'form.html' %} {% block other-buttons %} <div id="send_code" class="btn btn-primary">發送驗證碼</div> {% endblock %} {% block js %} <script> $("#send_code").click(function () { if ($(this).hasClass('disabled')) { return false; } let email = $('#id_email').val(); if (email === '') { $('#error-tip').text('郵箱不能爲空'); return false } let re_email = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/; if (!re_email.test(email)) { alert('郵箱格式不正確'); return false } // 發送驗證碼 $.ajax({ url: "{% url 'send_verification_code' %}", type: 'GET', data: { 'email': email, 'send_for':'bind_email_code', }, cache: false, success: function (data) { if (data['status'] === 'ERRORS') { alert(data['msg']); } else { alert(data['msg']); } } }); // # 把按鈕變灰 $(this).addClass('disabled'); $(this).attr("disabled", true); let time = 60; let interval = setInterval(() => { time -= 1; $(this).text(`再次發送(${time}s)`); if (time <= 0) { // 時間等於0,進行復原 clearInterval(interval); $(this).removeClass('disabled'); $(this).attr('disabled', false); $(this).text('再次發送'); return false; } }, 1000); }); </script> {% endblock %}
{% extends 'form.html' %} {% block other-buttons %} <div id="send_code" class="btn btn-primary">發送驗證碼</div> {% endblock %} {% block js %} <script> $("#send_code").click(function () { if ($(this).hasClass('disabled')) { return false; } let email = $('#id_email').val(); if (email === '') { $('#error-tip').text('郵箱不能爲空'); return false } let re_email = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/; if (!re_email.test(email)) { alert('郵箱格式不正確'); return false } // 發送驗證碼 $.ajax({ url: "{% url 'send_verification_code' %}", type: 'GET', data: { 'email': email, 'send_for': 'forgot_password_code', }, cache: false, success: function (data) { if (data['status'] === 'ERRORS') { alert(data['msg']); } else { alert(data['msg']); } } }); // # 把按鈕變灰 $(this).addClass('disabled'); $(this).attr("disabled", true); let time = 60; let interval = setInterval(() => { time -= 1; $(this).text(`再次發送(${time}s)`); if (time <= 0) { // 時間等於0,進行復原 clearInterval(interval); $(this).removeClass('disabled'); $(this).attr('disabled', false); $(this).text('再次發送'); return false; } }, 1000); }); </script> {% endblock %}
{% extends 'base.html' %} {% block title %} 個人博客|登陸 {% endblock %} {% block content %} <div class="container"> <div class="col-xl-6 offset-xl-3"> {% if not user.is_authenticated %} <div class="card"> <h5 class="card-header">登陸</h5> <div class="card-body"> <form action="" method="post"> {% csrf_token %} {% for field in login_form %} <label for="{{ field.id_for_label }}">{{ field.label }}</label> {{ field }} <p class="text-danger">{{ field.errors.as_text }}</p> {% endfor %} <span class="text-danger float-left">{{ login_form.non_field_errors }}</span> <div class="clearfix"></div> <a class="float-left" href="{% url 'forgot_password' %}">忘記密碼?</a> <input type="submit" value="登陸" class="btn btn-primary float-right"> </form> </div> </div> {# 未登陸跳轉到首頁 #} {% else %} <script> window.location.href = '{% url 'home' %}' </script> {% endif %} </div> </div> {% endblock %} {% block js %} {# 將首頁這個按鈕設置激活狀態 #} <script> $(".nav-home").addClass("active").siblings().removeClass("active"); </script> {% endblock %}
{% extends 'base.html' %} {% block title %} 個人博客|註冊 {% endblock %} {% block content %} <div class="container"> {% if not user.is_authenticated %} <div class="col-xl-6 offset-xl-3"> <div class="card"> <h5 class="card-header">註冊</h5> <div class="card-body"> <form action="{% url 'register' %}" method="post"> {% csrf_token %} {% for field in reg_form %} <label for="{{ field.id_for_label }}">{{ field.label }}</label> {{ field }} <p class="text-danger">{{ field.errors.as_text }}</p> {% endfor %} <span class="text-danger">{{ login_form.non_field_errors }}</span> <span id="error-tip" class="text-danger">{{ form.non_field_errors }}</span> <div class="clearfix"></div> <div id="send_code" class="btn btn-primary float-left">發送驗證碼</div> <input type="submit" value="註冊" class="btn btn-primary float-right"> </form> </div> </div> {% else %} <script> window.location.href = '{% url 'home' %}' </script> {% endif %} </div> </div> {% endblock %} {% block js %} {# 將首頁這個按鈕設置激活狀態 #} <script> $(".nav-home").addClass("active").siblings().removeClass("active"); </script> <script> $("#send_code").click(function () { if ($(this).hasClass('disabled')) { return false; } let email = $('#id_email').val(); if (email === '') { $('#error-tip').text('郵箱不能爲空'); return false } let re_email = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/; if (!re_email.test(email)) { alert('郵箱格式不正確'); return false } // 發送驗證碼 $.ajax({ url: "{% url 'send_verification_code' %}", type: 'GET', data: { 'email': email, 'send_for': 'register_code', }, cache: false, success: function (data) { if (data['status'] === 'ERRORS') { alert(data['msg']); } else { alert(data['msg']); } } }); // # 把按鈕變灰 $(this).addClass('disabled'); $(this).attr("disabled", true); let time = 60; let interval = setInterval(() => { time -= 1; $(this).text(`再次發送(${time}s)`); if (time <= 0) { // 時間等於0,進行復原 clearInterval(interval); $(this).removeClass('disabled'); $(this).attr('disabled', false); $(this).text('再次發送'); return false; } }, 1000); }); </script> {% endblock %}
{% extends 'base.html' %} {% block title %} 我的資料 {% endblock %} {% block content %} <div class="container"> <div class="col-xl-8 offset-xl-2"> <h2>{{ user.username }}</h2> {% if user.is_authenticated %} <ul> <li>暱稱:{{ user.get_nickname }} <a href="{% url 'change_nickname' %}?from={{ request.get_full_path }}">修改暱稱</a></li> <li> 郵箱: {% if user.email %} {{ user.email }} {% else %} 未綁定 <a href="{% url 'bind_email' %}?from={{ request.get_full_path }}">綁定郵箱</a> {% endif %} </li> <li>上一次登陸時間:{{ user.last_login|date:"Y-m-d H:i:s" }}</li> <li><a href="{% url 'change_password' %}">修改密碼</a></li> </ul> {% else %} {# 未登陸跳轉到首頁 #} <script> window.location.href = '{% url 'home' %}' </script> {% endif %} </div> </div> </div> {% endblock %} {% block js %} {# 將首頁這個按鈕設置激活狀態 #} <script> $(".nav-home").addClass("active").siblings().removeClass("active"); </script> {% endblock %}
# -*- coding: utf-8 -*-
# @Time : 18-11-20 下午8:10
# @Author : Felix Wang
import re
from django import forms
from django.contrib import auth
from django.contrib.auth.models import User
class LoginForm(forms.Form):
username_or_email = forms.CharField(label='用戶名', required=True,
widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': '請輸入用戶名或郵箱'}))
# widget指定input標籤類型
password = forms.CharField(label='密碼',
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '請輸入密碼'}))
def clean(self): # 驗證數據
username_or_email = self.cleaned_data['username_or_email']
password = self.cleaned_data['password']
user = auth.authenticate(username=username_or_email, password=password)
if user is None:
# 使用郵箱登陸
if User.objects.filter(email=username_or_email).exists():
username = User.objects.get(email=username_or_email).username
user = auth.authenticate(username=username, password=password)
if user is not None:
self.cleaned_data['user'] = user
return self.cleaned_data
raise forms.ValidationError('用戶名或密碼錯誤')
else:
self.cleaned_data['user'] = user # 將驗證過的user放入clean_data
return self.cleaned_data
class RegisterForm(forms.Form):
# 用戶名字段
username = forms.CharField(label='用戶名',
max_length=30,
min_length=3,
required=True,
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '請輸入用戶名'}))
# 郵箱字段
email = forms.EmailField(label='郵箱',
min_length=3,
required=True,
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '請輸入郵箱'}))
verification_code = forms.CharField(
label='驗證碼',
max_length=20,
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': '請輸入驗證碼',
}
)
)
# 密碼字段
password = forms.CharField(label='密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請輸入密碼'}))
# 再次輸入密碼
password_again = forms.CharField(label='確認密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請再輸入一次密碼'}))
def __init__(self, *args, **kwargs):
if 'requests' in kwargs:
self.requests = kwargs.pop('requests')
super().__init__(*args, **kwargs)
def clean_username(self):
username = self.cleaned_data['username']
if User.objects.filter(username=username).exists():
raise forms.ValidationError('用戶名已存在')
return username
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError('郵箱已存在')
if not re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', email):
raise forms.ValidationError('郵箱格式錯誤')
return email
def clean_password_again(self):
password = self.cleaned_data['password']
password_again = self.cleaned_data['password_again']
if password != password_again:
raise forms.ValidationError('兩次輸入的密碼不一致')
return password_again
def clean_verification_code(self):
verification_code = self.cleaned_data.get('verification_code', '').strip().upper()
if verification_code == '':
raise forms.ValidationError('驗證碼不能爲空')
code = self.requests.session.get('register_code', '').upper()
if code != verification_code or code == '':
raise forms.ValidationError('驗證碼不正確')
return verification_code
class ChangeNicknameForm(forms.Form):
nickname_new = forms.CharField(
label='新的暱稱',
max_length=20,
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': '請輸入新的暱稱',
}
)
)
def __init__(self, *args, **kwargs):
if 'user' in kwargs:
self.user = kwargs.pop('user')
super().__init__(*args, **kwargs)
# 表單驗證
def clean(self):
# 判斷用戶是否登陸
if self.user.is_authenticated:
self.cleaned_data['user'] = self.user
else:
raise forms.ValidationError('用戶還沒有登陸')
return self.cleaned_data
def clean_nickname_new(self):
nickname_new = self.cleaned_data.get('nickname_new', '').strip()
if nickname_new == '':
raise forms.ValidationError('新的暱稱不能爲空')
return nickname_new
class BindEmailForm(forms.Form):
email = forms.EmailField(
label='郵箱',
widget=forms.EmailInput(
attrs={
'class': 'form-control',
'placeholder': '請輸入郵箱',
}
)
)
verification_code = forms.CharField(
label='驗證碼',
max_length=20,
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': '請輸入驗證碼',
}
)
)
def __init__(self, *args, **kwargs):
if 'requests' in kwargs:
self.requests = kwargs.pop('requests')
super().__init__(*args, **kwargs)
# 表單驗證
def clean(self):
# 判斷用戶是否登陸
if self.requests.user.is_authenticated:
self.cleaned_data['user'] = self.requests.user
else:
raise forms.ValidationError('用戶還沒有登陸')
# 判斷用戶是否已經綁定郵箱
if self.requests.user.email != '':
raise forms.ValidationError('你已經綁定郵箱')
# 判斷驗證碼
code = self.requests.session.get('bind_email_code', '').upper()
verification_code = self.cleaned_data.get('verification_code', '').upper()
if code != verification_code or code == '':
raise forms.ValidationError('驗證碼不正確')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError('該郵箱已經被綁定')
if not re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', email):
raise forms.ValidationError('郵箱格式錯誤')
return email
def clean_verification_code(self):
verification_code = self.cleaned_data.get('verification_code', '').strip().upper()
if verification_code == '':
raise forms.ValidationError('驗證碼不能爲空')
return verification_code
class ChangePasswordForm(forms.Form):
old_password = forms.CharField(label='舊的密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請輸入舊的密碼'}))
new_password = forms.CharField(label='新的密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請輸入新的密碼'}))
new_password_again = forms.CharField(label='請再次輸入新的密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請再次輸入新的密碼'}))
def __init__(self, *args, **kwargs):
if 'user' in kwargs:
self.user = kwargs.pop('user')
super().__init__(*args, **kwargs)
def clean(self):
# 驗證新密碼是否一致
new_password = self.cleaned_data.get('new_password', '').strip()
new_password_again = self.cleaned_data.get('new_password_again', '').strip()
if new_password != new_password_again or new_password == '':
raise forms.ValidationError('兩次輸入密碼不一致')
return self.cleaned_data
def clean_old_password(self):
# 驗證舊的密碼是否正確
old_password = self.cleaned_data.get('old_password', '').strip()
if not self.user.check_password(old_password):
raise forms.ValidationError('舊的密碼錯誤')
return old_password
class ForgotPasswordForm(forms.Form):
email = forms.EmailField(label='郵箱',
min_length=3,
required=True,
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '請輸入綁定過的郵箱'}))
verification_code = forms.CharField(
label='驗證碼',
max_length=20,
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': '請輸入驗證碼',
}
)
)
new_password = forms.CharField(label='密碼',
min_length=6,
required=True,
widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': '請輸入密碼'}))
def __init__(self, *args, **kwargs):
if 'requests' in kwargs:
self.requests = kwargs.pop('requests')
super().__init__(*args, **kwargs)
def clean_email(self):
email = self.cleaned_data['email'].strip()
if not User.objects.filter(email=email).exists():
raise forms.ValidationError('郵箱不存在')
return email
def clean_verification_code(self):
verification_code = self.cleaned_data.get('verification_code', '').strip().upper()
if verification_code == '':
raise forms.ValidationError('驗證碼不能爲空')
code = self.requests.session.get('forgot_password_code', '').upper()
if code != verification_code or code == '':
raise forms.ValidationError('驗證碼不正確')
return verification_code
from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) nickname = models.CharField(max_length=20, verbose_name='暱稱', default='') def __str__(self): return '<Profile: {} for {}>'.format(self.nickname, self.user.username) def get_nickname(self): if Profile.objects.filter(user=self).exists(): profile = Profile.objects.get(user=self) return profile.nickname else: return '' def get_nickname_or_username(self): if Profile.objects.filter(user=self).exists(): profile = Profile.objects.get(user=self) return profile.nickname else: return self.username def has_nickname(self): if Profile.objects.filter(user=self).exists(): profile = Profile.objects.get(user=self) return True if profile.nickname.strip() else False return False User.get_nickname = get_nickname # 動態綁定方法 User.has_nickname = has_nickname # 動態綁定方法 User.get_nickname_or_username = get_nickname_or_username # 動態綁定方法
# -*- coding: utf-8 -*- # @Time : 18-11-4 下午5:22 # @Author : Felix Wang from django.urls import path from . import views urlpatterns = [ path('login/', views.login, name='login'), # 登陸 path('logout/', views.logout, name='logout'), # 登陸 path('login_for_model/', views.login_for_model, name='login_for_model'), # 登陸 path('register/', views.register, name='register'), # 註冊 path('user_info/', views.user_info, name='user_info'), # 用戶信息 path('change_nickname/', views.change_nickname, name='change_nickname'), # 更改暱稱 path('bind_email/', views.bind_email, name='bind_email'), # 更改暱稱 path('send_verification_code/', views.send_verification_code, name='send_verification_code'), # 更改暱稱 path('change_password/', views.change_password, name='change_password'), # 更改密碼 path('forgot_password/', views.forgot_password, name='forgot_password'), # 更改密碼 ]
# -*- coding: utf-8 -*- # @Time : 18-11-7 下午4:12 # @Author : Felix Wang import random import re import time from django.shortcuts import render, redirect from django.http import JsonResponse from django.contrib import auth from django.contrib.auth.models import User from django.urls import reverse from django.conf import settings from .forms import LoginForm, RegisterForm, ForgotPasswordForm, ChangeNicknameForm, BindEmailForm, ChangePasswordForm from .models import Profile from myblog.utils import AutoSendEmail def login(requests): # 若是是form表單提交驗證登陸 if requests.method == 'POST': login_form = LoginForm(requests.POST) if login_form.is_valid(): # 驗證是否經過 # 由於在form表單驗證過了,因此不用本身再驗證 user = login_form.cleaned_data.get('user') auth.login(requests, user) return redirect(requests.GET.get('from', reverse('home'))) else: login_form.add_error(None, '用戶名或密碼不正確') else: login_form = LoginForm() context = { 'login_form': login_form, } return render(requests, 'user/login.html', context) def login_for_model(requests): login_form = LoginForm(requests.POST) # 若是是form表單提交驗證登陸 if login_form.is_valid(): # 驗證是否經過 # 由於在form表單驗證過了,因此不用本身再驗證 user = login_form.cleaned_data.get('user') auth.login(requests, user) data = { 'status': 'SUCCESS', } else: data = { 'status': 'ERROR', } return JsonResponse(data) def register(requests): if requests.method == 'POST': reg_form = RegisterForm(requests.POST, requests=requests) if reg_form.is_valid(): username = reg_form.cleaned_data['username'] email = reg_form.cleaned_data['email'] password = reg_form.cleaned_data['password'] # 建立用戶 user = User.objects.create_user(username=username, email=email, password=password) user.save() # 登陸用戶 user = auth.authenticate(username=username, password=password) auth.login(requests, user) # 註冊成功否刪除保存的驗證碼 del requests.session['register_code'] # 登陸以後跳轉 return redirect(requests.GET.get('from', reverse('home'))) else: reg_form = RegisterForm() context = { 'reg_form': reg_form, } return render(requests, 'user/register.html', context) def logout(requests): auth.logout(requests) return redirect(requests.GET.get('from', reverse('home'))) def user_info(requests): context = {} return render(requests, 'user/user_info.html', context) def change_nickname(requests): redirect_to = requests.GET.get('from', reverse('home')) if requests.method == 'POST': form = ChangeNicknameForm(requests.POST, user=requests.user) if form.is_valid(): nickname_new = form.cleaned_data['nickname_new'] profile, created = Profile.objects.get_or_create(user=requests.user) profile.nickname = nickname_new profile.save() return redirect(redirect_to) else: form = ChangeNicknameForm() context = { 'submit_text': '修改', 'page_title': '修改暱稱', 'form_title': '修改暱稱', 'form': form, 'return_back_url': redirect_to, } return render(requests, 'form.html', context) def bind_email(requests): redirect_to = requests.GET.get('from', reverse('home')) if requests.method == 'POST': form = BindEmailForm(requests.POST, requests=requests) if form.is_valid(): email = form.cleaned_data['email'] requests.user.email = email requests.user.save() # 綁定成功後刪除驗證碼 del requests.session['bind_email_code'] return redirect(redirect_to) else: form = BindEmailForm() context = { 'submit_text': '綁定郵箱', 'page_title': '綁定郵箱', 'form_title': '綁定', 'form': form, 'return_back_url': redirect_to, } return render(requests, 'user/bind_email.html', context) def send_verification_code(requests): email = requests.GET.get('email', '') send_for = requests.GET.get('send_for', '') if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', email): # 生成驗證碼 all_codes = list(range(0x30, 0x39)) + list(range(0x61, 0x74)) + list(range(0x41, 0x5a)) # 大寫,小寫和數字 code = ''.join([chr(random.choice(all_codes)) for i in range(6)]) now = int(time.time()) send_code_time = requests.session.get('send_code_time', 0) if now - send_code_time < 60: data = { 'status': 'ERROR', } else: requests.session[send_for] = code requests.session['send_code_time'] = send_code_time title = '驗證碼' auto_email = AutoSendEmail(sender=settings.EMAIL_HOST_USER, recever=[email], password=settings.EMAIL_HOST_PASSWORD, title=title, from_who=settings.FROM_WHO, smtp_server=settings.MAIL_HOST, port=settings.EMAIL_PORT) html = """ <html> <head></head> <body> <p>Hi!<br> 很是感謝您綁定郵箱! <br> 本次的驗證碼是:{},請不要透露給其餘人! <br> </p> <img style="width:180px;height:240px" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1541440161574&di=fd6156e441788866ffbd6c654d75fa23&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201507%2F22%2F20150722222322_Ky8Nj.jpeg" /> </body> </html> """.format(code) # 以html的形式發送文字,推薦這個,由於能夠添加圖片等 auto_email.addHtml(html) # 發送郵件 try: auto_email.sendEmail() data = { 'status': 'SUCCESS', 'msg': '郵件發送成功', } except Exception as e: print(str(e)) data = { 'status': 'ERRORS', 'msg': '郵件發送失敗', } else: data = { 'status': 'ERRORS', 'msg': '郵箱格式不正確', } return JsonResponse(data) def change_password(requests): redirect_to = reverse('home') if requests.method == 'POST': form = ChangePasswordForm(requests.POST, user=requests.user) if form.is_valid(): new_password = form.cleaned_data['new_password'] profile, created = Profile.objects.get_or_create(user=requests.user) profile.user.set_password(new_password) profile.user.save() # 密碼修改爲功後登出 auth.logout(requests) return redirect(redirect_to) else: form = ChangePasswordForm() context = { 'submit_text': '修改', 'page_title': '修改密碼', 'form_title': '修改密碼', 'form': form, 'return_back_url': redirect_to, } return render(requests, 'form.html', context) def forgot_password(requests): redirect_to = reverse('login') if requests.method == 'POST': form = ForgotPasswordForm(requests.POST, requests=requests) if form.is_valid(): email = form.cleaned_data['email'] new_password = form.cleaned_data['new_password'] user = User.objects.get(email=email) user.set_password(new_password) user.save() # 綁定成功後刪除驗證碼 del requests.session['forgot_password_code'] return redirect(redirect_to) else: form = ForgotPasswordForm() context = { 'submit_text': '重置密碼', 'page_title': '重置密碼', 'form_title': '重置', 'form': form, 'return_back_url': redirect_to, } return render(requests, 'user/forgot_password.html', context)