1. Django的命令:css
1. 下載安裝
pip install django==1.11.16 -i 源
2. 建立項目
django-admin startproject 項目名稱
3. 啓動項目
cd 項目根目錄下
python manage.py runserver # 127.0.0.1:8000
python manage.py runserver 80 # 127.0.0.1:80
python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80
4. 建立APP
python manage.py startapp app名稱
註冊
5. 數據庫相關
python manage.py makemigrations # 記錄model的變動狀況
python manage.py migrate # 將變動記錄同步到數據庫中html
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函 數之間的映射表。前端
咱們就是以這種方式告訴Django,遇到哪一個URL的時候,要對應執行哪一個函數。python
from django.conf.urls import url
from app1 import views as aap1vw
from app2 import views as aap2vw
urlpatterns = [ url(正則表達式, app1vw,參數,別名),
url(正則表達式, app2vw, 參數, 別名), ]
示例:web
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
Django 2.0版本中的路由系統是下面的寫法(官方文檔):正則表達式
from django.urls import path,re_path urlpatterns = [ path('articles/2003/', views.special_case_2003), #與1的區別一個是url 一個是path path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
# 是否開啓URL訪問地址後面不爲/跳轉至帶有/的路徑的配置項 APPEND_SLASH=True
Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。 其做用就是自動在網址結尾加'/'。數據庫
其效果就是:django
咱們定義了urls.py:json
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^blog/$', views.blog), ]
訪問 http://www.example.com/blog 時,默認將網址自動轉換爲 http://www.example/com/blog/ 。bootstrap
若是在settings.py中設置了 APPEND_SLASH=False,此時咱們再請求 http://www.example.com/blog 時就會提示找不到頁面。
上面的示例使用簡單的正則表達式分組匹配(經過圓括號)來捕獲URL中的值並以位置參數形式傳遞給視圖。
在更高級的用法中,可使用分組命名匹配的正則表達式組來捕獲URL中的值並以關鍵字參數形式傳遞給視圖。
在Python的正則表達式中,分組命名正則表達式組的語法是(?P<name>pattern)
,其中name
是組的名稱,pattern
是要匹配的模式。
下面是以上URLconf 使用命名組的重寫:
from django.conf.urls import url from . import views #將匹配到括號裏的url內容傳給views,views必須的寫形參接收 urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。
例如,針對URL /articles/2017/12/至關於按如下方式調用視圖函數:
views.month_archive(request, year="2017", month="12") #viewa必須的帶接收的參數
在實際應用中,使用分組命名匹配的方式可讓你的URLconf 更加明晰且不容易產生參數順序問題的錯誤,可是有些開發人員則認爲分組命名組語法太醜陋、繁瑣。
至於究竟應該使用哪種,你能夠根據本身的喜愛來決定。
# urls.py中 from django.conf.urls import url from . import views urlpatterns = [ #不一樣的url找同一個視圖函數 url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # views.py中,能夠爲num指定默認值 def page(request, num="1"): pass
在上面的例子中,兩個URL模式指向相同的view - views.page - 可是第一個模式並無從URL中捕獲任何東西。
若是第一個模式匹配上了,page()函數將使用其默認參數num=「1」,若是第二個模式匹配,page()將使用正則表達式捕獲到的num值。
將django項目裏的urls.py 文件複製到app1 和app2裏
項目裏的urls.py文件
from django.conf.urls import url, include #引用include urlpatterns = [ url(r'app1/', include('app1.urls')), #r''能夠爲空,也能夠匹配1級url,include 找到app1裏的urls文件 url(r'app1/', include('app1.urls')), url(r'app2/', include('app2.urls')), url(r'app2/', include('app2.urls')), url(r'app2/', include('app2.urls')), ]
app1裏的urls.py文件
from django.conf.urls import url from app1 import views as aap1vw urlpatterns = [ #此時的url前邊要加上/app1/ 即127.0.0.1/app1/zzzz/ url(r'zzzz/',aap1vw.zzzz),
app2裏的urls.py文件
from django.conf.urls import url from app2 import views as aap2vw urlpatterns = [ url(r'xxxx/',aap2vw.xxxx), url(r'dddd/',aap2vw.dddd), url(r'cccc/',aap2vw.cccc), ]
使用上述方法會致使 html頁面裏的和views裏寫死的url不能使用,解決辦法:給url命名和反向解析:
給url起一個別名 經過反向解析,經過別名動態拿到url地址
from django.conf.urls import url from app1 import views as aap1vw urlpatterns = [ url(r'zhanshi/',aap1vw.Zhan_shi,name='zhanshi'), #增長別名 url(r'add/', aap1vw.Add,name='add'), url(r'update/', aap1vw.Update,name='update'), url(r'del/', aap1vw.Del,name='del'), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/das.css"> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">出版社管理</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Dashboard</a></li> <li><a href="#">Settings</a></li> <li><a href="#">Profile</a></li> <li><a href="#">Help</a></li> </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="Search..."> </form> </div> </div> </nav> <div class="container-fluid"> <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="{% url 'zhanshi' %}">出版社列表 <span class="sr-only">(current)</span></a></li> {#將 以前的/展現/ 改成 {% url 'zhanshi' %}#} 動態或其url別名對應的url路徑 </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h2 class="sub-header">出版社信息</h2> <div class="table-responsive"> <a href="{% url 'add' %}" class="btn btn-primary">添加</a> <table class="table table-striped table-hover"> <thead> <tr> <th>序號<th> <th>ID</th> <th>出版社名稱</th> <th>操做</th> </tr> </thead> <tbody> {% for foo in all %} <tr> <td>{{ forloop.counter }}</td> <td>{{ foo.pk }}</td> <td>{{ foo.mane }}</td> <td> <a href="{% url 'del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">刪除</a> <a href="{% url 'update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">編輯</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </div> </body> </html>
from django.shortcuts import render,redirect,reverse #引用reverse方法 from app1 import models def Zhan_shi(request): all_tusu = models.tusu.objects.all() return render(request,'zhanshi.html',{'all': all_tusu}) def Add(request): if request.method == 'POST': newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('zhanshi')) #將以前寫的跳轉寫死的redirect('/zhanshi/') 修改成獲取別名的redirect(reverse('zhanshi')) return render(request,'add.html') def Update(request): pk = request.GET.get('zj') obj = models.tusu.objects.filter(pk=pk).first() if request.method == 'POST': newname = request.POST.get('newname') obj.mane = newname obj.save() return redirect(reverse('zhanshi')) return render(request,'update.html', {'obj' : obj} ) def Del(request): pk = request.GET.get('sh') obj = models.tusu.objects.filter(pk=pk).first() if request.method == 'POST': dname = request.POST.get('dname') models.tusu.objects.get(mane = dname).delete() return redirect(reverse('zhanshi')) return render(request,'del.html',{'obj':obj})
用來解決 不一樣app中,url名相同路由找錯的問題
即便不一樣的APP使用相同的URL名稱,URL的命名空間模式也可讓你惟一反轉命名的URL。
設置項目裏的urls.py
from django.conf.urls import url, include urlpatterns = [ url(r'app1/', include('app1.urls',namespace='app1')), #namespace 至關於增長一個別名,用來讓模板和views來識別出惟一的url路徑 url(r'app2/', include('app2.urls',namespace='app2')) ]
app1中的urls.py
from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^zhanshi', views.yemian1, name='zhanshi'), url(r'^add', views.yemian2, name='add'), ]
app2中的urls.py
from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^zhanshi', views.yemian1, name='zhanshi'), url(r'^add', views.yemian2, name='add'), ]
此時app1和app2裏的別名相同,要想確認惟一頁面,就要把namespace對應的值加入到先後端代碼裏
前端使用方法
{% url 'app1:zhanshi' %} #在app裏的url的別名前加上 views裏的url別名
後端使用方法
return redirect(reverse('app1:zhanshi') #和前端同樣也是前面加views裏的url別名
詳細介紹:http://www.ruanyifeng.com/blog/2007/11/mvc.html
MVC,全名是Model View Controller,是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型(Model)、視圖(View)和控制器(Controller),具備耦合性低、重用性高、生命週期成本低等優勢。
Django框架的設計模式借鑑了MVC框架的思想,也是分紅三部分,來下降各個部分之間的耦合性。
Django框架的不一樣之處在於它拆分的三部分爲:Model(模型)、Template(模板)和View(視圖),也就是MTV框架。
Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個urls分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
一個視圖函數(類),簡稱視圖,是一個簡單的Python 函數(類),它接受Web請求而且返回Web響應。
響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片。
不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你當前項目目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,你們約定成俗將視圖放置在項目(project)或應用程序(app)目錄中的名爲views.py的文件中。
咱們以前寫過的都是基於函數的view,就叫FBV。還能夠把view寫成基於類CBV的。
def Add(request): #此處定義的是函數 是FBV F是function if request.method == 'POST': newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi')) return render(request,'add.html')
先修改 對應的url
from django.conf.urls import url from app1 import views as aap1vw urlpatterns = [ url(r'zhanshi/',aap1vw.Zhan_shi,name='zhanshi'), url(r'add1/', aap1vw.Add,name='add'), #這是FBV的url url(r'add2/', aap1vw.AddC.as_view(),name='add'), #這是CBV的url 區別在於後邊多了.as_view() url(r'update/', aap1vw.Update, name='update'), url(r'del/', aap1vw.Del,name='del'),
寫CBF方法
from django.views import View #在VBV的基礎上增長引用View方法 class AddC(View): #定義類名並繼承View def get(self,request): #與FBV的區別在於直接把get和post請求處理的邏輯區分開了 邏輯更清晰 return render(request, 'add.html') def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
裝飾器計算程序執行時間
import time def Time(func): def inner(*args, **kwargs): cc = time.time() ret = func(*args,**kwargs) print(cc - time.time()) return ret return inner
FBV自己就是一個函數,因此和給普通的函數加裝飾器無差
@Time def Add(request): if request.method == 'POST': newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi')) return render(request,'add.html')
類中的方法與獨立函數不徹底相同,所以不能直接將函數裝飾器應用於類中的方法 ,咱們須要先將其轉換爲方法裝飾器。
Django中提供了method_decorator裝飾器用於將函數裝飾器轉換爲方法裝飾器。
第一種 low版直接在函數上加
class AddC(View): @Time def get(self,request): return render(request, 'add.html') @Time def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
第二種引用method_decorator
from django.utils.decorators import method_decorator #引用method_decorator方法, class AddC(View): @method_decorator(Time) #在每一個函數上加裝飾器 def get(self,request): return render(request, 'add.html') @method_decorator(Time) def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
第三種 引用上級的dispatch
from django.utils.decorators import method_decorator #無論走post仍是gat都走dispatch函數,裝飾dispatch函數就是裝飾了他倆 class AddC(View): @method_decorator(Time) #裝飾當前的dispatch函數 def dispatch(self, request, *args, **kwargs): #定義函數dispatch ret = super().dispatch(request, *args, **kwargs) 引用上級的dispatch return ret #把上級的調用結果返回給當前的dispatch函數 def get(self,request): return render(request, 'add.html') def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
第四種在類上加並指定使用裝飾器的函數
from django.utils.decorators import method_decorator @ method_decorator(Time,name='get') @ method_decorator(Time,name='post') class AddC(View): def get(self,request): return render(request, 'add.html') def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
第五種 最終版直接裝飾上級的dispatch 一句搞定
from django.utils.decorators import method_decorator @ method_decorator(Time,name='dispatch') class AddC(View): def get(self,request): return render(request, 'add.html') def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
區別在於在裝飾器裏接受的args
def Time(func): def inner(*args, **kwargs): cc = time.time() ret = func(*args,**kwargs) print(cc - time.time()) return ret return inner
若是直接加 args接受倆參數,第一個是func對象,第二個是request請求對象
若是用method_decorator args 只接受一個參數就是request對象
from django.utils.decorators import method_decorator # @ method_decorator(Time,name='dispatch') class AddC(View): @Time #get方式直接裝飾 def get(self,request): return render(request, 'add.html') @method_decorator(Time) #post方式method_decorator方式 def post(self,request): newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
結果
(<app1.views.AddC object at 0x00000241089604A8>, <WSGIRequest: GET '/app1/add2/'>) #get方式 args倆參數 -0.0019369125366210938 [22/Feb/2019 22:44:11] "GET /app1/add2/ HTTP/1.1" 200 2628 (<WSGIRequest: POST '/app1/add2/'>,) #post方式 args一個參數 -0.01776266098022461 [22/Feb/2019 22:44:15] "POST /app1/add2/ HTTP/1.1" 302 0
HttpResponse('字符串') #給請求返回一個字符串
redirect(request,'html文件') #給請求返回一個html文件 rende(重定向地址) #重定向
request.method 請求方法 GET POST PUT
request.GET URL上攜帶的參數
request.POST POST請求提交的數據
request.path 返回用戶訪問url路徑,不包括域名和參數信息 (和request.path_info同樣)
request.body 請求體,byte類型,即 POST請求傳過來的參數
class AddC(View): @Time def get(self,request): print(request.GET) return render(request, 'add.html') @method_decorator(Time) def post(self,request): print(request.method) print(request.path_info) print(request.body) print(request.POST) newname = request.POST.get('newname') models.tusu.objects.create(mane=newname) return redirect(reverse('app1:zhanshi'))
# 打印出的參數 (<WSGIRequest: POST '/app1/add2/'>,) #url上帶的參數 request.GET 因爲沒有在get上傳參 因此這個例子沒有參數 POST #請求方式 request.method /app1/add2/ #url路徑 request.path_info b'newname=%E4%BA%BA%E6%B0%91%E5%87%BA%E7%89%88%E7%A4%BE' #請求主體 byte請求體 request.body <QueryDict: {'newname': ['人民出版社']}> #post請求出來的鍵值, request.POST
request. scheme 表示請求方案的字符串 (一般爲http或https)
def Zhan_shi(request): all_tusu = models.tusu.objects.all() print(request.scheme) return render(request,'zhanshi.html',{'all': all_tusu}) http
request.FILES
一個相似於字典的對象,包含全部的上傳文件信息。 FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。 注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會 包含數據。不然,FILES 將爲一個空的相似於字典的對象。
request.META
一個標準的Python 字典,包含全部的HTTP 首部。具體的頭部信息取決於客戶端和服務器
def Zhan_shi(request): all_tusu = models.tusu.objects.all() print(request.scheme) print(request.META) return render(request,'zhanshi.html',{'all': all_tusu}) {'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\22490\\AppData\\Roaming', 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMPUTERNAME': 'DESKTOP-G8I5SER', 'COMSPEC': 'C:\\WINDOWS\\system32\\cmd.exe', 'CONFIGSETROOT': 'C:\\WINDOWS\\ConfigSetRoot', 'DJANGO_SETTINGS_MODULE': 'tushu.settings', 'DRIVERDATA': 'C:\\Windows\\System32\\Drivers\\DriverData', 'FPS_BROWSER_APP_PROFILE_STRING': 'Internet Explorer', 'FPS_BROWSER_USER_PROFILE_STRING': 'Default', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\22490', 'LOCALAPPDATA': 'C:\\Users\\22490\\AppData\\Local', 'LOGONSERVER': '\\\\DESKTOP-G8I5SER', 'MOZ_PLUGIN_PATH': 'D:\\福喜\\Foxit Reader\\plugins\\', 'NUMBER_OF_PROCESSORS': '4', 'ONEDRIVE': 'C:\\Users\\22490\\OneDrive', 'OS': 'Windows_NT', 'PATH': 'C:\\Python27\\;C:\\Python27\\Scripts;C:\\Python36\\Scripts\\;C:\\Python36\\;C:\\Program Files (x86)\\Intel\\iCLS Client\\;C:\\Program Files\\Intel\\iCLS Client\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;D:\\shexiangt\\3rdparty\\lib\\Win32\\;D:\\shexiangt\\Redist\\Win32\\;C:\\Users\\22490\\AppData\\Local\\Microsoft\\WindowsApps;;D:\\pycharm\\PyCharm 2018.3.2\\bin;;C:\\Python36\\lib\\site-packages\\numpy\\.libs;C:\\Python36\\lib\\site-packages\\numpy\\.libs', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 142 Stepping 9, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '8e09', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules', 'PT5HOME': 'D:\\思科交換機模擬器\\Cisco Packet Tracer 6.0', 'PT6HOME': 'D:\\思科交換機模擬器\\Cisco Packet Tracer 6.0', 'PUBLIC': 'C:\\Users\\Public', 'PYCHARM': 'D:\\pycharm\\PyCharm 2018.3.2\\bin;', 'PYCHARM_HOSTED': '1', 'PYCHARM_MATPLOTLIB_PORT': '55621', 'PYTHON36': 'C:\\Python36', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'D:\\django\\tushu;D:\\pycharm\\PyCharm 2018.3.2\\helpers\\pycharm_matplotlib_backend', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\WINDOWS', 'TEMP': 'C:\\Users\\22490\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\22490\\AppData\\Local\\Temp', 'USERDOMAIN': 'DESKTOP-G8I5SER', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-G8I5SER', 'USERNAME': '22490', 'USERPROFILE': 'C:\\Users\\22490', 'WINDIR': 'C:\\WINDOWS', 'RUN_MAIN': 'true', 'SERVER_NAME': 'DESKTOP-G8I5SER', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/app1/zhanshi/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'wsgi.input': <_io.BufferedReader name=464>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}
def upload(request): """ 保存上傳文件前,數據須要存放在某個位置。默認當上傳文件小於2.5M時,django會將上傳文件的所有內容讀進內存。從內存讀取一次,寫磁盤一次。 但當上傳文件很大時,django會把上傳文件寫到臨時文件中,而後存放到系統臨時文件夾中。 :param request: :return: """ if request.method == "POST": # 從請求的FILES中獲取上傳文件的文件名,file爲頁面上type=files類型input的name屬性值 filename = request.FILES["file"].name # 在項目目錄下新建一個文件 with open(filename, "wb") as f: # 從上傳的文件對象中一點一點讀 for chunk in request.FILES["file"].chunks(): # 寫入本地文件 f.write(chunk) return HttpResponse("上傳OK")
request.get_full_path() 獲取全路徑 即路徑和參數
print(request.get_full_path()) /app1/update/?zj=16
request.is_secure() 若是請求時是https,則返回True;反之False
JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。
from django.http import JsonResponse #引用JsonResponse def json_text(request): data = {'name':'wk','age':18} return JsonResponse(data) #這樣前端就能接收到json格式的數據 默認只能傳遞字典類型,若是要傳遞非字典類型須要設置一下safe關鍵字參數。 JsonResponse([1, 2, 3], safe=False)
Django模板中只須要記兩種特殊符號:
{{ }}和 {% %}
{{ }}表示變量,在模板渲染的時候替換成值,{% %}表示邏輯相關的操做。
{{ 變量名 }}
變量名由字母數字和下劃線組成。
點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。
def test(request): l = [1, 2, 3] d = {'name':'wk'} class dd_a(): def __init__(self, name, age): self.name = name self.age = age def dream(self): return "%s 1111" %(self.name) Wk = dd_a('wk',15) wc = dd_a('wc',13) ww = dd_a('ww',18) pp = [Wk,wc,ww] return render(request, "test.html",{'l':l,'d':d, 'pp':pp} )
在html 取變量
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ l.0 }} #根據索引取列表的值 <br> {{ l.1 }} #取列表的第一個值 <br> {{ d.name }} #根據key取字典的值 <br> {{ d.keys }} #取字典的全部key values 取字典全部的值 items取字典的鍵值 <br> {{ pp.0.name }} #取列表pp第一個對象的 name屬性 <br> {{ pp.0.age }} <br> {{ pp.0.dream }} #使用pp列表第一個對象的dream方法 </body> </html>
注:當模板系統遇到一個 .(點)時,會按照以下的順序去查詢:
翻譯爲過濾器,用來修改變量的顯示結果。
語法: {{ value|filter_name:參數 }}
'|'左右沒有空格沒有空格沒有空格
default
{{ value|default:"nothing"}}
若是value值沒傳的話就顯示nothing
注:TEMPLATES的OPTIONS能夠增長一個選項:string_if_invalid:'找不到',能夠替代default的的做用。
filesizeformat
將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}
若是 value 是 123456789,輸出將會是 117.7 MB。
add
給變量加參數
{{ value|add:"2" }}
value是數字4,則輸出結果爲6。
{{ first|add:second }}
若是first是 [1,.2,3] ,second是 [4,5,6] ,那輸出結果是 [1,2,3,4,5,6] 。
lower
小寫
{{ value|lower }}
upper
大寫
{{ value|upper}}
title
標題
{{ value|title }}
ljust
左對齊
"{{ value|ljust:"10" }}"
rjust
右對齊
"{{ value|rjust:"10" }}"
center
居中
"{{ value|center:"15" }}"
length
{{ value|length }}
返回value的長度,如 value=['a', 'b', 'c', 'd']的話,就顯示4.
slice
切片
{{value|slice:"2:-1"}}
first
取第一個元素
{{ value|first }}
last
取最後一個元素
{{ value|last }}
join
使用字符串拼接列表。同python的str.join(list)。
{{ value|join:" // " }}
truncatechars
若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
參數:截斷的字符數
{{ value|truncatechars:9}}
date
views視圖添加時間
import datetime def test(request): Date = datetime.datetime.now() return render(request, "test.html",{'date':Date})
日期格式化
{{ value|date:"Y-m-d H:i:s"}}
可格式化輸出的字符:點擊查看。
日期也能夠改配置文件顯示
修改settings.py文件
USE_L10N = False DATETIME_FORMAT = 'Y-m-d H:i:s'
此時html只須要寫 {{ date }}
就顯示格式化的日期
safe (轉譯,把傳進來的字符串轉譯爲html可識別的語言)
Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。
好比:
value = "<a href='#'>點我</a>"
{{ value|safe}}
for循環
<ul> {% for user in user_list %} <li>{{ user.name }}</li> {% endfor %} </ul>
for循環可用的一些參數:
Variable | Description |
---|---|
forloop.counter |
當前循環的索引值(從1開始) |
forloop.counter0 |
當前循環的索引值(從0開始) |
forloop.revcounter |
當前循環的倒序索引值(從1開始) |
forloop.revcounter0 |
當前循環的倒序索引值(從0開始) |
forloop.first |
當前循環是否是第一次循環(布爾值)若是是第一次顯示True 後邊的每次循環顯示Flase |
forloop.last |
當前循環是否是最後一次循環(布爾值) |
forloop.parentloop |
本層循環的外層循環 |
def test(request): class dd_a(): def __init__(self, name, age): self.name = name self.age = age def dream(self): return "%s 1111" %(self.name) Wk = dd_a('wk',15) wc = dd_a('wc',13) ww = dd_a('ww',18) pp = [Wk,wc,ww] return render(request, "test.html",{'pp':pp} ) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for ps in pp %} <li>{{ forloop.counter }} = {{ ps.name }}</li> {% endfor %} </ul> </body> </html>
for ... empty 當循環爲空時走empty
{% for foo in all %} <tr> <td>{{ forloop.counter }}</td> <td>{{ foo.pk }}</td> <td>{{ foo.mane }}</td> <td> <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">刪除</a> <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">編輯</a> </td> <td> {% empty %} {# 當for循環爲空時,顯示empty的內容 #} <td>空的</td> </td> </tr> {% endfor %}
if,elif和else
{% for foo in all %} <tr {% if forloop.first %} style="color: red" {% endif %}> #若是是第一次循環得出的結果則顯示紅色 <td>{{ forloop.counter }}</td> <td>{{ foo.pk }}</td> <td>{{ foo.mane }}</td> <td> <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">刪除</a> <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">編輯</a> </td> <td> {% empty %} <td>空的</td> </td> </tr> {% endfor %}
{% if user_list %} 用戶人數:{{ user_list|length }} {% elif black_list %} 黑名單數:{{ black_list|length }} {% else %} 沒有用戶 {% endif %}
固然也能夠只有if和else
{% if user_list|length > 5 %} 七座豪華SUV {% else %} 黃包車 {% endif %}
if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。
{% with oldname as newname %} {{ newname }} {% endwith %}
這個標籤用於跨站請求僞造保護。
在頁面的form表單裏面寫上{% csrf_token %} ,這樣不用註釋中間件 也能夠提交post請求
<form class="form-horizontal" action="" method="post"> {% csrf_token %} {# 加在form表單下 #}
母版就是一個普通的頁面,存放全部頁面公共的代碼,定義好block塊,讓子頁面進行重寫
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/das.css"> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">出版社管理</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Dashboard</a></li> <li><a href="#">Settings</a></li> <li><a href="#">Profile</a></li> <li><a href="#">Help</a></li> </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="Search..."> </form> </div> </div> </nav> <div class="container-fluid"> <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="{% url 'app1:zhanshi' %}">出版社列表 <span class="sr-only">(current)</span></a></li> </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> {% block main %} {% endblock %} {# 母版只保留公共部分,而且定義block來定位不一樣的部分#} </div> </div> </div>
{% extends 'muban.html' %} {# 繼承母版 #} {% block main %} {# 在blick 定位的地方加上不通的部分#} <h2 class="sub-header">出版社信息</h2> <div class="table-responsive"> <a href="{% url 'app1:add2' %}" class="btn btn-primary">添加</a> <table class="table table-striped table-hover"> <thead> <tr> <th>序號<th> <th>ID</th> <th>出版社名稱</th> <th>操做</th> </tr> </thead> <tbody> {% for foo in all %} <tr {% if forloop.first %} style="color: red" {% endif %}> <td>{{ forloop.counter }}</td> <td>{{ foo.pk }}</td> <td>{{ foo.mane }}</td> <td> <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">刪除</a> <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">編輯</a> </td> <td> {% empty %} <td>空的</td> </td> </tr> {% endfor %} </tbody> </table> </div> {% endblock %}
注意點:
1. {% extends 'muban.html' %} 寫在第一行
2. 不一樣的內容寫在這中間{% block main %}
3.子頁面和主頁面不一樣的靜態css js也能夠經過block 添加
一小段公用的html代碼 不少頁面要用的 把這段代碼保存到html文件裏
能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方按以下語法導入便可。
{% include 'toubuxinxi.html' %}
公共頭部文件代碼 toubuxinxi.html
<nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">出版社管理</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Dashboard</a></li> <li><a href="#">Settings</a></li> <li><a href="#">Profile</a></li> <li><a href="#">Help</a></li> </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="Search..."> </form> </div> </div> </nav>
在修改頁面添加頭部
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/das.css"> </head> <body> {% include 'toubuxinxi.html' %} <br> <form class="form-horizontal" action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">出版社名稱</label> <div class="col-sm-10"> <input type="text" class="form-control" id="inputEmail3" placeholder="出版社名稱" name="newname" value="{{ obj.mane }}"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">修改</button> </div> </body> </html>
{% load static %}
head裏得引用靜態文件的static是寫死了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/das.css"> </head>
若是settings.py文件裏的static修改了則每一個引用都要改
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static')
所以使用{% load static %}來解決
<head> <meta charset="UTF-8"> <title>Title</title> {% load static %} {# <link rel="stylesheet" href="/static/css/bootstrap.min.css">#} <link rel="stylesheet" href={% static "css/bootstrap.min.css"%}> {#變量名拼接相對路徑#} {# <link rel="stylesheet" href="/static/css/das.css">#} <link rel="stylesheet" href={% static "css/das.css"%}> </head>
此時改變STATIC_URL = 的值頁面也照常訪問
STATIC_URL = '/11111/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static')
{% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件時使用:
{% load static %} <script src="{% static "mytest.js" %}"></script>
某個文件多處被用到能夠存爲一個變量
{% load static %} {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img>
這種用法至關於使用絕對路徑
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
在數據庫增長關聯表
from django.db import models # Create your models here. class tusu(models.Model): pid = models.AutoField(primary_key=True) mane = models.CharField(max_length=32)
class Book(models.Model): #新增表Book title = models.CharField(max_length=32) #定義書名 tusu = models.ForeignKey('tusu',on_delete=models.CASCADE) #定義外鍵鏈接 鏈接的的表是tusu, on_delete=models.CASCADE 即若是出版社刪除了對應的書也刪除
變動數據庫
python3 manage.py makemigrations
python3 manage.py migrate
新建的book表
加入數據後
作展現頁
url略
views.py
def newzs(request): books = models.Book.objects.all() #查出book表的信息 return render(request,'newzs.html',{'books':books}) #傳到前端
前端 用母版 拿外鍵的值直接點外鍵名(不要加_id)獲得外鍵表的對象再點對應的key拿值
{% extends 'muban.html' %} {% block main %} <h2 class="sub-header">書籍信息</h2> <div class="table-responsive"> {# <a href="{% url 'app1:add2' %}" class="btn btn-primary">添加</a>#} <table class="table table-striped table-hover"> <thead> <tr> <th>序號<th> <th>ID</th> <th>出版社名稱</th> <th>書名 </th> <th>操做</th> </tr> </thead> <tbody> {% for book in books %} <tr {% if forloop.first %} style="color: red" {% endif %}> <td>{{ forloop.counter }}</td> <td>{{ book.pk }}</td> <td>{{ book.tusu.mane }}</td> {# book.tusu點出來的不是外鍵的值而是對應的tusu表的對象,經過對象.key拿對應的值 #} <td>{{ book.title }}</td> <td> <a href="{% url 'app1:del' %}?sh={{ foo.pk }}" class="btn btn-danger btn-sm">刪除</a> <a href="{% url 'app1:update' %}?zj={{ foo.pk }}" class="btn btn-primary btn-sm">編輯</a> </td> <td> {% empty %} <td>空的</td> </td> </tr> {% endfor %} </tbody> </table> </div> {% endblock %}
刪除出版社 ,對應的書也沒了
url略
views.py
class newadd(View): def get(self,request): tusu = models.tusu.objects.all() #獲取全部出版社的信息返回給前端 return render(request,'newadd.html',{'tusu':tusu}) def post(self,request): #post請求添加出版舍 newname = request.POST.get('newname') #獲取要添加的書的名字 put = request.POST.get('put') #獲取要添加的書名對應的外鍵的值 models.Book.objects.create(title=newname,tusu_id=put) #建立新數據 return redirect(reverse('app1:newzs'))
前端展現頁功能 直接跳轉
<a href="{% url 'app1:newadd' %}" class="btn btn-primary">添加</a>
添加頁功能
<div class="table-responsive"> <form class="form-horizontal" action="" method="post"> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">書名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="inputEmail3" placeholder="書名" name="newname"> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">出版社</label> <div class="col-sm-10"> <select name="put" id="inputEmail3" class="form-control"> {% for i in tusu %} <option value="{{ i.pk }}">{{ i.mane }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">添加</button> </div> </div> </form> </div>
url
url(r'upda/(\d+)$', aap1vw.upda.as_view(),name='upda'), #使用分組的方法
views.py
class upda(View): def get(self,request,zh): #分組要在這裏接收前端傳來的分組的位置參數 Book表的主鍵 # zh = request.GET.get('zh') #這是以前的接受前端傳來的?號的方法 如今用分組的方法 book_obg = models.Book.objects.get(pk=zh) tusu = models.tusu.objects.all() return render(request,'upda.html',{'book_obg':book_obg,'tusu':tusu}) def post(self,request,zh): book_obg = models.Book.objects.get(pk=zh) #拿到原有的書的對象 upname = request.POST.get('upname') #拿到修改後的書名 put = request.POST.get('put') #拿到修改後的書的對應的外鍵的值 book_obg.title = upname book_obg.tusu_id = put book_obg.save() return redirect(reverse('app1:newzs'))
展現頁提交信息 #分組url獲得的參數是Book表的主鍵
<a href="{% url 'app1:upda' book.pk %}" class="btn btn-primary btn-sm">編輯</a>
修改頁功能
<div class="col-sm-10"> <input type="text" class="form-control" id="inputEmail3" placeholder="書名" name="upname" value="{{ book_obg.title }}"> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">出版社</label> <div class="col-sm-10"> <select name="put" id="inputEmail3" class="form-control"> {% for i in tusu %} {% if book_obg.tusu == i %} {# book_obg是前端提交的對象,加點外鍵對應的鍵即獲得對應連接的對象 而後對比前端發來的對象是否是當次循環的對象 #} <option selected value="{{ i.pk }}">{{ i.mane }}</option> {# 若是循環列表該次循環的對象是前端get提交來的對象 是就 selected 選中 #} {% else %} <option value="{{ i.pk }}">{{ i.mane }}</option> {# 若是不是就不選中 #} {% endif %} {% endfor %} </select> </div> </div>
url 定義兩個分組分別傳數據庫對面的名字和對應的主鍵
url(r'del_(tusu|book)/(\d+)/$', aap1vw.Del,name='Del'),
前端傳出的值
1.出版社傳出的值爲 對應的數據庫名 和對應 的主鍵值
<a href="{% url 'app1:Del' 'tusu' foo.pk %}" class="btn btn-danger btn-sm">刪除</a>
2. 圖書傳出的值爲 對應的數據庫名 和對應的 主鍵值
<a href="{% url 'app1:Del' 'book' book.pk %}" class="btn btn-danger btn-sm">刪除</a>
views.py 文件邏輯
def Del(request,zz,hh): #分別接收前端傳來的兩個參數 if zz == 'tusu': #圖書的返回圖書的展現頁,出版社的返回出版社的 dd = 'app1:zhanshi' elif zz == 'Book': #此處能夠優化 把展現頁的別名改成對應數據庫對象的名字 dd = 'app1:newzs' #能夠省略以上4行代碼 Obj = getattr(models,zz) #反射獲得models 裏的對應的圖書的或出版社的數據庫對象 Obj.objects.get(pk=hh).delete() #刪除對應的數據庫對象的選中的主鍵 return redirect(reverse(dd)) #返回對應的展現頁