前戲
上篇文章寫了一個簡單的登錄頁面,那我們可不可以實現一個簡單的登錄功能呢?如果登錄成功,給返回一個頁面,失敗給出錯誤的提示呢?
在之前學HTML的時候,我們知道,網頁在往服務器提交數據的時候,都是在form表單里,并且要滿足下面的幾個條件:
1.form標簽必須要有action和method屬性,如果是文件上傳還要加上下面的一句
<form action="www.baidu.com" enctype="multipart/form-data"></form>
?
2.所有獲取用戶的標簽必須放在form表單中,必須要有name屬性
3.必須要有submit按鈕
Django必學三件套
Django 基礎必會三件套,render,HttpResponse,redirect
from django.shortcuts import HttpResponse, render, redirect
HttpResponse:返回一個指定的字符串
render:返回一個HTML文件
redirect:跳轉url,如果是同一個網站,可以省略域名,如果想跳轉到其他網站,要寫上全部的網址
?
知道了form表單提交數據的三個要素后,我們修改一下login.html文件


<!DOCTYPE html> <html lang="zh-CN"> <head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Title</title><link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"><link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css"><style>body {background-color: #eeeeee;}.login-box {margin-top: 50px;}</style> </head> <body> <div class="container"><div class="row"><div class="col-md-4 col-md-offset-4 login-box"><form class="form-horizontal" action="/login/" method="post"><div class="col-sm-9"><h2 class="text-center">請登錄</h2></div><div class="form-group"><div class="col-sm-9"><div class="input-group margin-bottom-sm"><label for="email" class="hidden">郵箱</label><span class="input-group-addon"><i class="fa fa-envelope-o fa-fw"></i></span><input class="form-control" type="text" name="email" id="email" placeholder="您的郵箱地址"></div><span class="help-block"></span></div></div><div class="form-group"><div class="col-sm-9"><div class="input-group"><label for="password" class="hidden" >密碼</label><span class="input-group-addon"><i class="fa fa-key fa-fw"></i></span><input class="form-control" type="password" name="pwd" id="password" placeholder="請輸入密碼"></div><span class="help-block"></span></div></div><div class="form-group"><div class="col-sm-9"><div class="checkbox"><label><input type="checkbox"> 記住我</label></div></div></div><div class="form-group"><div class="col-sm-9"><button type="submit" id="b1" class="btn btn-block btn-primary">登錄</button><p style="color: red;text-align: center">{{ error_msg}}</p></div></div></form></div></div> </div><script src="/static/jquery-3.3.1.js"></script> <script>$("#b1").click(function () {$("input:not([type='checkbox'])").each(function () {// 判斷值為不為空if ($(this).val().length === 0) {// 展示錯誤提示var errMsgPrefix = $(this).prev().prev().text();$(this).parent().next().text(errMsgPrefix + "不能為空");$(this).parent().parent().parent().addClass("has-error");}});});// 給輸入框綁定獲取焦點的事件 $("input:not([type='checkbox'])").focus(function () {// 清空錯誤提示 $(this).parent().next().text("");// 移除父標簽的has-error $(this).parent().parent().removeClass("has-error");}); </script> </body> </html>
注意:action="/login/"要加/,要不然下面的錯誤時路徑會是這樣的:login/login
我們在去login函數里打印一下request.GET
def login(request):print(request.GET)return render(request,'login.html')
結果:
[02/Jul/2019 20:46:35] "GET /login/login?email=%40163.com&pwd=123 HTTP/1.1" 200 3532 <QueryDict: {'email': ['@163.com'], 'pwd': ['123']}>
可以看到,我們在登錄頁面輸入的郵箱和密碼都以字典的方式傳給了后臺,其中字典的key就是我們在html文件里對應標簽的name屬性,如果沒有name屬性,則為空
?
我們提交數據的時候,通常都是以post方法來提交的,get通常是用于獲取數據的,那我們把login.html文件里的method=‘get’改為post,在來試一下
<form class="form-horizontal" action="login" method="post">
?
上面的錯誤信息告訴了我們:CSRF驗證失敗。請求中止。我們只需要把setting.py里的CSRF注釋掉就可以了
'django.middleware.csrf.CsrfViewMiddleware' #注釋掉這行
先去把login函數里的GET換成POST
print(request.POST),然后就可以正常訪問了
那我們登錄之后能不能給瀏覽器返回一個“登錄成功”的提示呢?
?
index.html


<!DOCTYPE html> <html lang="zh-CN"> <head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Title</title><link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> </head> <body><div class="container"><div class="row"><div class="col-md-12"><div class="page-header"><h1>信息收集卡<small>共三步</small></h1></div><div class="progress"><div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="60" aria-valuemin="0"aria-valuemax="100" style="width: 33%;">1/3</div></div><!--面板--><div class="panel panel-primary"><div class="panel-heading">基本信息<span class="glyphicon glyphicon-pushpin pull-right"></span></div><div class="panel-body"><!--表單--><form class="form-horizontal"><div class="form-group"><label for="inputEmail3" class="col-sm-2 control-label">姓名</label><div class="col-sm-4"><input type="text" class="form-control" id="inputEmail3" placeholder="Email"></div></div><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">手機號</label><div class="col-sm-4"><input type="text" class="form-control" id="inputPassword3" placeholder="Password"></div></div><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">郵箱</label><div class="col-sm-4"><input type="email" class="form-control" id="inputPassword" placeholder="Password"></div></div><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">密碼</label><div class="col-sm-4"><input type="password" class="form-control" id="inputPassword4" placeholder="Password"></div></div><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">頭像</label><div class="col-sm-4"><input type="file" id="inputPassword5" placeholder="Password"><span class="help-block">只支持jpg,png,gif格式</span></div></div><hr><div class="form-group"><label for="inputPassword3" class="col-sm-2 control-label">屬性</label><div class="col-sm-10"><div class="radio"><label><input type="radio" name="optionsRadios" id="optionsRadios1" value="option1"checked>Option one is this and that—be sure to include why it's great</label></div><div class="radio"><label><input type="radio" name="optionsRadios" id="optionsRadios2" value="option2">Option two can be something else and selecting it will deselect option one</label></div><div class="radio disabled"><label><input type="radio" name="optionsRadios" id="optionsRadios3" value="option3"disabled>Option three is disabled</label></div></div></div></form></div></div><!--下一步按鈕--><button class="btn btn-success pull-right">下一步</button></div></div> </div> </body> </html>
?先在view里創建一個index的函數
def index(request):
return render(request,"index.html")
這里我們需要導入HttpResponse,然后再url.py新增index的路徑
from . import views urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^login/', views.login),url(r'^index/', views.index), ]
在login函數里寫如下代碼
def login(request):if request.method == 'POST':email = request.POST.get('email')pwd = request.POST.get('pwd')if email == 'zouzou' and pwd == '123':return redirect('/index/')# return HttpResponse('ok')else:return render(request,'login.html')
這樣我們如果輸入的是zouzou和123,則會跳轉到index頁面,那如果我們需要錯誤的時候給我們提示怎么辦呢?django提供了我們模版語言;{{變量名}},我們在login.html的button按鈕下面加入如下代碼
<button type="submit" id="b1" class="btn btn-block btn-primary">登錄</button><p style="color: red;text-align: center">{{ error_msg}}</p>
在去修改login函數里的代碼
def login(request):error_msg=''if request.method == 'POST': #如果是post,表示提交數據email = request.POST.get('email')pwd = request.POST.get('pwd')if email == 'zouzou' and pwd == '123':#登錄成功跳轉到index頁面return redirect('/index/')# return HttpResponse('ok')else:#登錄失敗,提示用戶名密碼錯誤error_msg = '郵箱或密碼錯誤'#如果是GET,表示要獲取這個頁面return render(request,'login.html',{"error_msg":error_msg})
這樣,我們輸入正確的郵箱和密碼就會跳轉到index頁面,錯誤的會提示
?app
上面我們把login函數和index函數都放到了views.py文件里面。試想一下,如果我們的項目有成百上千和函數呢?放到一個py文件里是不是很麻煩。
python給我們提供了一個app,我們可以把一個模塊放到一個app里,可以有多個app,不同的功能放到不同的app里面。
?
創建app:
如下我們創建了一個叫“appTest01”的項目
python manage.py startapp appTest01
創建完app后,我們要告訴Django我們創建了一個叫“appTest01”的app,去setting.py里加上下面的代碼。
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','appTest01.apps.Apptest01Config', # 告訴django我們創建了一個叫appTest01的app# 'appTest01', # 上面代碼的簡寫方式 ]
上面的設置好了之后,我們把之前在view.py里寫的代碼放到剛創建的appTest01下的view.py里面,然后去url.py里把導入的view.py改一下。啟動我們的項目,訪問登錄頁面,能正常訪問就表示我們的設置是沒有問題的
ORM
前面我們的郵箱和密碼是寫死的。我們可不可以從數據庫里面讀取數據做一個判斷呢?這時我們就要用到ORM了,那什么是ORM呢?
ORM就是一群寫代碼的,懶的寫sql語句,寫了一個工具,自動生成sql語句
ORM:Object Relational Mapping(關系對象映射)
類名對應------------》數據庫中的表名
類屬性對應---------》數據庫里的字段
類實例對應---------》數據庫表里的一行數據
?
ORM的優勢
Django的orm操作本質上會根據對接的數據庫引擎,翻譯成對應的sql語句;所有使用Django開發的項目無需關心程序底層使用的是MySQL、Oracle、sqlite....,如果數據庫移只需要更換Django的數據庫引擎即可
?
ORM的缺點就是執行效率低
1.創建數據庫
由于ORM沒有沒有創建數據庫的方法,所以我們手動創建一個數據庫:
create database mysite;
2.告訴Django連接哪個數據庫
因為Django默認的數據庫是sqlite3,我們要使用mysql,所以要告訴mysql,去setting.py里修改如下代碼
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', # 連接數據庫的類型'NAME': 'mysite', # 數據庫名'HOST': '127.0.0.1', # 數據庫主機地址'PORT': 3306, # 數據庫的端口'USER': 'root', # 登錄數據庫的用戶名'PASSWORD': '123456', # 登錄數據庫的密碼 } }
3.用什么連接數據庫
上面我們已經告訴了django連接哪個數據庫,那用什么連?利用第三方的包,比如第三方包:pymysql和MySQLdb,因為MySQLdb不支持python3,所以我們使用pymysql來連接數據庫,之前也寫過pymysql連接mysql的文章
去和setting.py同級的__init__.py里告訴Django用pymysql模塊代替默認的MySQLdb去連接MySQL數據庫,寫上如下代碼
import pymysqlpymysql.install_as_MySQLdb()
4.創建數據表
數據庫已經配置好了,也告訴了用什么連,然后我們使用ORM去創建一個數據表。
在appTest01/models.py的文件中創建類(只能在這里面創建),類必須繼承models.Model
from django.db import models# Create your models here.class User(models.Model):id = models.AutoField(primary_key=True) # 創建一個自增的id作為主鍵email = models.CharField(max_length=32) # varchar(32)pwd = models.CharField(max_length=32) # varchar(32)
代碼解釋:
我們創建了一個User的類,上面也說過,類名對應的數據庫表,所以會給我們創建一個User的數據表。類下面的就是ORM的語法,創建了三個字段,分別是id(主鍵)和長度為varchar(32)的email和pwd字段
5.生成數據表
現在我們已經萬事具備,只欠東風了,只要生成數據表就可以了,ORM提供了我們兩條命令來生成數據表
1.
python manage.py makemigrations #根據app下的migrations目錄中的記錄,檢測當前model層代碼是否發生變化
結果:
Migrations for 'appTest01':appTest01\migrations\0001_initial.py- Create model User
2.執行完下面的代碼如果都顯示OK就表示數據表創建成功了
python manage.py migrate #把orm代碼轉換成sql語句去數據庫執行
使用pycharm連接mysql數據庫
點擊右邊的DataBase
?
使用ORM查詢數據
上面的apptest01_user是我們創建的表,其他的都是django默認幫我們創建的。我們往數據表里插幾條數據
這樣,數據我們有了,那我們怎么獲取到數據庫里的數據和用戶輸入的數據對比呢?ORM提供了我們一種User.objects.filter(email='', pwd='')?的方法來查詢數據
注意:前面的Uer是我們的數據表名,email和pwd是我們數據表里的字段,那我們是不是可以修改一下登錄函數了呢
from django.shortcuts import render,HttpResponse,redirect from appTest01.models import User def login(request):error_msg=''if request.method == 'POST': #如果是post,表示提交數據ema = request.POST.get('email')password = request.POST.get('pwd')res = User.objects.filter(email=ema,pwd=password)print(res)if res:#登錄成功跳轉到index頁面return redirect('/index/')# return HttpResponse('ok')else:#登錄失敗,提示用戶名密碼錯誤error_msg = '郵箱或密碼錯誤'#如果是GET,表示要獲取這個頁面return render(request,'login.html',{"error_msg":error_msg})def index(request):return render(request,"index.html")
?
如果查詢到res的值就是
<QuerySet [<User: User object>]>
查詢不到res的值就是
<QuerySet []>
如果要獲取對應的值,可以用下面的方法
print(res[0].id,res[0].email,res[0].pwd) # 獲取到數據庫里對應的字段
對象.屬性《-----》數據表里具體字段的值
總結:
1. form表單提交數據的三個要素
1.1. form標簽必須要有action和method屬性
1.2. 所有獲取用戶輸入的標簽必須放在form表單中,必須要有name屬性
1.3. 必須要有submit按鈕
?
2. Django 基礎必會三件套
from django.shortcuts import HttpResponse, render, redirect
2.1. HttpResponse ? ??返回一個指定的字符串時
2.2. render ??返回一個HTML文件
2.3. redirect 跳轉
?
3. request相關的屬性
3.1. request.method --> 返回的是請求的方法(全大寫):GET/POST ...
3.2. request.GET --> 取得是URL里面的參數,類似于字典的數據結構
3.3. request.POST --> post提交的數據,類似于字典的數據結構
4. Django的模板語言
{{ 變量名 }}
?
?
5. Django項目app --> 項目中又分了一級Python包,不同的功能放到不同的包里面
5.1. 創建app
python manage.py startapp app01
5.2. 告訴Django創建了一個app
在settings.py找那個的INSTALLED_APPS中添加新創建的app
6. Django中ORM的使用
6.1. 用處
6.1.1. 操作數據表
6.2.2. 操作數據行
6.2. 使用
6.2.1. 手動創建一個數據庫
-> create database mysite;
6.2.2. 告訴Django連哪個數據庫
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 連接數據庫的類型
'NAME': 'mysite', # 數據庫名
'HOST': '127.0.0.1', # 數據庫主機地址
'PORT': 3306, # 數據庫的端口
'USER': 'root',
'PASSWORD': '123456',
}
}
6.3. 用什么連數據庫?
利用第三方的包,比如第三方包:pymysql和MySQLdb
告訴Django用pymysql模塊代替默認的MySQLdb去連接MySQL數據庫
和settings.py同級的__init__.py文件,寫上:
import pymysql pymysql.install_as_MySQLdb()
?
6.4. 在app/models.py的文件中創建類,只能在這里面創建
類必須繼承models.Model
6.5.?兩個命令
6.5.1. python manage.py makemigrations --> 把models.py的變更記錄一下,注意要保證數據庫里的和ORM變更記錄一樣,否則會報錯
6.5.2. python manage.py migrate --> 把上面的變更記錄翻譯成SQL語句,去數據庫執行
6.5.3. ORM查詢
User.objects.filter(email='', pwd='')
6.5.4.數據表名或結構變了都要重新執行一下6.5.3