# =====> 用戶注冊與登錄|找回密碼 1.頁面沒有邏輯操作 from django.views.generic import TemplateView urlpatterns = [ url(r'^$', TemplateView.as_view(template_name="index.html")) ] # 如果頁面有邏輯操作就需要配置視圖函數; from django.shortcuts import render def user_login(requet): if request.method == "POST": user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") 2.authenticate用戶認證方法 from django.contrib.auth import authenticate,login # 驗證用戶名密碼是否正確 user = authenticate(username=user_name, password=pass_word) # login()方法 if user is not None: login(request, user) return render(request, "index.html", locals()) else: return render(request, "login.html", locals()) # ======================================>>index.html # ----->>> 在登錄成功之后跳轉首頁 # 注冊與登錄的form就變成了登錄狀態,需要在前端做判斷; {% if request.user.is_authenticated %} ... {% else %} ... {% endif %} # =================================================== elif request.method == "GET": return render(request, "login.html", locals()) 3.自定義后台auth認證方法-->>> 通過郵箱或者用戶名登錄 # ①在settings.py文件中重載變量 AUTHENTICATION_BACKENDS = ( 'users.views.CustomBackend', # 自定義類 ) # ②自定義認證方法 from django.contrib.auth.backends import ModelBakend # UserProfile是用戶表 from .models import UserProfile # 將這個類配置到settings.py文件中 from django.db.models import Q class CustomerBackend(ModelBackend): # 傳入兩個關鍵詞參數 def authenticate(self, username=None, password=None, **kwargs): try: user = UserProfile.objects.get(Q(username=username)|Q(email=username)) # 存在數據庫的用戶名是加密的,所有不能get # 通過user中的check_password()方法,檢測密碼是否正確 if user.check_password(password): # 用戶名密碼正確,返回user對象 return user # 如果get不到數據,或者多個數據,就返回異常 except Exception as e: return None 4.基於類的用戶登錄 # views.py from django.views.generic.base imoprt View # View這視圖類中,有類似http的get,post等方法 class LoginView(View): def get(self, request): return render(request, "login.html", locals()) def post(self, request): user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, "index.html") else: return render(request, "login.html", {"msg":"用戶名密碼錯誤"}) # urls.py from django.views.generic import TemplateView urlpatterns = [ url(r'login/$', LoginView.as_view(), name="login") ] 5.form表單驗證 # ①myforms.py from django import forms class LoginForm(forms.Form): username = forms.CharField( required=True, ) password = forms.CharField( required=True, ) # 將驗證成功之后的業務邏輯添加到視圖中 # ②views.py from django.views.generic.base imoprt View # View這視圖類中,有類似http的get,post等方法 class LoginView(View): def get(self, request): return render(request, "login.html", locals()) def post(self, request): # 創建表單對象 login_form = LoginForm(request.POST) if login_form.is_valid(): user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: # 執行登錄 login(request, user) return render(request, "index.html") else: # 登錄不成功 return render(request, "login.html", {"msg":"用戶名密碼錯誤"}) else: # 同時返回表單驗證錯誤信息 return render(request, "login.html", {'login_form':login_form}) 6.django中login()函數實現的原理 # session&cookie # 請看相關博客補充 7.注冊功能 # 1.顯示注冊頁面 # views.py from django.views.generic.base import View class RegisterView(View): def get(self, request): return render(request, "register.html", locals()) # urls.py from django.views.generic import TemplateView urlpatterns = [ url(r'register', RegisterView.as_view(), name="register") ] # 2.用於生成圖片驗證碼的第三方庫django-simple-captcha==0.4.6 pip install django-simple-captcha==0.4.6 # 添加到應用配置中 'captcha' # 遷移生成表 # 配置urlconf # 3.RegisterForm注冊表單驗證 from django import forms from captcha.field import CaptchaField class RegisterForm(forms.Form): email = forms.EmailField( required=True ) password = forms.CharField( required=True ) # 驗證碼input框 captcha = CharField( error_messages={"invalid":"驗證碼錯誤"} ) # 4.在視圖中操作表單驗證邏輯 # views.py from django.views.generic.base import View from .myform import RegisterForm class RegisterView(View): def get(self, request): register_form = RegisterForm() return render(request, "register.html", locals()) def post(self, request): register_form = RegisterForm(request.POST) # 如果格式校驗成功 if register_form.is_valid(): # 注冊流程 # 取出表單輸入數據 user_name = request.POST.get("email", "") # 判斷用戶名是否存在 if UserProfile.objects.filter(email=user_name): return render(request, "register.html", {'register_form':register_form}, {'msg':'用戶已經存在'}) else: password = request.POST.get("password", "") # 創建模型類對象,給將數據存入數據庫中 user_profile = UseProfile() user_profile.username = user_name user_profile.email = user_name # 數據庫中is_active字段來表示是否激活的狀態 user_profile.is_active = False # 密碼加密 from django.contrib.auth.hashers import make_password user_profile.password = make_password(pass_word) user_profile.save() # 發送郵箱激活鏈接 send_register_email(user_name, 'register') # 發送成功 return render(request, "login.html) else: return render(request, "register.html", {'register_form':register_form}) # register.html # 驗證碼input框 {{ register_form.captcha }} # 5.發送郵箱激活鏈接 # 新建utils->email_send.py from users.models import EmailVerifyRecord def send_register_email(email, send_type='register'): # 創建驗證碼對象 email_record = EmailVerifyRecord() # 生成四個隨機字符串 random_str = random_str(16) # 將發送郵件的字段數據事先保存到數據庫中 email_record.code = code email_recode.email = email email_recode.send_type = send_type email_recode.save() # 定義文件內容 email_title = "" email_body = "" if send_type == "0": email_title = "" email_body = "點擊下面鏈接激活賬號:http://127.0.0.1:8000/active/{0}.format(code)" # 使用django內部函數直接發送郵件 from django.core.mail import send_mail from 項目.settings import EMAIL_FROM # 參數:subject, message, from_email, recipient_list... send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果發送成功 if send_status: pass # 06-10 視頻=======-=-=-=-=-=-=||||||||||||||||||||||||||||||~~~~~~~ # ===========================>>> 在settings.py文件中寫入發送配置 EMAIL_HOST = "smtp.sina.com" # 復制相關郵箱客戶端SMTP服務器的地址 EMAIL_PORT = 25 EMAIL_HOST_USER = "公司郵箱@sina.com" EMAIL_HOST_PASSWORD = "*****密碼" EMAIL_USE_TLS = False EMAIL_FROM = "公司郵箱@sina.com" # ============================================================== # 生成隨機字符串的函數 import random def random_str(num) code = '' for i in range(num): add = random.choice([random.randrange(10), chr(random.randrange(65,91))]) code+=str(add) return code # EmailVerifyRecord表結構 # models.py class EmailVerifyRecord(models.Model): code = models.CharField(max_length=20, verbose_name="驗證碼") email = models.EmailField(max_length=50, verbose_name="郵箱") send_type = models.CharField( verbose_name="驗證碼類型", choices=( ('register', "注冊"), ('find', "找回密碼") ) ) send_time = models.DateTimeField(verbose_name="發送時間", default=datetime.time()) # 6.激活郵箱 # urls.py url(r'^active/(?P<active_code>.*)/$', ActiveUserView.as_view(), name='user_active') # views.py class ActiveUserView(View): def get(self, request, active_code): all_records = EmailVerifyRecord.objects.filter(code=active_code) if all_records: for record in all_records: email = record.email user = UserProfile.objects.get(email=email) user.is_active = True user.save() else: # 如果數據庫中沒有獲取到active_code return render(request , 'register_fail.html') return render(request, "login.html") # 再到登錄login視圖中,添加是否激活is_active的條件 from django.views.generic.base imoprt View # View這視圖類中,有類似http的get,post等方法 class LoginView(View): def get(self, request): return render(request, "login.html", locals()) def post(self, request): # 創建表單對象 login_form = LoginForm(request.POST) if login_form.is_valid(): user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: # 表示已激活 if user.is_active: # 執行登錄 login(request, user) return render(request, "index.html") else: return render(request, "login.html", {"msg":"用戶名未激活"}) else: # 登錄不成功 return render(request, "login.html", {"msg":"用戶名密碼錯誤"}) else: # 同時返回表單驗證錯誤信息 return render(request, "login.html", {'login_form':login_form}) 8.找回用戶密碼 # 1.點擊找回密碼,頁面提示輸入用戶名密碼; # 2.提交之后后台發送重置密碼的鏈接; # 3.重置密碼之后跳轉登錄頁面; # ----------->> 1.發送重置密碼鏈接 # views.py class ForgetPwdView(View): def get(self, request): # 實例化form表單對象 forget_form = ForgetForm() return render(request, "forgetpwd.html", {'forget_form':forget_form}) def post(self, request): # 實例化form表單對象 forget_form = ForgetForm(request.POST) if forget_form.is_valid(): email = request.POST.get() send_register_email(email, 'find') return render(request, "send_success.html") else: # 如果表單驗證失敗 return render(request, "forgetpwd.html", {'forget_form':forget_form}) # ------>>> email_send.py # ==================================== elif send_type == "find": email_title = "在線注冊密碼重置鏈接" email_body = "請點擊下面的鏈接重置密碼:http://127.0.0.1:8000/reset/{0}.format(code)" send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) if send_status: pass # ==================================== # urls.py url(r'^forget/$', ForgetPwdView.as_view(), name="forget_pwd") # myform.py class ForgetForm(forms.Form): email = forms.EmailField(required=True) captcha = CaptchaField(error_messages={"invalid":"驗證碼錯誤"}) # forgetpwd.html {{ forget_form.captcha}} # send_success.html <p>郵件發送成功!</p> # ----------->> 2.重置密碼 # urls.py url(r'^reset/(?P<active_code>.*)/$', ResetView.as_view, name='reset_pwd') # views.py class ResetView(View): def get(self, request, active_code): all_records = EmailVerifyRecord.objects.filter(code=active_code) if all_records: for record in all_records: email = record.email return render(request , 'password_reset.html', {'email':email}) else: # 如果數據庫中沒有獲取到active_code return render(request , 'register_fail.html') return render(request, "login.html") # reset.html # 添加一個隱藏的輸入框,給后台傳遞郵箱地址 <input type="hidden" value="{{email}}"> # myform.py class ModifyPwdForm(forms.Form): password1 = forms.CharField(required=True, min_length=5) password2 = forms.CharField(required=True, min_length=5) # post請求處理修改驗證碼的邏輯 from .myforms import ModifyPwdForm class ModifyPwdView(View): # 重新定義一個form表單類,而不是在ResetView中繼續操作; # 因為RestView需要傳入一個active_code參數; def post(self, request): modify_forms = ModifyPwdForm(request.POST) if modify_form.is_valid(): pwd1 = request.POST.get("password1", "") pwd2 = request.POST.get("password2", "") email = request.POST.get("email", "") if pwd1 != pwd2: return render(request, "password_reset.html", {"email":email}) user = UserProfile.objects.get(email=email) user.password = make_password(pwd2) user.save() return render(request, "login.html") else: email = request.POST.get("email", "") return render(request, "password_reset.html", {"email":emial, "modify_form":modify_form}) # urls.py url(r'^modify_pwd', ModifyPwdView.as_view(), name="modify_pwd") # password_reset.htl ...action="{% url 'modift_pwd' %}" # 遺留問題:1.添加一個email_verify字段,表示這個鏈接是否用過, # 在user.save()之后,設置email_verify=True; # 再次點擊就告訴用戶,密碼已經修改過了或者失效; # 2.給驗證碼設置過期時間;