static資源文件
首先把static文件夾粘貼到項(xiàng)目中,
注意一定要在pycharm中進(jìn)行粘貼,否則可能無效。

配置static資源文件
STATIC_URL = '/static/' //在html頁面引用時(shí)要使用這個(gè)內(nèi)容
#添加:
#配置靜態(tài)資源
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'), //與目錄名稱相同
]
模板html
把index.html和login.html粘貼到templates文件夾下:

配置html與static資源文件關(guān)聯(lián)
打開index.html,按ctrl+r鍵,批量替換replace all代碼。
這是django自帶的路徑特性--- /static/***
./static --> /static

login.html同理替換。
顯示頁面
index.html
上一步我們關(guān)聯(lián)了html頁面和static靜態(tài)資源文件,
所以要先配置url和view,否則django不會(huì)識(shí)別關(guān)聯(lián)的路徑特性---/static/
(1)使用之前的方法
我們直接在MXOnline/urls.py下進(jìn)行配置:
from apps.users import views
#相比于django1.8,2.2版本的url配置相對(duì)簡(jiǎn)單。
path('',views.index),
編寫視圖view:
打開apps/user/views.py文件
def index(request):
return render(request,'index.html')
啟動(dòng)項(xiàng)目:
127.0.0.1:8000

(2)使用新的方法
在django中為了開發(fā)方便,已經(jīng)有了為顯示模板的一些類,我們直接拿過來調(diào)用即可,不用再自定義視圖函數(shù)進(jìn)行顯示了。
打開MXOnline/urls.py:
from django.contrib import admin
from django.urls import path
import xadmin
from apps.users import views
#導(dǎo)入TemplatesView
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('xadmin/',xadmin.site.urls),
#之前的方法
# path('',views.index),
#新的方法
path('',TemplateView.as_view(template_name='index.html'),name='index')
]

再次啟動(dòng)項(xiàng)目,進(jìn)入127.0.0.1:8000:

一樣的效果。
login.html
login--登錄頁面也很特殊,網(wǎng)站中必備,所以django也自帶了一些類和方法供我們使用。
上一步中的index頁面,在右上角有一個(gè)的登錄按鈕,當(dāng)我點(diǎn)擊它時(shí),會(huì)出現(xiàn):

這是由于我們還沒有在url中進(jìn)行配置它。
(1)django自帶類及方法實(shí)現(xiàn)login頁面的顯示以及驗(yàn)證
打開index.html,修改登錄按鈕的跳轉(zhuǎn)url為:
#點(diǎn)擊登錄,會(huì)重新進(jìn)入url進(jìn)行匹配
<a href = '{% url 'login' %}'>登錄</a>

配置url
打開MXOnline/urls.py:
#必須加name = '*****'否則會(huì)報(bào)login是無效的視圖函數(shù)等等。
path('login/',LoginView.as_view(),name = 'login)
所以我們給要加上name = ‘名稱’。

views
打開apps/users/views.py:
from django.shortcuts import render
#導(dǎo)入View
from django.views.generic.base import View
#login頁面的顯示以及表單提交的處理
class LoginView(View):
#如果使用get,#點(diǎn)擊按鈕#,跳轉(zhuǎn)到login.html
def get(self,request,*args,**kwargs):
return render(request,'login.html')

當(dāng)啟動(dòng)項(xiàng)目時(shí),點(diǎn)擊右上角的登錄按鈕:


那么login.html頁面的顯示就成功了。
表單驗(yàn)證處理
首先要在login.html頁面中修改form表單的提交地址,我們還是提交到/login/中,但是,寫法要寫為:
{% url 'login' %}
提交地址的name為login,通過name到url中進(jìn)行匹配

在url中匹配后還是進(jìn)入LoginView.as_view()中。
因?yàn)閒orm表單是post提交,所以要在LoginView類中添加一個(gè)新的方法post()。
在這之前,django中內(nèi)置了一個(gè)用于防止大量不合法的登錄user的攻擊而設(shè)置的一個(gè)模塊forms.Form,所以我們?cè)趗serapp下新建一個(gè)文件form.py,用于書寫表單限制類LoginForm:
from django import forms
#用于防止大量不合理的用戶名和密碼進(jìn)行攻擊網(wǎng)站
class LoginForm(forms.Form):
'''
表單限制類:
繼承于django內(nèi)置的表單認(rèn)證模塊forms.Form,
當(dāng)用戶輸入的內(nèi)容不符合設(shè)置的要求時(shí),django內(nèi)置的form表單認(rèn)證會(huì)自動(dòng)阻擋,
并且報(bào)出視圖函數(shù)沒有返回HttpResponse對(duì)象的異常(該異常頁面可在view視圖函數(shù)中進(jìn)行重新編輯)
不會(huì)再到view的提交處理函數(shù)(LoginView.post)獲取數(shù)據(jù)。
'''
#設(shè)置用戶名必填,并且最小長(zhǎng)度為2
username = forms.CharField(required=True,min_length=2)
#密碼必填,并且最小長(zhǎng)度為3
password = forms.CharField(required=True,min_length=3)
在apps/user/view.py中編寫表單提交的處理函數(shù):
from django.shortcuts import render
# Create your views here.
from django.views.generic.base import View #View視圖
from django.http import HttpResponse,HttpResponseRedirect
from apps.users.form import LoginForm #表單驗(yàn)證
from django.contrib.auth import authenticate,login #用戶名或密碼認(rèn)證
from django.urls import reverse #重定向參數(shù)
#login.html的顯示
class LoginView(View):
#如果使用get,#點(diǎn)擊按鈕#,跳轉(zhuǎn)到login.html
def get(self,request,*args,**kwargs):
return render(request,'login.html')
#如果使用的是post,#表單提交#,那么
def post(self,request,*args,**kwargs):
'''
用戶登陸處理邏輯:
(1).實(shí)例化form.py中的表單限制類,參數(shù)為(request.POST)
(2).用戶輸入用戶名和密碼,首先進(jìn)入django內(nèi)置的合法限制類--form.py中的LoginForm類。
不合法:默認(rèn)會(huì)報(bào)出視圖函數(shù)沒有返回HttpResponse對(duì)象的異常,我們?cè)谥茍D函數(shù)中重寫頁面,
如果不合法,那么重新返回login.html頁面,并攜帶不合法的數(shù)據(jù)。不再往下進(jìn)行。
合法,通過--- 對(duì)象.cleaned_data['username/password']進(jìn)行獲取用戶輸入的數(shù)據(jù),往下將繼續(xù)進(jìn)行
(3).django內(nèi)置表單驗(yàn)證模塊,用于驗(yàn)證用戶名和密碼的方法,有兩個(gè)參數(shù)username和password
驗(yàn)證成功返回驗(yàn)證對(duì)象(數(shù)據(jù)庫中的對(duì)象),失敗則是None
(4).判斷:
如果返回的對(duì)象不為空:那么表示數(shù)據(jù)庫中有該對(duì)象,那么
通過django內(nèi)置的表單登錄方法login(request,返回的對(duì)象),
進(jìn)行登錄操作,并重定向到index頁面
如果為空:那么表示數(shù)據(jù)庫中沒有該對(duì)象,
直接返回login.html重新登陸,
并攜帶msg(用戶名或密碼錯(cuò)誤)的提示信息,以及用戶不正確的數(shù)據(jù)信息。
:param request:
:param args:
:param kwargs:
:return:
'''
#實(shí)例化LoginForm
login_form = LoginForm(request.POST)
#如果login_form表單是合法的,則獲取,不合法直接阻擋。
if login_form.is_valid():
user_name = login_form.cleaned_data['username']
pass_word = login_form.cleaned_data['password']
#django內(nèi)置用于驗(yàn)證用戶名和密碼的方法,有兩個(gè)參數(shù)username和password
#驗(yàn)證成功返回驗(yàn)證對(duì)象(數(shù)據(jù)庫中的對(duì)象),失敗則是None
user = authenticate(username=user_name,password=pass_word)
if user is not None:
#登錄模塊,接受request和成功驗(yàn)證返回的user對(duì)象
login(request,user)
#返回重定向到index頁面,然后到url中進(jìn)行匹配
return HttpResponseRedirect(reverse('index'))
else:
#如果沒有查詢到用戶,那么要求重新登陸,仍然返回login頁面
return render(request,'login.html',{'msg':'用戶名密碼錯(cuò)誤','login_form':login_form})
else:
return render(request,'login.html',{'login_form':login_form})
msg--錯(cuò)誤信息,要在html頁面上顯示,所以要對(duì)login.html進(jìn)行修改渲染數(shù)據(jù)msg:
輸入錯(cuò)誤的用戶名或者密碼時(shí):msg會(huì)被渲染出來。
當(dāng)我們填寫正確的信息后,登陸成功,返回到index頁面,發(fā)現(xiàn)index頁面并沒有發(fā)生變化,還是要進(jìn)行登錄

那么這時(shí)候我們要再index頁面中進(jìn)行判斷:
如果登陸成功,那么頁面的一些元素要發(fā)生變化,比如:

那么打開index.html:
添加if語句即可完成

總結(jié):用戶輸入username和password,點(diǎn)擊立即登錄按鈕,會(huì)通過url的name屬性進(jìn)入到view視圖的表單類中(LoginView),因?yàn)槭莗ost請(qǐng)求,所以進(jìn)入post函數(shù)中,
首先會(huì)通過django的表單合法驗(yàn)證設(shè)置的標(biāo)準(zhǔn)看是否合法(合法性標(biāo)準(zhǔn)自定義,合法反饋頁面自定義)(合法驗(yàn)證模塊定義在user/form.py中)。
如果不合法,默認(rèn)會(huì)報(bào)出沒有返回HttpResponse對(duì)象的異常,但在這里返回login.html頁面,并攜帶不合法的信息。
如果合法,通過clean_data['username/password']獲取表單信息,然后使用django內(nèi)置的表單驗(yàn)證authenticate(username=,passsword=)進(jìn)行驗(yàn)證該用戶是否注冊(cè),返回一個(gè)user對(duì)象(數(shù)據(jù)庫中)。
如果user對(duì)象不為空,表示已注冊(cè),允許登錄使用login(request,user)進(jìn)行登錄操作,返回到index頁面,并且index頁面的某些元素會(huì)被替換。
如果user對(duì)象為空,那么表示填寫的信息不正確,直接返回login頁面,并攜帶msg(錯(cuò)誤提示)和錯(cuò)誤的表單信息。
最后提交GitHub。
使用之前的方法進(jìn)行登陸驗(yàn)證
復(fù)制index和login命名為index1和login1。
首先,配置url:
path('index1/',views.index1,name = 'index1'),
path('login1/',views.login1,name = 'login1'),
在index1.html中修改登錄按鈕的鏈接地址,修改為'login1':

在login1.html中修改form表單提交按鈕的提交地址也為'login1':

這樣兩個(gè)按鈕的提交地址通過name屬性匹配url,進(jìn)入view視圖的login():
#之前方法實(shí)現(xiàn)登錄驗(yàn)證
def index1(request):
return render(request,'index1.html')
from apps.users.models import UserProfile
def login1(request):
'''
表單驗(yàn)證;
如果是通過get方法進(jìn)行訪問,那么直接返回login1.html.
如果使用post方法,那么表示是表單提交:
(1).獲取用戶輸入的表單數(shù)據(jù)
(2).首先從數(shù)據(jù)庫中查找用戶名為用戶輸入的用戶名的queryset對(duì)象(假設(shè)注冊(cè)時(shí)用戶名唯一,不重復(fù))
(3).如果queryset對(duì)象存在,通過迭代取出對(duì)象中的密碼,(由于用戶名唯一,密碼也一定唯一)
判斷用戶輸入的密碼是否于取出的密碼相等,
如果相等:允許登錄,重定向index1頁面。
不相等,返回login1.html,并且攜帶正確的username以及錯(cuò)誤提示信息。
(4).如果queryset對(duì)象不存在,那么返回login.html,并攜帶錯(cuò)誤提示信息。
:param request:
:return:
'''
if request.method == 'GET':
return render(request,'login1.html')
if request.method == 'POST':
#獲取表單數(shù)據(jù)
username = request.POST.get('username')
password = request.POST.get('password')
#從數(shù)據(jù)庫中獲取用戶名為用戶輸入用戶名的queryset對(duì)象,(假設(shè)注冊(cè)時(shí)用戶名不能重復(fù),唯一的)
users = UserProfile.objects.filter(username=username)
if users.exists(): #判斷queryset對(duì)象中是否有數(shù)據(jù)
passwordlist = []
for user in users:
passwordlist.append(user.password) #通過迭代取出密碼
if password in passwordlist: #判斷密碼是否一致
return HttpResponseRedirect(reverse('index1'))
else:
return render(request,'login1.html',{'msg':'密碼錯(cuò)誤','username':username})
else:
return render(request, 'login1.html', {'msg': '用戶名不存在'})
在用戶名或密碼錯(cuò)誤時(shí),要對(duì)login1.html頁面進(jìn)行數(shù)據(jù)綁定

那么現(xiàn)在開始運(yùn)行項(xiàng)目;
127.0.0.1:8000/index1;

點(diǎn)擊右上角登錄按鈕,進(jìn)入login1頁面:

輸入錯(cuò)誤的username和password;

點(diǎn)擊立即登錄,出現(xiàn)錯(cuò)誤提示信息,不攜帶任何數(shù)據(jù)

輸入正確的username和錯(cuò)誤的password:

點(diǎn)擊立即登錄,保留了正確的username,出現(xiàn)了錯(cuò)誤提示信息

輸入正確的username和password:

點(diǎn)擊立即登錄,跳轉(zhuǎn)到index1頁面


