您好,登錄后才能下訂單哦!
Django2.2.2
Python3.6.2
所謂MVC,就是把Web應用分為模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的,松耦合的方式連接在一起。
模型負責業務對象與數據庫的映射(ORM),
視圖負責與用戶的交互(頁面),
控制器接收用戶的輸入,調用模型和視圖完成用戶的請求。
Django的MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關系,只是定義上有些不同。
Django的MTV分別為
M 代表模型(Model):負責業務對象和數據庫的關系映(ORM)。
T 代表模板(Template):負責展示頁面給用戶(HTML)。
V 代表視圖(View):負責業務邏輯,并在適當的時候調用Model和Template。
除了上面三層,還需要一個URL分發器,
它的作用是將一個個URL頁面請求分發給不同的View處理,View再調用相應的Model和Template。
pip3 install django
windows上
django-admin.exe startproject mysite
Linux上
django-admin.py startproject mysite
manage.py Django項目中的工具,可以通過它調用django shell和數據庫等。
settings.py 包含了項目的默認設置,包含數據庫信息,調試標志及其他工作變量。
urls.py 負責把URL映射到應用程序。
python manage.py startapp blog
python manage.py runserver 8080
除了默認生成的信息,下面的內容是新加的
urls.py
from django.contrib import admin
from django.urls import path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
views.py
from django.shortcuts import render
import datetime
# Create your views here.
def index(request):
now = datetime.datetime.now()
ctime = now.strftime("%Y-%m-%D")
return render(request, "index.html", {"ctime": ctime})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h5>當前時間為:{{ ctime }}</h5>
</body>
</html>
settings.py
# 這是Django默認給我們設置的
# 這里是static的訪問URL,全路徑為--http://127.0.0.1:8000/static/jquery-3.3.1.js,可以修改,但默認我們都不修改
STATIC_URL = '/static/'
# 這里是靜態文件存放的路徑,訪問上面的URL,就能找到該路徑下的js文件。
# 該目錄也可以命名為別的,但我們默認都命名為static
# 這是我們自己設置的
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
index.html中
<!-- 這里的src中的static實際是STATIC_URL = '/static/' 中的static。
正是因為配置了STATICFILES_DIRS,所以才能通過STATIC_URL找到jquery-3.3.1.js文件-->
<script type="text/javascript" src="/static/jquery-3.3.1.js"></script>
<script type="text/javascript" src="/static/app1/index.js"></script>
<link rel="stylesheet" type="text/css" href="/static/app1/index.css">
URL配置就是用戶請求的URL與views.py中函數的映射表。通過urls.py,找到對應的函數。
在Django-1.x版本中,使用url
from django.conf.urls import url
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.x版本中,使用path和re_path
from django.urls import path, re_path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
re_path("^articles/2003/$",views.special_case_2003),
]
urls.py
from django.contrib import admin
from django.urls import path, re_path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^articles/2003/$", views.special_case_2003),
re_path(r"^articles/([0-9]{4})/$", views.year_archive),
re_path(r"^articles/([0-9]{4})/([0-9]{2})/$", views.month_archive),
re_path(r"^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$", views.article_detail),
]
views.py
from django.shortcuts import HttpResponse
def special_case_2003(request):
return HttpResponse("^articles/2003/$")
def year_archive(request, year):
return HttpResponse("^articles/([0-9]{4})/$ year:%s" % year)
def month_archive(request, year,month):
return HttpResponse("^articles/([0-9]{4})/([0-9]{2})/$ year:%s,month:%s" % (year, month))
def article_detail(request, year, month, article_id):
return HttpResponse("^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$ year:%s,month:%s,id:%s" % (year, month, article_id))
說明:
1.要從URL中捕獲一個值,只需要用()括起來。
2.不需要添加一個前導的/,因為每個URL都有。例如,應該是^article,而不是^/article。
3.每個正則表達式前面的'r'是可選的,但是建議加上。它告訴python這個字符串是'原始的'----字符串中的任何字符都不應該轉義。
特殊例子說明
一些請求的例子:
/articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數views.month_archive(request, '2005', '03')。
/articles/2005/3/ 不匹配任何URL 模式,因為列表中的第三個模式要求月份應該是兩個數字。
/articles/2003/ 將匹配列表中的第一個模式不是第二個,因為模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的情況來探測匹配的次序。
/articles/2003 不匹配任何一個模式,因為每個模式要求URL 以一個反斜線結尾。
/articles/2003/03/03/ 將匹配最后一個模式。Django 將調用函數views.article_detail(request, '2003', '03', '03')。
上面的例子中,是按照參數的順序,把URL中匹配到的內容傳遞給函數。
可以按照參數的名稱進行匹配,語法是:
(?P<name>pattern),其中name是參數名稱,pattern是匹配的正則表達式。
注意:
urls.py中
re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive)
函數定義中
def year_archive(request, year)
參數名稱要保持相同,都要是year。
urls.py
from django.contrib import admin
from django.urls import path, re_path
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^articles/2003/$", views.special_case_2003),
re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<article_id>[0-9]+)/$", views.article_detail),
]
views.py
from django.shortcuts import HttpResponse
def special_case_2003(request):
return HttpResponse("^articles/2003/$")
#注意,這里的參數名一定要和url中的命名相同才能進行相互匹配
def year_archive(request, year):
return HttpResponse("^articles/([0-9]{4})/$ year:%s" % year)
def month_archive(request, month, year):
return HttpResponse("^articles/([0-9]{4})/([0-9]{2})/$ year:%s,month:%s" % (year, month))
def article_detail(request, article_id, year, month):
return HttpResponse("^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$ year:%s,month:%s,article_id:%s" % (year, month, article_id))
這個實現是捕獲的值作為關鍵字參數而不是位置參數傳遞給視圖函數。
/articles/2005/03/ 請求將調用views.month_archive(request, year='2005', month='03')函數,而不是views.month_archive(request, '2005', '03')。
/articles/2003/03/03/ 請求將調用函數views.article_detail(request, year='2003', month='03', day='03')。
在實際應用中,這意味著你的urls.py中會更加清晰且不容易產生參數順序問題。你可以在視圖函數中重新安排參數的順序。
當有多個app的時候,url配置可以分別寫在每個app中的urls.py中。
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^app1/", include('app1.urls')),
]
在使用Django項目時,一個常見的需求是獲得URL的最終形式,以用于嵌入到視圖或html中,或用于處理服務器端的重定向。
我們不希望硬編碼這些URL,希望設計一種與urls.py中配置對應的動態的URL。
在html中:使用url模板標簽
在python代碼中:使用django.urls.reverse
urls.py
from django.contrib import admin
from django.urls import path, re_path, include
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^article/([0-9]{4})/$", views.year_archive, name='year_archive'),
]
views.py
from django.shortcuts import HttpResponse, render,HttpResponseRedirect
from django.urls import reverse
def year_archive(request, year):
redirect_url = reverse('year_archive', args=(year,))
print(redirect_url) # /article/2004/
year_list = [2014, 2015]
# return HttpResponseRedirect(reverse('year-archive', args=(year,)))
# 在render的時候,就會對index.html進行渲染,所以就把a標簽中的href設置了值
return render(request, 'index.html', {'year_list': year_list})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="{% url 'year_archive' 2013 %}">2013</a>
{% for yearvar in year_list %}
<a href="{% url 'year_archive' yearvar %}">{{ yearvar }}</a>
{% endfor %}
</body>
</html>
由于name沒有作用域,Django在反向解析URL時,會在全局項目搜索,找到一個name指定的URL時,立即返回。
當我們項目中有多個app時,可能會出現name相同的情況,為了避免name相同引發的解析異常,引入了名稱空間。
project的urls.py
from django.contrib import admin
from django.urls import path, re_path, include
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^app1/", include('app1.urls', namespace="app1")),
re_path(r"^app2/", include('app2.urls', namespace="app2")),
]
app1的urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
from django.urls import path, re_path, include
from app1 import views
app_name = '[app1]'
urlpatterns = [
re_path(r"^articles/([0-9]{4})/$", views.year_archive, name="year_archive" ),
]
app1的views.py
from django.shortcuts import HttpResponse, render,HttpResponseRedirect
from django.urls import reverse
def year_archive(request, year):
redirect_url = reverse('app1:year_archive', args=(year,))
return HttpResponse("app1 %s"% redirect_url)
app2的urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
from django.urls import path, re_path, include
from app2 import views
app_name = '[app2]'
urlpatterns = [
re_path(r"^articles/([0-9]{4})/$", views.year_archive, name="year_archive"),
]
app2的views.py
from django.shortcuts import HttpResponse, render,HttpResponseRedirect
from django.urls import reverse
def year_archive(request, year):
url = reverse('app2:year_archive', args=(year,))
return HttpResponse("app2 %s" % url)
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"^articles/2003/$", views.special_case_2003),
re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<article_id>[0-9]+)/$", views.article_detail),
]
上面的內容,考慮如下兩個問題:
1.默認ulr中匹配到的year,month是字符串類型,如果我們想要使用int類型,需要在views.py中手動進行類型轉換。
那是否可以直接在ulr中自動轉換為int類型呢。
2.上面的year,month都是相同的正則表達式,需要寫三次,如果一處修改,三處都要修改。
那是否能只修改一處呢
基本規則:
1.使用<>從url中捕獲值
2.捕獲值中可以包含一個轉化器類型,比如捕獲一個整數變量。如果沒有轉化器,將匹配任何字符串,也包含/字符。
3.無需添加前導斜杠/。
urls.py
"""first_django URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path, include
from app1 import views
urlpatterns = [
path('admin/', admin.site.urls),
path("articles/2003/", views.special_case_2003),
path("articles/<int:year>/", views.year_archive),
path("articles/<int:year>/<int:month>/", views.month_archive),
path("articles/<int:year>/<int:month>/<slug:article_id>/", views.article_detail),
]
views.py
from django.shortcuts import HttpResponse
def special_case_2003(request):
return HttpResponse("articles/2003/")
def year_archive(request, year):
print(type(year))#<class 'int'>
return HttpResponse("articles/<int:year>/ year:%s" % (year))
def month_archive(request, month, year):
return HttpResponse("articles/<int:year>/<int:month>/ year:%s ,month:%s " % (year, month))
def article_detail(request, article_id, year, month):
return HttpResponse("articles/<int:year>/<int:month>/<slug:article_id>/ year:%s ,month:%s ,article_id:%s " % (year, month, article_id))
1.str匹配除了路徑分隔符(/)之外的非空字符串,這是默認的形式。
2.int匹配正整數,包含0。
3.slug匹配字母、數字以及橫杠、下劃線組成的字符串
4.uuid匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
5.path匹配任何非空字符串,包含路徑分隔符
對于一些復雜或者復用的需要,可以定義自己的轉化器。轉化器是一個類或接口,要求下面的三點。
1.regex類屬性,字符串類型。
2.to_python(self,value)方法,value是由regex匹配到的字符串,返回具體的python變量值,以供對應的視圖函數使用。
3.to_url(self,value)方法,和to_python相反,value是一個具體的python變量值,返回其字符串,通常用于url反向引用,即reverse。
converters.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
class YearConverter:
regex = '[0-9]{4}'
def to_python(self,value):
print("to_python",value)
return int(value)
def to_url(self,value):
print("to_url",value)
return '%04d' % value
urls.py
from django.contrib import admin
from django.urls import path, register_converter
from app1 import views,converters
register_converter(converters.YearConverter,"int_con")
urlpatterns = [
path('admin/', admin.site.urls),
path("articles/2003/", views.special_case_2003),
path("articles/<int_con:year>/<int_con:month>/", views.month_archive,name="month_archive"),
]
views.py
from django.shortcuts import HttpResponse
from django.urls import reverse
def special_case_2003(request):
return HttpResponse("articles/2003/")
def month_archive(request, year, month):
print(reverse(month_archive,args=(121,234)))#<class 'int'>
return HttpResponse("articles/<int:year>/ year:%s" % (year))
從上面結果可以看出,to_python調用了兩次,to_url調用了兩次
在to_url中,是把args=(121,234)中的參數,每一個參數調用一次to_url。
from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
解讀代碼:
1.首先導入模塊:from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
2.定義視圖函數current_datetime。每個視圖函數第一個參數都是HttpRequest對象。
3.這個視圖會返回一個HttpResponse對象,每個視圖都負責返回一個HttpResponse對象。
django將請求報文中的請求行、首部信息,內容主體封裝成HttpRequest類中的屬性。
1.HttpRequest.GET
一個類似于字典的對象。
get請求時,
瀏覽器中手動設置參數http://127.0.0.1:8000/login/?user_name=vita&passwd=123
<QueryDict: {'user_name': ['vita'], 'passwd': ['123']}>
不手動設置參數http://127.0.0.1:8000/login/
<QueryDict: {}>
2.HttpRequest.POST
post請求時,
form表單提交
<QueryDict: {'user_name': ['vita'], 'passwd': ['123']}>
http://127.0.0.1:8000/index/
url:協議://IP:port/路徑?get請求數據
3.HttpRequest.path
表示請求的路徑
例如:請求http://127.0.0.1:8000/login/?user=vita&passwd=123
print(request.path) # /login/
print(request.get_full_path()) #/login/?user=vita&passwd=123
4.HttpRequest.get_full_path()
返回path,如果有查詢字符串,查詢字符串也在路徑中。
5.HttpRequest.method
用于判斷是GET請求還是POST請求
6.HttpRequest.FILES
print(request.FILES)#<MultiValueDict: {'myfile': [<InMemoryUploadedFile: Java快捷鍵.txt (text/plain)>]}>
print(type(request.FILES.get("myfile")))# <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
一個類似于字典的對象,包含所有的上傳文件信息。
FILES總的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。
注意:FILES只有在請求的方法為POST且提交的<form>表單中帶有屬性enctype="multipart/form-data"的情況下才會有數據。
否則,FILES將是一個空的類似于字典的對象。
7.HttpRequest.META
一個標準的Python 字典,包含所有的HTTP 首部。具體的頭部信息取決于客戶端和服務器,下面是一些示例:
CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。
CONTENT_TYPE —— 請求的正文的MIME 類型。
HTTP_ACCEPT —— 響應可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
HTTP_HOST —— 客服端發送的HTTP Host 頭部。
HTTP_REFERER —— Referring 頁面。
HTTP_USER_AGENT —— 客戶端的user-agent 字符串。
QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。
REMOTE_ADDR —— 客戶端的IP 地址。
REMOTE_HOST —— 客戶端的主機名。
REMOTE_USER —— 服務器認證后的用戶。
REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服務器的主機名。
SERVER_PORT —— 服務器的端口(是一個字符串)。
從上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,請求中的任何 HTTP 首部轉換為 META 的鍵時,
都會將所有字母大寫并將連接符替換為下劃線最后加上 HTTP_ 前綴。
所以,一個叫做 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。
8.HttpRequest.encoding
print(request.encoding) # None
一個字符串,表示提交的數據的編碼方式(如果為None,表示使用DEFAULT_CHARSET的設置,默認為utf-8)。
這個屬性是可寫的,你可以修改它來修改訪問表單數據使用的編碼。
接下來對屬性的任何訪問,將使用新的encoding值。
如果你知道表單數據的編碼不是DEFAULT_CHARSET,則使用它。
響應對象主要有三種形式:
1.HttpResponse()
HttpResponse()括號中直接跟一個具體的字符串作為響應體,比較簡單直接。
2.render(request, template_name,{"ctime":ctime})
def render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
render(request, "index.html",{"ctime":ctime})
結合一個給定的模板和一個上下文字典,把字典中的數據渲染到html頁面中。
request:用于生成響應的請求對象。
template_name:html模板名稱,可選參數。
context:默認是一個字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。
render方法就是把一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面為響應體。
3.redirect()
1)傳遞要重定向的一個硬編碼URL
def my_view(request):
...
return redirect('/some/url/')def my_view(request):
...
return redirect('http://example.com/')
2)也可以是一個完整的URL
def my_view(request):
...
return redirect('http://example.com/')
3)發送了兩次請求 ,返回碼是302(login為舊地址,auth為跳轉的地址)
[23/Jun/2019 10:26:15] "GET /login/ HTTP/1.1" 302 0
[23/Jun/2019 10:26:15] "GET /auth/ HTTP/1.1" 200 4
4)return http.HttpResponsePermanentRedirect ('http://www.baidu.com/'),返回碼是301,發送了一次請求
[23/Jun/2019 10:32:50] "GET /login/ HTTP/1.1" 301 0
5)302與301的區別:
django實現302臨時重定向的代碼,也可以使用上面的redirect
from django import http
def view(request):
return http.HttpResponseRedirect('http://www.baidu.com/')
django實現301永久重定向
from django import http
def view(request):
return http.HttpResponsePermanentRedirect ('http://www.baidu.com/')
相同點:
1)都表示重定向,瀏覽器自動跳轉到一個新地址,用戶看到的效果是輸入的A地址瞬間變為了B地址。
不同點:
1)301表示永久跳轉,舊地址被永久的移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時,也將舊地址轉換為新地址。
永久跳轉在后端實際只發生一條請求log,為新地址。
2)302表示臨時跳轉,舊的資源依然可以訪問。
臨時跳轉在后端發生了兩條請求log,分別為舊地址和新地址。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。