網頁偽靜態 1.什麼是偽靜態網頁? 偽靜態是相對於靜態文件來說的,例如https://www.cnblogs.com/hesujian/p/11165818.html 將一個動態網頁偽裝成靜態網頁 將url地址模擬成html結尾的樣子,看上去像是一個靜態文件,只是改變了URL的表現形式,實際上還是動 ...
目錄
網頁偽靜態
1.什麼是偽靜態網頁?
偽靜態是相對於靜態文件來說的,例如https://www.cnblogs.com/hesujian/p/11165818.html
將一個動態網頁偽裝成靜態網頁
將url地址模擬成html結尾的樣子,看上去像是一個靜態文件,只是改變了URL的表現形式,實際上還是動態頁面
搜索優化:seo
在路由的最後加上.html
2.偽靜態的好處
1、美觀(傳統的問號拼接看起來比較雜亂)
2、seo(搜索引擎優化技術),搜索引擎比較喜歡收錄靜態頁面,所以大家都做成偽靜態去增加收錄機會,增大本網站的seo查詢力度,增加搜索引擎收藏本網站的概率
3.實現偽靜態網頁
# 在路由後面加上.html就可實現靜態頁面效果
path('index.html',view.index)
視圖層
Django視圖層,視圖就是Django項目下的views.py文件,它的內部是一系列的函數或者是類,用來專門處理客戶端訪問請求後處理請求並且返回相應的數據,相當於一個中央情報處理系統。
1.三板斧
"""
HttpResponse
返回字元串類型
httpresponse() 括弧內直接跟一個具體的字元串作為響應體,比較直接簡單,所有這裡主要介紹後面兩種形式。
render
返回html頁面 並且在返回給瀏覽器之前還可以給html文件傳值
render(request, template_name[, context])結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
# 參數:
request: 用於生成響應的請求對象。
template_name:要使用的模板的完整名稱,可選的參數
context:添加到模板上下文的一個字典。預設是一個空字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。
render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面作為響應體。
redirect
傳遞要重定向的一個硬編碼的URL
def my_view(request):
rerurn redirect('/some/url/')
也可以是一個完整的URL
def my_view(request):
...
return redirect('http://www.baidu.com/')
"""
2.三板斧的本質
視圖app01沒有返回一個HttpResponse對象,返回一個None代替了
Django視圖層函數必須要返回一個HttpResponse對象
django視圖層函數必須有一個返回值,並且返回值的數據類型必須是HttpResponse對象
研究底層源碼
1.def index(request):
return HttpResponse()
"""
按住ctrl點擊進入HttpResponse:
發現HttpResponse其實是一個類,那麼類名加()實例化產生一個對象
class HttpResponse(HttpResponseBase):
pass
"""
2.def index(request):
return render()
"""
按住ctrl點擊進入render:
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
先執行的是render函數,然後render函數返回的是HttpResponse(content, content_type, status)
"""
3.def index(request):
return redirect()
"""
按住ctrl點擊進入redirect:
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
按住ctrl點擊進入HttpResponsePermanentRedirect:
class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
pass
按住ctrl點擊進入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
會發現它繼承的也是HttpResponse
按住ctrl點擊進入HttpResponseRedirect:
class HttpResponseRedirect(HttpResponseRedirectBase):
pass
按住ctrl點擊進入HttpResponseRedirectBase:
class HttpResponseRedirectBase(HttpResponse):
pass
會發現它繼承的也是HttpResponse
"""
'''綜上研究發現:Django視圖層函數必須要返回一個HttpResponse對象'''
3.視圖函數返回json格式數據
def index(request):
# 將後端字典序列化發送到前端
user_dict = {'name': 'jason', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# 先轉成json格式字元串
json_str = json.dumps(user_dict)
# 將該欄位返回
return HttpResponse(json_str)
解決這個中文輸入的問題我們之前是加了ensure_ascill=False,ensure_ascii 內部預設True自動轉碼,改為False不轉碼,只生成json格式,雙引號
以上實現返滬json格式數據比較麻煩,又得轉換json格式又得編碼設置,那麼Django的出現就在這方面做出了改變
JsonResponse
# 導入JsonResponse模塊
from django.http import JsonResponse
def index(request):
user_dict = {'name': 'jason老師', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# json_str = json.dumps(user_dict, ensure_ascii=False)
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii':False}) # 直接寫入JsonResponse,不需要去做json序列化操作
# user_dict,json_dumps_params={'ensure_ascii':False} :解決前端中文轉碼問題
JsonResponse底層
# 繼承了HttpResponse,返回的還是HttpResponse對象
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
# json_dumps_params=None,註意這個參數,是一個預設參數
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
# 對應開始json_dumps_params=None,
json_dumps_params = {}
# 如果我們在這裡傳入了一個值,那麼這裡的json_dumps_params = {'XXX':'XXX'},然後在下麵的data裡面轉換為的是關鍵字參數,XXX=XX
kwargs.setdefault('content_type', 'application/json')
'''
將data數據進行了json序列化,然後做了一個返回
**json_dumps_param,**加在字典前面,現在是在調用一個函數,那麼它在這裡做實參,**在是實參中將字典打散為關鍵字參數形式,就是什麼等於什麼
'''
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
JsonResponse序列化(列表註意事項)
# 導入JsonResponse模塊
from django.http import JsonResponse
def ab_json(request):
l = [111,222,333,444,555]
# 預設只能序列化字典 序列化其他需要加safe參數 safe=False
return JsonResponse(l,safe=False)
json與pickle區別
import json
'''支持的數據類型:str,list, tuple, dict, set'''
# 序列化出來的數據是可以看得懂的,就是一個字元串
dumps 將Python對象轉換成json字元串
loads
dump 將Python對象寫入json文件
load
import pickle
'''支持的數據類型:python中的所有數據類型'''
# 序列化出來的結果看不懂,因為結果是一個二進位
# pickle序列化出的來的數據只能在python中使用
dumps
loads
dump
load
4.FBV與CBV
1.FBV與CBV區別
FBV基於函數的視圖(Function base view) 我們前面寫的視圖函數都是FBV
CBV基於類的視圖(Class base view)
視圖文件種除了用一系列的函數來對應處理客戶端請求的數據邏輯外,還可以通過定義類來處理相應的邏輯。
# 視圖函數既可以是函數也可以是類
def index(request):
return HttpResponse('index')
2.CBV
從index頁面,後臺修改action的參數,朝func發送post請求
點擊提交以後自動出發了類裡面的post方法
CBV比起FBV來說的話,不需要通過request.method來判斷當前是什麼請求,CBV會自動判斷,是哪種請求,就去觸發哪種方法(寫在類裡面里的函數叫做方法)
3.CBV底層源碼
源碼分析入口
path('func/', views.MyView.as_view())
"""
# 面向對象屬性方法查找順序
1.先從對象自己名稱空間找
2.在去產生類對象的類裡面找
3.在去父類裡面找
"""
1.綁定給類的as_view方法(它是我們自己寫的類裡面繼承的類)
class View:
@classonlymethod
def as_view(...):
綁定給類的,類調用會自動將類當作第一個參數傳入
def view(...):
pass
return view
2.CBV路由匹配本質:跟FBV是一致的
path('func/', views.view)
3.訪問func觸發view執行
def view(...):
obj = cls() # 我們自己寫的類加括弧產生的對象
return obj.dispatch()
'''涉及到對象點名字 一定要確定對象是誰 再確定查找順序'''
4.研究dispatch方法
def dispatch(...):
判斷 request.method將當前請求方式轉成小寫 在不在 self內 self==MyLogin
"http_method_names 內有八個請求方式 合法"
['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
if request.method.lower() in self.http_method_names:
# getattr 反射: 通過字元串來操作對象的屬性或者方法
func_name = getattr(obj,request.method.lower())
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
用到了一個反射的知識,從obj這個對象裡面,找一個request.method.lower()這個的函數
form表單如何攜帶數據文件
form表單如何攜帶數據文件需要註意滿足以下倆個要求
1.method屬性值必須是post
2.enctype屬性值必須是multipart/form-data
後端獲取文件數據的操作,request對象方法
1.獲取請求方式POST/GET
request.method
一個字元串,表示請求使用的HTTP 方法。必須使用大寫。
2.request.POST
獲取POST請求提交普通的鍵值對數據 一個類似於字典的對象,如果請求中包含表單數據,則將這些數據封裝成
3.獲取GET請求
request.GET
獲取GET請求 一個類似於字典的對象,包含 HTTP GET 的所有參數
4.獲取文件
request.FILES
一個類似於字典的對象,包含所有的上傳文件信息。
FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。
註意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會包含數據。否則,FILES 將為一個空的類似於字典的對象。
5.原生的瀏覽器發過來的二進位數據
request.body
一個字元串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,
例如:二進位圖片、XML,Json等。
6.拿到路由
request.path
print(request.path) # /app01/index/
個字元串,表示請求的路徑組件(不含功能變數名稱)
7.拿到路由
request.path_info
print(request.path_info) # /app01/index/
8.能過獲取完整的url及問號後面的參數
request.get_full_path()
print(request.get_full_path()) # /app01/index/?username=jason
實際案例展示
import json
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
# Create your views here.
def index(request):
# user_dict = {'name': 'jason老師', 'pwd': 123, 'hobby': ['read', 'run', 'music']}
# # json_str = json.dumps(user_dict, ensure_ascii=False)
# return JsonResponse(user_dict, json_dumps_params={'ensure_ascii':False}) # 直接寫入JsonResponse,不需要去做json序列化操作
#
# # user_dict,json_dumps_params={'ensure_ascii':False} :解決前端中文轉碼問題
if request.method == 'POST':
# 普通的鍵值對形式的數據
print(request.POST)
# 專門用來攜帶過來的文件數據,流式的文件數據
print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 今日內容.md (application/octet-stream)>]}>
# 也可以取到這個文件,註意它也是一個Dict,可以通過點的方式得到,'file'由前端的name標簽決定
file_obj = request.FILES.get('file')
# 可以使用這個對象去點出一些方法
print(file_obj.name)
# 也可以將這個文件保存下來,這個文件可以是文本文件,也可以是音頻文件,只不過pycharm不能拿播放音頻文件
with open(file_obj.name, 'wb') as f:
for line in file_obj:
f.write(line)
return render(request, 'index.html')
模板層
1.模板語法的傳值
方式一:指名道姓的傳
urls代碼:
path('modal/', views.modal)
views代碼:
def modal(request):
name = 'jason'
return render(request, 'modal.html', {'name':name})
指名道姓傳參 不浪費資源
方式二:關鍵字locals()
html代碼:
<body>
{{ name }}
{{ age }}
{{ gender }}
</body>
urls代碼:
path('modal/', views.modal)
views代碼:
def modal(request):
name = 'jason'
age = 18
gender = 'female'
return render(request, 'modal.html', locals()) # 將函數體里局部空間里所有的名字全部傳入給前面的那個頁面
將整個局部名稱空間中的名字去全部傳入簡單快捷
2.模板語法傳值的範圍
基本數據類型直接傳遞使用
views代碼
def modal(request):
i = 123
f = 13.4
s = 'study work hard'
d = {'name': 'Tony', 'pwd': 123}
t = (11, 22, 33)
se = {11, 22, 33}
b = True
return render(request, 'modal.html', locals())
html代碼
<body>
<p>{{ i }}</p>
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ l }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
</body>
函數名的傳遞會自動加括弧執行並將返回值展示到頁面上,註意函數如果有參數則不會執行也不會展示 模板語法不支持有參函數
views代碼
def modal(request):
def func1():
print('函數')
return '這裡才能傳過去值哦'
return render(request, 'modal.html', locals())
html代碼
<body>
{#傳遞函數名會自動加括弧調用 但是模板語法不支持給函數傳額外的參數#}
<p>{{ func1 }}</p>
</body>
類名的傳遞也會自動加括弧產生對象並展示到頁面上,對象的傳遞則直接使用即可,對象預設情況下不可以加括弧了,除非自己寫__call__方法,模板語法會判斷每一個名字是否可調用 如果可以則調用!!!
views代碼
class MyClass(object):
def get_obj(self):
return 'obj'
@classmethod
def get_cls(cls):
return 'cls'
@staticmethod
def get_func():
return 'func'
obj = MyClass()'
return render(request, 'modal.html', locals())
html代碼
<body>
{#傳類名的時候也會自動加括弧調用(實列化) 生成對象#}
<p>{{ MyClass }}</p>
{#內部能夠自動判斷出當前的變數名是否可以加括弧調用 如果可以就會自動執行 針對的是函數名和類名#}
<p>{{ obj }}</p>
{#模板語法支持對象調用類方法#}
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_class }}</p>
</body>
django的模板語法在操作容器類型的時候只允許使用句點符,既可以點鍵,也可以點索引
.key
.index
.key.index.index.key
3.模板語法過濾器(類似於python內置函數)
1.模板語法過濾器
過濾器就類似於是模板語法內置的 內置方法
模板語法提供了一些內置方法,以助於快速的處理數據(過濾器最多只能有兩個參數)
2.基本語法
{{ 變數|過濾器:參數}}
過濾器:會自動將豎杠左側的變數當做第一個參數交給過濾器處理,右側的當做第二個參數。
3.過濾器內置方法
<p>統計長度:{{ s|length }}</p>
# 統計長度:15
<p>加法運算:{{ i|add:123 }}、加法運算:{{ s|add:'heiheihei' }}</p>
# 加法運算:246、字元串加法運算:study work hard +every day
<p>日期轉換:{{ s|date:'Y-m-d H:i:s' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
# 文件大小:31.1 KB
<p>數據切片:{{ l|slice:'0:10' }}</p>
# 切片操作(支持步長)
<p>字元截取(三個點算一個):{{ s1|truncatechars:6 }}</p>
# 字元截取(包含三個點):模板語法提供...
<p>單詞截取(空格):{{ s1|truncatewords:6 }}</p>
# 單詞截取(不包含三個點 按照空格切):my name is objk my age is 18 and ...
<p>語法轉義:{{ script_tag }}</p>
# <h1>今晚晚飯又有好多好吃的了</h1>(是不會識別前端標簽的)
<p>語法轉義:{{ script_tag|safe }}</p>
# 今晚晚飯又有好多好吃的了
# 如果不轉移的話,那麼無法識別前端標簽,那麼以下這種功能的情況就沒有辦法實現
<p>語法轉義:{{ script_tag1|safe }}</p>
script_tag1 = '<script>alert(666)</script>'
# 也可以使用後端轉
from django.utils.safestring import mark_safe
script_tag2 = '<script>alert(666)</script>'
res = mark_safe(script_tag2)
ps:有時候html頁面上的數據不一定非要在html頁面上編寫了 也可以後端寫好傳入
'''django模板語法中的符號就兩個 一個{{}} 一個{%%}
需要使用數據的時候 {{}}
需要使用方法的時候 {%%}
'''
4.模板語法標簽(類似於python流程式控制制)
1.if判斷
<body>
{% if 條件 %} 條件一般是模板語法傳過來的數據 直接寫名字使用即可
條件成立執行的代碼
{% elif 條件1 %}
條件1成立執行的代碼
{% else %}
條件都不成立執行的代碼
{% endif %}
</body>
2.for迴圈
forloop 模板語法自帶的變數名
{% for i in s %}
{% if forloop.first %}
<p>這是第一次喲~</p>
{% elif forloop.last %}
<p>這是最後一次!</p>
{% else %}
<p>{{ i }}</p>
{% endif %}
{% empty %}
<p>empty專門用來判斷空的時候,當in後面是空的時候執行這個,給予提示</p>
{% endfor %}
解析:
forloop內置對象:運行結果解析
'counter0': 從0開始計數
'counter' : 從1開始計數
'first': True,判斷迴圈的開始
'last' : Tues,判斷迴圈的結束
3.with語法起別名
# with起別名
{% with d.hobby.3.info as nb %}
<p>{{ nb }}</p>
在with語法內就可以通過as後面的別名快速的使用到前面非常複雜獲取數據的方式
<p>{{ d.hobby.3.info }}</p>
{% endwith %}
解析:
可以通過as後面的別名快速的使用到前面非常複雜獲取數據的方式
取別名後原來的名字也能正常使用
命名規範: 只能在with代碼塊兒的範圍之內才能使用別名
5.自定義標簽函數、過濾器、inclusion_tag
1.自定義過濾器,標簽,inclusion_tog必須要有一下三步準備
1.在應用下創建一個名為templatetags文件夾
2.在該文件夾創建任意名稱的py文件
3.在該py文件內編寫自定義相關代碼
from django.template import Library
register = Library()
2.自定義過濾器filter,最多能有倆個參數
# mytag.py
from django import template
register = template.Library()
# 參數 過濾器 過濾器名字
@register.filter(name='myfiltermyfilter')
def my_add(a, b):
return a + b
# index.html頁面使用
載入自定義文件名
{% load mytag %}
<p>{{ i|myfilter:1 }}</p>
3.自定義標簽(函數)
# 參數 標簽(函數)標簽(函數)名字
@register.simple_tag(name='mt')
def func(a, b, c, d):
return a + b + c + d
載入自定義文件名
{% load mytag %}
{% mt 1 2 3 4 %}
4.自定義inclusion_tag
當html頁面某一個地方的頁面需要傳參數才能夠動態的渲染出來,並且在多個頁面上都需要使用到該局部
@register.inclusion_tag(filename='it.html')
def index(n):
html = []
for i in range(n):
html.append('第%s頁'%i)
return locals() # 將html傳給filename這個頁面,然後可以在那個頁面上使用
載入自定義文件名
{% load mytag %}
{% index 10 %}
filename是作用於一個頁面,這個頁面可以不是一個完整的頁面,只是一部分,
6.模板的繼承
1.什麼是模板的繼承
你需要事先在你想要使用的主頁面上劃定區域做好標記,之後在子頁面繼承的時候你就可以使用在主頁面劃定的區域,也就意味著,如果你不劃定任何區域,那麼你子頁面將無法修改主頁面內容
2.如何使用模板的繼承
1.先在你想要繼承的主頁面上通過bolck劃定你將來可能要改的區域,並做好標記
2.在子頁面上繼承extends,利用block自動提示選取你想要修改的內容區域標記名稱
3.在子頁面extends中寫你要修改主頁面標記區的代碼
4.然後就可以讓子頁面的修改內容渲染到主頁面的劃定區域上
# 模板頁面提前先寫好將來可能要替換的內容
{% block 名字 %}
"""模板內容"""
{% endblock %}
# 新頁面要基於模板頁面替換的內容
{% extends 'html文件名' %}
{% block 名字 %}
"""子板內容"""
{% endblock %}
"""一般情況下母板中至少應該有三個區域使得擴展性更高!!! css content js"""
{% block css %}
<style>...</style>
{% endblock %}
{% block content %}
...
{% endblock %}
{% block js %}
<script>...</script>
{% endblock %}
'''子板中還可以使用母板的內容 {{ block.super }} '''
7.模板的導入
1.模板導入
將頁面的某一個局部當成模塊的形式
哪個地方需要就可以直接導入使用即可
2.導入格式
{% include '導入html文件名' %}