python3之Django後續
環境準備
創建一個Django項目,可以使用前面使用命令行創建,在這裏我是使用pycharm創建的。
記得選擇左邊的Django,Location創建項目的目錄最後一級為項目的名稱。在這裏我們可以創建一個app,如上如我創建了app01。
創建好後我們可以看見一個目錄為:
我們需要在這個目錄的manager.py同級目錄創建一個static的靜態目錄,用來放置css,和js。
再往後我們需要在setting.py的配置文件做以下配置:
- 找到 ‘django.middleware.csrf.CsrfViewMiddleware‘並把它註釋掉
- 找到TEMPLATES部分,如果沒有如下代碼,則需要添加:‘DIRS‘: [os.path.join(BASE_DIR, ‘templates‘)]
- 在文件的最後添加靜態文件目錄,這裏需要註意這裏面是一個元組,所以註意要有逗號(,)。
到這裏我們的一些基本的配置就配好了。最後我們得到的目錄為
上面就是我們開始Django項目前的一些環境準備。
下面是一個簡單的登錄驗證的頁面
大致可以寫如下3步:
- 在myobj下的urls.py裏面寫下相應的路有關系
- 在app01目錄下面我們寫相關的業務代碼,也就是寫相應的視圖函數
- 在寫相應的html
上面在我們寫相應的路由關系的時候,我們需要把把路由關系和視圖函數聯系起來
寫法如圖:加上紅色的那一句
第一步就是寫相關的路由關系
from django.contrib import adminfrom django.urls import path from django.conf.urls import url,include from app01 import views urlpatterns = [ path(‘admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^index/‘, views.index), ]
寫好後我們在寫對應的視圖函數、視圖函數在app01下面的views裏面寫代碼如下
from django.shortcuts import render,redirect# Create your views here. def login(request): if request.method == "GET": return render(request,‘login.html‘) elif request.method == "POST": user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘admin‘ and pwd == ‘admin‘: return redirect(‘/index/‘) else: return render(request,‘login.html‘) else: return render(request,‘login.html‘) def index(request): return render(request,‘index.html‘)
在接下來寫index和login相關的代碼
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post" enctype="multipart/form-data"> <p><input type="text" name="user" placeholder="請輸入用戶名"/></p> <p><input type="password" name="pwd" placeholder="請輸入密碼"/></p> <p><input type="submit" value="登陸"></p> </form> </div> </body> </html>
index.html代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>登陸成功</div> </body> </html>
記住上面的這些HTML代碼都是放在templates目錄下面的。而static目錄裏面放的是一些js和css文件
上面我們可以看到
這個就是登錄界面,當我們輸入的用戶名和密碼正確的時候就會跳轉到我們成功的頁面,當我們失敗的時候還會停留在這個頁面。
獲取數據和文件上傳
在視圖裏面(/app01/views.py) 1、獲取用戶請求數據 request.GET.get(標簽裏面的name屬性值) request.POST.get(標簽裏面的name屬性值) request.FILES.get(標簽裏面的name屬性值) PS: GET:獲取數據 POST:獲取用戶提交數據 2、獲取checkbox等多選的內容 request.POST.getlist(標簽裏面的name屬性值) 3 、上傳文件 # 上傳文件,form標簽做特殊設置 obj = request.FILES.get(‘fafafa‘) obj.name f = open(obj.name, mode=‘wb‘) for item in obj.chunks(): f.write(item) f.close()
上面使用標簽裏面的name屬性值獲取到的是標簽裏面value屬性值。
關於獲取checkbox等多選的內容實驗
視圖裏面的代碼(/app01/views.py)
from django.shortcuts import render,redirect,HttpResponse from django.views import View import os # Create your views here. def login(request): if request.method == "GET": return render(request,‘login.html‘) elif request.method == "POST": user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) gender = request.POST.get(‘gender‘) favor = request.POST.getlist(‘favor‘) city = request.POST.getlist(‘city‘) print(user,pwd,gender,favor,city) obj = request.FILES.get(‘upload‘) print(obj,type(obj),obj.name) file_path = os.path.join(‘upload_dir‘,obj.name) with open(file_path, ‘wb‘) as f: for i in obj.chunks(): f.write(i) return HttpResponse(‘ok‘) # 打印的結果 #admin admin 1 [‘1‘, ‘2‘, ‘3‘] [‘sh‘, ‘bj‘, ‘tj‘] #2018-07-04日22:00 巡檢記錄.txt <class ‘django.core.files.uploadedfile.InMemoryUploadedFile‘> 2018-07-04日22:00 巡檢記錄.txt
login.html代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post" enctype="multipart/form-data"> <p> <input type="text" name="user" placeholder="用戶名"> </p> <p> <input type="password" name="pwd" placeholder="密碼"> </p> <p> 男:<input type="radio" name="gender" value="1"> 女:<input type="radio" name="gender" value="2"> </p> <p> 乒乓球:<input type="checkbox" name = "favor" value="1"> 籃球:<input type="checkbox" name = "favor" value="2"> 羽毛球:<input type="checkbox" name = "favor" value="3"> </p> <p> <select name="city" multiple> <option value="sh">上海</option> <option value="bj">北京</option> <option value="tj">天津</option> </select> </p> <p> <input type="file" name="upload"> </p> <input type="submit" value="提交"> </form> </body> </html>
從上面我們可以知道我們通過標簽裏面的name屬性值獲取到的是標簽的value,當時多選的時候會得到一個列表。
同時上傳文件我們得到的是一個obj我們打印出這個obj看到的是一個上傳文件的名字,但是通過type可以知道這個並不只是一個文件名。
要想獲取裏面文件裏面的數據我們使用obj.chunks()的方法獲取裏面數據,通過和操作文件句柄一樣的操作一行行的讀取裏面的數據再把這個數據寫入到文件中,記住使用‘wb‘的方式,這個上傳的可能是圖像
通過obj.name獲取到我們真正想知道的文件名。上面上傳文件我們需要提前創建一個upload_dir目錄要不就會報錯。
寫視圖的方式有FBV和CBV
1、FBV
FBV --> function base view
這個寫視圖用的是函數的方式。
如:
def 函數名(request):
同時寫路由關系就是上面的方式:
from app01 import views
url(r‘^login/‘, views.login)
2、CBV
CBV --> class base view
使用類的方式寫視圖。
這裏的類需要繼承View類,所以我們在視圖函數裏面需要導入
from django.views import View
class 類名(View):
寫路由關系我們需要在路由關系中寫:
記住在視圖類的後面要加上.as_view(),下面黃色部分使我們可以變化的路由關系
url(r‘^login/‘, views.Login.as_view())
我們上面就是使用的FBV寫的,現在我們使用CBV實現下登錄頁面的驗證
先在myobj/urls.py裏面代碼
from django.contrib import admin from django.urls import path from django.conf.urls import url from app01 import views urlpatterns = [ path(‘admin/‘, admin.site.urls), url(r‘^index/‘, views.Index.as_view()), url(r‘^login/‘, views.Login.as_view()), ]
視圖裏面的代碼
from django.shortcuts import render,redirect from django.views import View class Index(View): def get(self,request): return render(request,‘index.html‘) class Login(View): def get(self,request): return render(request,‘login.html‘) def post(self,request): user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) if user == ‘admin‘ and pwd == ‘admin‘: return redirect(‘/index/‘) else: return render(request,‘login.html‘)
html代碼和上面的第一個登錄界面的html代碼是一樣的沒什麽區別。這個實現後的效果也是一樣的。只是不同形式的實現方式這個是CBV的方式實現的。
簡單分析CBV的運行的流程
我們直接訪問頁面的時候一般都是使用get的方式提交的
當我們輸入url他會在路由關系裏面找到相應的視圖類,我們使用繼承的類的裏面使用了反射函數。
我們可以通過看繼承的父類裏面的代碼可以知道它裏面是幫我們做了相應的處理,反射到我們在類裏面綁定的函數。
直接執行我們在內中綁定的函數。就實現了整個流程。
視圖中傳入模板的字典數據的循環取值
卸載app01/views.py中的代碼
from django.shortcuts import render USER_DICT = { "k1":"root1", "k2":"root2", "k3":"root3", "k4":"root4", "k5":"root5", } def index(request): return render(request,"index.html",{"user_dict":USER_DICT})
index.html代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for k,row in user_dict.items %} <li>{{ k }}-{{ row }}</li> {% endfor %} {% for k in user_dict %} <li>{{ k }}</li> {% endfor %} {% for v in user_dict.values %} <li>{{ v }}</li> {% endfor %} </ul> </body> </html>
上面我們可以看到我麽你可以通過for循環dict.items取字典的鍵值對
也可以通過for循環dict.values取字典的每一個值,也可以直接循環字典得到字典的鍵。
Django的路由系統
多級路由
上面寫的都是通過主urls文件通過導入app的views來實現關於路由到視圖的關聯,也可以稱主usrl文件為一級路由
當我們外部訪問的時候,會在一級路由中查找,如果想要多級路由就要在以及路由裏面導入下一級路由。
代碼為:
from django.conf.urls import url, include urlpatterns = [ url(r‘^cmdb/‘, include("app01.urls")), ]
上面的urls我們需要在app01下面自己創建。
先說一下當我們輸入url的時候在路由系統裏面我們匹配的去除掉前面域名的
如:http://127.0.0.1/cmdb/django/,我們只會匹配後面/cmdb/django
在一級路由的時候我們會正則匹配/cmdb/同時也去除掉前面正則匹配的這時只有/django/那會拿著這個url到app01裏面的urls裏面正則匹配相應的路由。這樣就實現了多級路由。我們可以認為只要前面是/cmdb/我們就會把剩下的路由傳遞給include的下一級路由。這個就是多級路由
url()方法
url()方法可以接受4個參數(regex, view, kwargs=None, name=None)可以看出2個是必須的
regex:這個就是正則表達式的縮寫,這個就是匹配字符串或這url地址的語法。
view:指的是處理當前url請求的試圖函數。
kwargs:任意數量的關鍵字參數可以作為一個字典傳遞給目標視圖
name:對你的URL進行命名,讓你能夠在Django的任意處,尤其是模板內顯式地引用它。這是一個非常強大的功能,相當於給URL取了個全局變量名,不會將url匹配地址寫死。
這裏只是簡單的介紹一下這四個參數。
regex
關於regex的寫法,當一個網站的url地址太多的時候我們就會寫的太多。我們可以把一些有相同特性的url寫成同意格式:
如:url(r‘^index-(\d+).html‘, views.index),這個就是一個正則表達式,可以匹配這一類型的url
或者url(r‘^index-(\d+)-(\d+).html‘, views.index),這個可以更好的匹配相應的url
上面的這個匹配會把分組的匹配到的按位置傳送到view試圖函數。相當於他會把第一個分組匹配的當作視圖函數的一個參數傳給試圖函數,
這個如果參數的位置寫錯了就會造成後面的一系列數據錯誤,所以不推薦使用這個。
我們可以使用:url(r‘^index-(?P<nid>\d+)-(?P<uid>\d+).html‘, views.index)
這個就是正則的給分組起一個名字,這樣我們就會得到一個字典我們就可以把這個字典傳到視圖函數裏面。
這樣我們就可以根據我們起的名字來取到我們想要的數據。
視圖函數可以是:def 函數名(request,*args,**kwargs):pass
這樣不管我們url裏面的分組是否起名字我們都能夠傳到後面。不過建議使用後一種方式這樣不容易出錯。
name
name是對URL路由關系進行命名,以後可以根據此名稱生成自己想要的URL
url(r‘^asdf/‘, views.index, name=‘i1‘),
url(r‘^qwe/(\d+)/(\d+)/‘, views.index, name=‘i2‘),
url(r‘^asd/(?P<pid>\d+)/(?P<nid>\d+)/‘, views.index, name=‘i3‘),
這個樣我們在視圖函數裏面可以:
from django.urls import reverse
def func(request,*args,**kwargs):
url1 = reverse(‘i1‘) # 得到的是 asdf/
url2 = reverse(‘i2‘,args(1,2)) # 得到 /qwe/1/2
url3 = reverse(‘i3‘,kwargs{pid:1,nid:3}) # asd/1/3
在模板語言中:
{% url "i1" %} ---生成/asdf/
{% url "i2" 1 2 %} --生成qwe/1/2/
{% url "i3" pid=1 uid=3 %} ---生成asd/1/3/
這個的用處比如我們原本有一個網址我們現在改為一個新的網址,但是因為舊的網址,用的人比較多我們就可以利用跳轉
如:
原來的:
url(r‘^qwe/(\d+)/(\d+)/‘, views.index),
改成
url(r‘^new_qwe(\d+)/(\d+)/‘, views.new_index,name=‘i1‘),
我們只需要在view裏面增加
from django.http import HttpResponseRedirect
from django.urls import reverse
def inde(requsrt,a,b):
return HttpResponseRedirect(reverse(‘i1‘,args=(a,b)))
Django的ORM
1、數據庫的安裝
再說ORM的時候,我們先說一下數據庫的安裝。
我們打開項目的setting.py的配置文件,這個是整個個Django項目的設置中心。Django默認使用SQLite數據庫,因為Python源生支持SQLite數據庫,所以你無須安裝任何程序,就可以直接使用它。當然,如果你是在創建一個實際的項目,可以使用類似PostgreSQL的數據庫,避免以後數據庫遷移的相關問題。
在這個配置文件中我們可以找到如下的代碼,這個就是默認的數據庫配置,這個默認為SQLite數據庫。
# Database # https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.sqlite3‘, ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘), } }
如果我們想要其他的數據庫的時候我們可以在上面的key為default對應的值進行配置。來連接你的數據庫。上面的一些參數的解釋
ENGINE(引擎):可以是django.db.backends.sqlite3
、django.db.backends.postgresql
、django.db.backends.mysql
、django.db.backends.oracle等其他的
NAME(名稱):類似Mysql數據庫管理系統中用於保存項目內容的數據庫的名字。如果你使用的是默認的SQLite,那麽數據庫將作為一個文件將存放在你的本地機器內,此時的NAME應該是這個文件的完整絕對路徑包括文件名,默認值os.path.join(BASE_DIR, ’db.sqlite3’)
,將把該文件儲存在你的項目目錄下。
下面就是一個使用mysql數據庫的,因為python不支持mysql所以只能借助pymysql來實現操作mysql
import pymysql # 一定要添加這兩行 # 這個pymysql不屬於python內置的需要我們自己安裝 pymysql.install_as_MySQLdb() DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘mysite‘, ‘HOST‘: ‘192.168.244.1‘, ‘USER‘: ‘root‘, ‘PASSWORD‘: ‘123456‘, ‘PORT‘: ‘3306‘, } }
我們在操作數據庫的時候,我們必須現在mysql中創建相應的數據庫才能操作。
還有在我自己創建的app時我們需要把這個app加入到setting中,如果是用pycharm創建Django項目是就穿件的就不需要
使用命令創建的就需要加入:
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘app01‘, # 把我們創建的app01加入 ]
2、創建類
我們在相應的app中的models.py裏面創建我們想要的模型,在這裏面我們全是用python代碼實現的不接觸任何的SQL語句
app01/models.py
from django.db import models class UserInfo(models.Model): # Django會默認創建一個id列,並且是自增,主鍵 # 用戶名列,字符串類型,指定長度 username = models.CharField(max_length=32) # 密碼列,字符類型,指定長度 password = models.CharField(max_length=64)
這樣創建模型後,我們需要執行相應的代碼才能把這些寫到相應的數據庫中,也就是啟動模型。
Django會做2件事。
1、創建app對應的數據庫表結構
2、為我們模型裏面的對象創建基於python的數據庫訪問API
這個執行的目錄就是manage.py同目錄下面。
在命令行:python3 manage.py makemigrations
通過運行makemigrations
命令,相當於告訴Django你對模型有改動,並且你想把這些改動保存為一個“遷移(migration)”。
migrations
是Django保存模型修改記錄的文件,這些文件保存在磁盤上。在例子中,它就是app01/migrations/0001_initial.py
,你可以打開它看看,裏面保存的都是人類可讀並且可編輯的內容,方便你隨時手動修改。
這裏還需要我們把數據遷移到數據庫裏面就還需要執行
python3 manage.py migrate
這裏面因為默認為SQLite,要想查看裏面的數據我們可以使用Navicat Premium 12這個軟件連接到SQLite
也可以直接在pycharm上查看。
點擊pycharm右面的有一個database然後就有上面的畫面,再把我們和manage.py同目錄上面的db.sqlite3拖到這個框框裏面
從上面可以看出我們能夠對數據庫進行相應的操作了。
上面就是在django裏面模型的創建以及把模型遷移到數據庫上的操作,以及查看的一些方式。
3、添加數據
使用python語句添加數據的幾種方式
一、
models.UserInfo.objects.create()
from django.shortcuts import HttpResponse from app01 import models def orm(request): models.UserInfo.objects.create(username=‘root‘, password=‘1234‘) return HttpResponse(‘ok‘)
當我們訪問http://127.0.0.1:8000/orm/的時候我們就會在數據庫裏面創建該數據
註意這裏我們在urls的路由系統裏面加了相應的路由配置
二、
obj = models.UserInfo()
obj.save()
from django.shortcuts import HttpResponse from cmdb import models def orm(request): obj = models.UserInfo(username=‘admin‘, password=‘1234‘) obj.save() return HttpResponse(‘ok‘)
當我們訪問http://127.0.0.1:8000/orm/的時候我們就會在數據庫裏面創建該數據
三、
這種方式就是第一種的差不多只是我們傳進去的是一個字典
from django.shortcuts import HttpResponse dic = { ‘username‘:‘qwer‘, ‘password‘:‘1234‘ } # Create your views here. from cmdb import models def orm(request): models.UserInfo.objects.create(**dic) return HttpResponse(‘ok‘)
上面的字典中的key就是我們數據庫中的列,值就是列中對應的數據。
4、數據庫數據的查詢
查詢所有:ret = models.UserInfo.objects.all()
這裏得到的返回值為:<QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>, <UserInfo: UserInfo object (3)>]>
上面可以知道我們得到一個QuerySet數據這個和列表有點類似,我們可以通過循環獲取它的數據
from django.shortcuts import render from django.shortcuts import HttpResponse # Create your views here. from cmdb import models def orm(request): ret = models.UserInfo.objects.all() print(ret) for row in ret: print(row) print(row.id,row.username,row.password) return HttpResponse(‘ok‘) ## 結果 <QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>, <UserInfo: UserInfo object (3)>]> UserInfo object (1) 1 root 1234 UserInfo object (2) 2 admin 1234 UserInfo object (3) 3 qwer 1234
可以看出ret是一個QuerySet數據類型,循環我們得到的是一個object對象,我們可以通過object對象獲取相應的數據。
條件語句查詢:result =models.UserInfo.objects.filter(username="root")
查詢username為root的用戶所有信息相當於數據庫的where username = ‘root‘
這個查詢出來的也是QuerySet類型的
from django.shortcuts import HttpResponse # Create your views here. from cmdb import models def orm(request): ret = models.UserInfo.objects.filter(username=‘root‘) print(ret) print(ret[0].username) return HttpResponse(‘ok‘) #結果為 <QuerySet [<UserInfo: UserInfo object (1)>]> root
上面我們可以看出查詢出來的還是QuerySet數據類型,
5、刪除數據
models.UserInfo.objects.delete() 刪除所有數據
models.UserInfo.objects.filter(id=2).delete() 通過條件刪除
6、更新數據
models.UserInfo.objects.all().update(password=222) #將所有的的密碼都更改,
models.UserInfo.objects.filter(id=2).update(password=888) # 根據條件更新
ORM的一些補充
創建數據庫表的有哪些字符類型中的字段的參數的意思
null -> db是否可以為空
default -> 默認值
primary_key -> 主鍵
db_column -> 列名
db_index -> 索引
unique -> 唯一索引
unique_for_date ->
unique_for_month
unique_for_year
auto_now -> 創建時,自動生成時間
auto_now_add -> 更新時,自動更新為當前時間
choices -> django admin中顯示下拉框,避免連表查詢
blank -> django admin是否可以為空
verbose_name -> django admin顯示字段中文
editable -> django admin是否可以被編輯
help_text -> django admin提示
...
python3之Django後續