文章目錄
前言
框架(framework)的作用:省去重複代碼的過程,使用框架可以快速開發特定的系統。
DRP:Don’t Repeat Yourself!
注意:理解所有註釋內容
一、Python基本框架WSGI
1.1 WSGI(Web Server Gateway Interface)接口
from wsgiref.simple_server import make_server
# url指向的後端方法
def application(environ, start_response):
# 通過environ封裝成一個所有請求信息的對象
# start_response可以很方便地設置響應頭
start_response('200 OK', [('Content-Type', 'text/html')])
# 字典取請求信息:environ['path']==
path = environ['PATH_INFO']
if path == '/book1':
return [b'<p>content1</p>']
elif path == '/book2':
return [b'<p style="color:red;">content2</p>']
else:
return [b"<p style='color:red;'>404</p>"]
# 封裝socket對象及準備過程(scoket, bind, listen)
httpd = make_server('', 8000, application) # url/port/function
# 開始監聽http請求:
httpd.serve_forever()
1.2 升級功能
在上面的代碼基礎上分離完善框架各種功能,使框架功能分明,更方便使用和修改
from wsgiref.simple_server import make_server
import time
def func1(request):
"""單獨寫各個url對應的方法"""
return [b'<p style="color:red;">content1</p>']
def func2(request):
return [b'<p style="color:red;">content2</p>']
def current_time(request):
time_now = time.ctime(time.time())
with open('current_time.html', 'r') as f:
data = f.read()
data = data.replace('!time!', str(time_now)) // 模板語言,動態修改html
return [data.encode('utf8')]
def routers():
"""將所有url與對應的方法以元組返回"""
urlpatterns = ( // 所有url對應的函數
('/content1', func1),
('/content2', func2),
('/current_time', current_time),
)
return urlpatterns
def application(environ, start_response):
"""
environ:request, 從瀏覽器返回的信息,鍵值對,用字典方法取出
start_response: 返回給瀏覽器的相應信息
return:後端處理之後的html
"""
# 通過environ封裝成一個所有請求信息的對象
# 字典取請求信息:environ['path']==
# start_response可以很方便地設置響應頭
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ['PATH_INFO']
urls = routers()
func = None
for item in urls: # 循環所有url路徑,執行url需求的函數
if item[0] == path:
func = item[1]
break
if func:
return func(environ)
else:
return [b'<p style="color:red;">404</p>']
# 封裝socket對象及準備過程(scoket, bind, listen)
httpd = make_server('', 8000, application)
# 開始監聽http請求(固定用法):
httpd.serve_forever()
MVC模式
MTV模式
二、Django
2.1 創建方法
- 創建方法一
django-admin startproject mysite // 創建django項目
python manage.py startapp f1 // 在django項目中創建f1功能塊
python manage.py runserver 127.0.0.1/8080 // 啓動django項目,設置url/port,url不寫時,默認爲本地
python manage.py makemigrations // 創建數據庫
python manage.py migrates // 更新數據庫
- 創建方法二
直接在pycharm中創建django項目
2.2 文件介紹
2.2.1 django項目文件解析
- funcName:網站各個功能文件夾,可能有多個,都有相同的文件,用於寫不同的功能
- migrations
- init.py:
- admin.py:
- apps.py:
- models.py:創建數據庫
- tests.py:
- views.py:不同url指向的方法,在這裏進行後端處理html,並將處理之後的html返回給前端
- migrations
- mysite
- settings:配置文件(路徑等)
- urls:路徑映射,就是網站各個路徑指向的函數的元組
- wsgi:python的基本網站框架,完成各種底層功能
- manage.py:功能接口,用於創建項目、數據庫等操作
- templates:所有的html放在這個文件夾
2.2.2 URL
url參數
# FILE:/urls.py
from django.contrib import admin
from django.urls import path
from blog import views
urlpatterns = [
path('admin/', admin.site.urls),
path(r'^info/', views.info, para, alias),
]
path(r'^info/', views.info, para, alias),
參數一:正則表達式,匹配相應的url,可能同一類的url都交給一個函數處理
參數二:url所映射到的處理函數
參數三:傳給函數的參數(選用)
- 無名參數 no-name
多個括號中的匹配內容按順序傳給函數,函數中參數名可自定義
# FILE:/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path(r'^info/([\d]{4})/([\d]{2})', views.info),
]
# 正則中,括號中的值會作爲para傳給映射函數view.info(),多個括號,函數中就需要接收多個參數
# para始終爲字符串類型
# FILE:/views.py
# 在映射函數中直接使用
def info(req, para1, para2):
return HttpResponse(para)
- 有名參數Named Group
命名分組後,傳入的參數必須按照組名傳入,但是可以不管順序,
# FILE:/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path(r'^info/(?P<year>[\d]{4})/(?P<month>[\d]{2})', views.info),
]
# FILE:/views.py
def info(req, month, year):
return HttpResponse(year + month)
- 默認參數
# FILE:/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path(r'^info/', views.info, {'name': 'wolf'}),
]
# FILE:/views.py
def info(req, name):
return HttpResponse(name)
# 這裏的參數name必須和默認參數中的key相同
如果同時有默認參數和有名參數,且命名一樣,默認參數會覆蓋掉有名參數
參數四:url別名(選用)
# FILE:/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path(r'^info/', views.info, {'name': 'wolf'}, name='user_info'),
]
# url別名,即127.0.0.1:8000/info == 127.0.0.1:8000/user_info
用法:
<form action={% url "wolf" %} method='post'> <!--可以用/user_info代替原/url,後端在修改url代碼時,前端可以一直用/user_info這個url登錄,-->
</form>
路由分發
# FILE:/mysite/urls.py
"""
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, include
from blog import views
urlpatterns = [
path('admin/', admin.site.urls),
path(r'blog/', include('blog.urls')),
# 將blog APP下的所有鏈接,分發到blog文件夾下的urls文件,以後由/blog/鏈接進來的都到blog/urls.py處理,映射函數就寫到blog/urls.py中
# /mysite/urls.py只用於路由分發,映射函數寫到app/urls.py中
]
# FILE:blog/urls.py
from django.urls import path
from blog import views
urlpatterns = [
path(r'info/', views.info),
]
2.2.3 靜態文件 statics
# FILE:/settings
STATIC_URL = '/static/' //這裏的命名須要和src='/static/js/jquery-3'中的static相同,這是下面statics的別名,
STATICFILES_DIRS = (
os.path.join(BASEDIR, 'statics'), // 這裏的路徑statics須要和自己創建的靜態文件夾名相同
)
2.2.4 VIEWS
REQUEST的方法與屬性
request.method # POST/GET
request.POST.get() # 字典方法
request.GET
request.path
request.FILES
request.COOKIES
request.user
request.session
locals()
多個變量須要在render渲染時,直接加入local()就可以了,但是效率相對會低一些
return render(request, 'xx.html', local())
render_to_response
return render_to_response('xx.html') # 少些一個request,其餘一樣
return render(request, 'xx.html')
redirect()
重定向
return redirect('www.baidu.com') # 跳轉頁面
2.3 常見報錯
- 路徑找不到時,導入出錯等,涉及到tuple錯誤時,注意settings中元組類型的變量,最後是不是加了逗號
- Forbidden錯誤:
註釋掉 ‘django.middleware.csrf.CsrfViewMiddleware’,
如下:
# FILE: mysite/settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
- 提交表單報錯:
RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set.
RuntimeError:您通過POST調用了這個URL,但是URL沒有以斜槓結尾,並且您設置了append_slash。
解決方法: 將from的action地址改爲斜槓結尾的就可以了
- 數據庫錯誤
TypeError: init() missing 1 required positional argument: ‘on_delete’
在django2.0後,定義外鍵和一對一關係的時候需要加on_delete選項,此參數爲了避免兩個表裏的數據不一致問題。
k= models.ForeignKey('Class',on_delete=models.CASCADE) # 在老版本這個參數(models.CASCADE)是默認值
"""
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值
CASCADE:級聯刪除。
PROTECT:報完整性錯誤。
SET_NULL:外鍵設置爲null,前提是允許爲null。
SET_DEFAULT:設置爲外鍵的默認值。
SET():會調用外面的值,可以是一個函數。
"""
三、模板語言
四、ORM(對象關係映射)
優點:1.使我們更簡單的跟數據庫交互
2.避免新手程序員寫sql語句帶來的性能問題
4.1創建單表
- 一對一
# FILE: app/medels.py
class Table(models.Model):
name = models.CharField(max_length=64)
pwd = models.CharField(max_length=64)
- 一對多
# FILE:models.py
class Book(models.Model):
name = models.CharField(max_length=64)
price = models.IntegerField()
# price = models.IntegerField(null=True)
publisher = models.ForeignKey('Publish') # 參數爲另一個表類,一對多關係建立,創建外鍵,添加鍵值看 *增* 中的代碼
author = models.ManyToManyField('Author') # 參數爲另一個表類,創建多對多關係,django自己創建第三張多對多關係的表
- 多對多
def info(req):
# 取到2個作者對象
author1 = models.Author.objects.get(id=1)
author2 = models.Author.objects.get(id=2)
# 取到一個書的對象
book = models.Book.objects.filter(id=3)[0]
# 將對應關係添加到多對多關係表中
book.author.add(author1,author2)
# book.author.add(*[author1,author2])
# 刪除多對多數據
book.author.remove(author1,author2)
自動創建用上面的models.ManyToManyField()
手動創建多對多關係表
class Book(models.Model):
name = models.CharField(max_length=64)
class Author(models.Model):
author = models.CharFeild(max_length=64)
# 手動創建第三張表,建立2個外鍵,達到多對多的關係
class BookToAuthor(models.Model):
book = models.ForeignKey('Book')
author = models.ForeignKey('Author')
聯合唯一
class BookToAuthor(models.Model):
author = models.ForeignKey('Author')
book = models.ForeignKey('Book')
class Meta:
unique_together = (
(book, author),
(),
) # 支持多個聯合唯一
一對多改一對一
給一對多的鍵加上(unique=true),將其設置爲唯一,就是一對一了。
4.2 字段類型參數
4.3 Field重要參數
4.4 總結
- 多對多:
ManyToManyField:或者通過2個ForeignKey手動創建(更方便查詢)
- 一對一:
通過1個ForeignKey和unique=true
4.5 增刪改查
增:creat、save
def info(req):
# 創建方式一
Table.objects.creat(
name = 'book1'
price = 89
pwd = '123'
publisher_id = 4 # 外鍵存值時,要加_id,django保存值的時候是存到publisher_id下
# 或者
publisher = pub[0] # 從數據庫的從表中取到對應的外鍵對象,如果不加_id,對應的賦值必須是一個對象
)
# 創建方式二*
Table.objects.creat(**{'name': 'book1', 'price': 89})
# 創建方式三
t = Table(name='book1')
t.save()
# 創建方式四
t = Table()
t.name = 'book1'
t.save
return render(req, 'html')
刪:delete、filter
級聯刪除:刪除數據的同時,其他表中與其相關的數據也會刪除
Table.objects.filter(id=1).delete() # 刪除id=1的整行數據
改:update、save、get
# 方法一
# 1.先查值
book1 = Table.objects.get(id=1)
# 2.修改值
book1.name = 'book2'
# 3.保存
book1.save()
# 方法二*
Table.objects.filter(name='book1').update(name='book2')
注意: 1.get方法沒有update對象,不能使用update方法,filter取到的是一個QuerySet對象,可能有多個滿足條件的數據。
2. save()方法會更新一行裏所有的列,而某些時候我們只需要更新行裏的某幾列。
查
Table.objects.
filter(**kwargs) # 包含所有滿足篩選條件的對象
all() # 查詢所有結果
get(**kwargs) # 返回滿足條件的對象,如果滿足條件的有多個或沒有,都會報錯
values(*field) # value('name') 返回一個ValueQuerySet,一個特殊的QuerySet,運行後得到的並不是一系列model的實例化對象,二十一個可迭代的字典序列
exclude(**kwargs) # 所有不滿足篩選條件的對象
order_by(*field) # order_by('id');通過id反向排:order_by('-id');對查詢結果排序
reverse() # 對查詢結果反序
disinct() # 從返回結果中剔除重複記錄
values_list(*field) # 類似values(),返回一個元組序列
count() # 返回匹配條件的對象數量
first() # 返回第一條記錄
last() # 返回最後一條記錄
exists() # 如果Queryset包含數據,就返回True,否則返回False
關聯查詢 __雙下劃線用法:
- 對主表
filter(id__gt=2) # id>2的查詢集/id__lt
filter(id__in=[1,2,3])
filter(id__range=(1, 5))
filter(name__contains='wolf')
filter(name__icontaions='Wolf') # 對大小寫不敏感
filter(name__startwith='wo')
示例:
# Book表中,名字含有python的對象,對應的發佈城市
models.Book.objects.filter(name__icontaions='pYthon').value('publisher__city')
- 對從表
# 通過從表Publish取主表Book中name爲Python並且pubtime爲20010101的對象,
models.Publish.objects.filter(book__name='Python',book_pubtime='20010101')
book與author爲一對多關係時:
正向查詢
book.author.add() # 通過book的author一對多關係查找
book.author.remove()
反向查詢
但是在author中沒有book關係的建立,如果我們須要通過author反向查找book對象:
author.book_set.add() # 通過給book加_set指代book對象,book小寫,其他地方取表時,都是類名,都是首字母大寫,這裏都用首字母小寫
author.book_set.remove()
基於django創建第三張多對多表時,對第三張表的操作:
# 作者表
class Author(models.Model):
name = models.CharField(max_length=64)
# 書籍表
class Book(models.Model):
name = models.CharField(max_length=64)
ba = ManyToManyField('Author') # django創建第三張多對多關係表
通過Book表經過Author表對第三張表進行增刪改操作
# 獲取書籍對象
obj = models.Book.objects.filter(id=1)
# 操作
obj.ba.add(5) # 爲Book中id=1的對象增加Author中id=5的數據
obj.ba.add(*[5,6,7])
obj.ba.add([5, 6, 6])
# 刪
obj.ba.remove(5)
obj.ba.clear() # 清除第三張表中所有Book_id=1的數據
# 改
obj.ba.set(*[5,6,7]) # 將第三張表中所有Book_id=1的數據改爲5,6,7,原來有的不變,原來沒有的增加,原來多餘的刪除
4.6 補充
- 惰性機制
.object.all()或者.filter()等都是返回了一個QuerySet(查詢集),他並不會馬上執行sql,而是當調用QuerySet的時候才執行。
QuerySet的特點:
- 可迭代的
- 可切片
- 迭代器
因爲查詢的對象雖然沒有執行sql語句,但是都是保存在緩存池中,爲了防止緩存過多,都用迭代器取值,
obj = Book.objects.filter(id=2)
for obj.iterator():
pass
- 聚合查詢和分組查詢
- 聚合查詢:aggregate(*args, **kwargs)
from django.db.models import Avg, Min, Max, Sum
# 求所有書價格平均值
models.Book.objects..all().aggregate(Avg('price')) # {'price_avg': 123.11}
- 分組查詢:annotate
# 根據作者名字分組,再按各個名字出書的價格計算平均值
models.objects.values('authors__name').annotate(Avg('price'))
- F查詢與Q查詢
- F查詢
對對象中的某列值操作
from django.db.models import F
# 對一列查詢集integer數據全部修改
models.Book.objects.all().update(price=F('price')+20) # book中所有價格增加20
- Q查詢
Q封裝之後用 & | ~(and or not)方法
from django.db.models import Q
models.Book.objects.filter(Q(author='wolf') & (Q(title__startwith='P')|Q(title__startwith='G')))
# 再加上之前的過濾方法
models.Book.objects.filter(Q(author='wolf') & (Q(title__startwith='P')|Q(title__startwith='G')),
color='red') # Q方法必須放在前面
五、admin的配置
admin.py:可視化地與數據庫交互
當我們進入鏈接127.0.0.1:8000/admin時:
這裏是django的管理員登錄頁面
5.1 初始化管理員用戶
運行代碼:
python manage.py createsuperuser
# 按提示創建管理員賬戶
-->Username (leave blank to use 'wolf_'):
-->Email address:
-->Password:
-->Password (again):
-->Superuser created successfully.
5.2 加入表格
from django.contrib import admin
# Register your models here.
from blog.models import *
# 將表格關聯到django的網頁
admin.site.register(Book)
admin.site.register(Publish)
admin.site.register(Author)
5.3 添加數據
點擊Books:
添加數據
注意: 網頁中選擇框中的數據爲models.py中,類的__str__方法的返回值,默認是一個對象object,即:
class Book(models.Model):
name = models.CharField(max_length=64)
def __str__(self):
return self.name
5.4 自定義顯示內容
- 自定義顯示類
from django.contrib import admin
# Register your models here.
from blog.models import *
class MyAdmin(admin.ModelAdmin):
list_display = ('b_name', 'price', 'publisher')
admin.site.register(Book, MyAdmin) # 在這裏傳入顯示格式
admin.site.register(Publish)
admin.site.register(Author)
- 加搜索框,可用的搜索項根據需求添加,filter功能
search_fields = ('title', 'price')
- 加入過濾信息
list_filter = ('state_province', )
- 排序規則
ordering = ('-id', )
- 自定義標題名
# 加入verbose_name參數,設置標題
# editable數據是否可以更改
class Book(models.Model):
b_name = models.CharField(max_length=64, verbose_name='書名', editable=Flase)
price = models.IntegerField(verbose_name='價格')
publisher = models.ForeignKey(Publish, on_delete=models.CASCADE, verbose_name='出版社')
author = models.ManyToManyField('Author')
def __str__(self):
return self.b_name
六、關聯Mysql數據庫
- 關聯本地mysql
# FILE:settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': mysql_database_name, # 數據庫名字
'HOST': ' 192.168.1.4', # 本機IP
'PORT': 3306,
'USER': 'root',
'PASSWORD': '666',
}
}
- 導入mysql模塊
# FILE: app/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
七、COOKIES/SESSION
7.1 cookie是什麼?
保存在用戶瀏覽器上的鍵值對
服務端根據cookie內容來判斷識別用戶登錄狀態等信息
可以利用來做登錄
- 保存在用戶瀏覽器
- 可以主動清除
- 可以被“僞造”
- 跨域名不共享
- 瀏覽器可以設置不接受cookie
7.2 服務器端操作cookie
cookie的基本應用
from django.shortcuts import render, redirect
from app01 import models
# Create your views here.
def login(request):
models.Administrator.objects.create(
username='jenny',
pwd='666'
)
tip = ''
if request.method == 'POST': # 提交數據時進入
username = request.POST.get('user') # 獲取用戶輸入的username
pwd = request.POST.get('pwd') # 獲取用戶輸入的pwd
c = models.Administrator.objects.filter(username=username, pwd=pwd).count() # 用戶輸入的id和pwd是否在數據庫中
if c: # 如果存在
rep = redirect('/app01/index.html') # 跳轉到登錄成功頁面
rep.set_cookie('username', username) # 給瀏覽器設置cookie
return rep
else: # 如果不存在
tip = '用戶名或密碼錯誤!' # 提示錯誤信息
return render(request, 'login_.html', {'tip': tip}) # 返回到登錄頁面
return render(request, 'login_.html')
def index(request):
username = request.COOKIES.get('username') # 當直接鏈接登陸成功頁面時,檢測是否有服務端設置的鍵值對
if username: # 如果有,直接進入登錄成功頁面
return render(request, 'index_.html', {'username': username})
else: # 如果沒有,跳轉到登錄頁面
return redirect('/app01/login.html')
cookie的參數
from django.shortcuts import render, redirect
from app01 import models
import datetime
# Create your views here.
def login(request):
models.Administrator.objects.create(
username='jenny',
pwd='666'
)
tip = ''
if request.method == 'POST':
username = request.POST.get('user')
pwd = request.POST.get('pwd')
c = models.Administrator.objects.filter(username=username, pwd=pwd).count()
if c:
rep = redirect('/app01/index.html')
v = datetime.datetime.utnow() + datetime.timedelta(seconds=10)
rep.set_cookie('username', username, max_age=10, expires=v, path='/', domain='wolf.com', secure=False; httponly=True)
"""
max_age: 失效時間(秒/s)
expires: datetime.datetime.utnow() + datetime.timedelta(seconds=10)
// 瀏覽器支持max_age就用max_age,不支持就用expires #, 不寫,django會根據max_age幫我們寫上expires
path: 默認='/',表示在全局生效;加上url表示只有當前url可以訪問此cookie設置
domain:None;cookie保存到的域名,默認爲當前訪問域名,不可以給同級域名設置cookie,可以指定爲頂級域名
secure:False;以https訪問時設置,這裏設置成True;安全相關
httponly: False,只能通過服務端修改,不能在客戶端修改,但是客戶端可以直接覆蓋,並不安全
// 如果設置cookie時,httponly=True,在瀏覽器上不能獲取到該cookie,但是抓包可以抓到,所以並不安全
"""
return rep
else:
tip = '用戶名或密碼錯誤!'
return render(request, 'login_.html', {'tip': tip})
return render(request, 'login_.html')
def index(request):
username = request.COOKIES.get('username')
if username:
return render(request, 'index_.html', {'username': username})
else:
return redirect('/app01/login.html')
域名
- 頂級域名:wolf.com
- 二級域名:www.wolf.com / crm.wolf.com
- url:www.wolf.com/login.html / www.wolf.com/index.html
設置主機域名別名:用自己設置的域名代替127.0.0.1
7.3 前端操作cookie
jQuery-cookie文檔下載:
jQuery-cookie
jQuery-cookie-GitHub
導入到html中,在前端:
$.cookie // 查詢cookie
$.cookie('key') // 獲取cookie值
$.cookie('key', 'value') // 添加設置cookie
$.cookie('key', 'value', {'path': '/'}) // 設置參數
// expires:可以填時間,也可以填js的時間對象,例:d = new Date()
7.4 敏感信息
- 普通信息,如用戶暱稱等,直接放在cookie中
- 簽名cookie,加密,但信息依然在cookie中,可能被解密
# 不加密操作
rep.set_cookie()
request.COOKIEs.get()
# 加密操作
rep.set_signal_cookie()
request.get_signal_cookie()
- 敏感信息不宜放在cookie中,敏感信息放在數據庫中,頻繁操作數據庫,服務器壓力大
- 敏感信息處理方法:session
7.5 session
簡單來說,session就是將本來要設置到cookie的信息,經過base64編碼後,保存在一個django_session的表中存在於服務器上,然後將該數據的主鍵設置到cookie中,保存到用戶的瀏覽器上;二次訪問時,通過django_session的主鍵id得到之前是否保存session信息,從而得到本來想保存到cookie的用戶信息。
- 保存在服務器上的鍵值對
- session的唯一標識碼保存在cookie中
- session也有失效時間,默認爲兩個星期
# 設置session
request.session['username'] = 'wolf'
# 獲取session
username = reqeust.session['username']
# get獲取session
username = request.session.get('鍵', 默認值)
# 清除session
# 刪除值的部分,主鍵仍在
request.session.clear()
# 刪除整條數據
request.session.flush()
# 根據鍵刪除鍵和值
del request.session['key']
# 設置失效時間,默認14天
request.session.set_expiry(value)
# 判斷session中是否存在某個鍵值對
request.session.has_key('key')
"""
value=int, 在沒有活動的int秒後失效
value=0,在瀏覽器關閉時失效
value=None,在14天后過去
"""
// 創建表、保存數據、獲取數據等操作django都做好了,只需要用session就行了
八、CBV(class base view)
依賴於類的django:
CBV的類父類方法 dispatch() 會根據請求頭的method方法,來分發處理函數,
在類中按不同函數名對應寫處理函數
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
from django.shortcuts import render, redirect
from edu import models
from django import views
from django.utils.decorators import method_decorator
# Create your views here.
# 登錄驗證裝飾器函數
def outer(func):
def inner(request, *args, **kwargs):
log_state = request.session.get('is_login', 'False')
if log_state:
return render(request, 'base.html')
else:
return render(request, 'login.html')
# @method_decorator(outer, name="dispatch") # 加裝飾器的方法三
@method_decorator(outer, name="post") # 加裝飾器的方法三
class Login(views.View):
# @method_decorator(outer) # 驗證方法二:在django請求分發之前做登錄驗證,相當於給每一種請求方法加裝飾器
# def dispatch(self, request, *args, **kwargs):
# super(Login, self).dispatch(self, *args, **kwargs)
# @method_decorator(outer) # 驗證方法一:在每一個請求前加一個登錄驗證的裝飾器
def get(self, request, *args, **kwargs):
username = request.session.get('username', "")
return render(request, 'login.html', {'username': username})
# @method_decorator(outer) # 驗證方法一:在每一個請求前加一個登錄驗證的裝飾器
def post(self, request, *args, **kwargs):
username = request.POST.get('username')
pwd = request.POST.get('password')
# remember = request.POST.get('remember')
c = models.Student.objects.filter(username=username, password=pwd)
if c:
print(c)
rep = redirect('/edu/home_page.html/')
request.session['username'] = username
return rep
else:
tip = '用戶名或密碼有誤!'
return render(request, 'login.html', {'tip': tip})
def get(self, request, *args, **kwargs):
pass
依賴CBV時,url路由方式:
from django.urls import path
from edu import views
urlpatterns = [
path(r'login.html/', views.Login.as_view()),
path(r'home_page.html/', views.Manage.as_view()),
]
九、上傳文件
form表單上傳
# FILE:/views.py
def upload(request):
if request.method == 'GET':
"""
get請求
從數據庫獲取圖片路徑,返回給前端
"""
img_path = models.Img.objects.all()
return render(request, 'upload.html', {'img_path': img_path})
elif request.method == 'POST':
""" 獲取上傳圖片,保存,並將其路徑保存到數據庫"""
# post請求
# name = request.POST.get('name')
# 獲取文件對象
obj = request.FILES.get('file')
# 分配文件保存地址
img_path = os.path.join('statics', 'upload', obj.name)
# print(img_path)
# 保存文件
with open(img_path, 'wb') as f:
for data in obj.chunks():
f.write(data)
# 將文件路徑保存到數據庫
models.Img.objects.create(img_path=img_path)
return redirect('/upload.html')
ajax上傳
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload</title>
</head>
<body>
form表單上傳部分:
<form action="/upload.html/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="name"><input type="file" name="img">
<input type="submit" value="Form提交">
</form>
ajax上傳部分:
<div>
<input id="img" type="file" name="file">
<input type="button" id="ajax_btn" value="ajax-提交">
</div>
<div id="imgs">
{% for foo in img_path %}
<img src="/{{ foo.img_path }}" style="height:200px;width:200px;">
{% endfor %}
</div>
</body>
</html>
<script src="/statics/jq/jquery-3.4.js"></script>
<script>
$(function(){
$("#ajax_btn").click(function(){
var formdata = new FormData;
formdata.append('name', '111');
formdata.append('img', document.getElementById('img').files[0]);
formdata.append('csrfmiddlewaretoken', '{{ csrf_token }}');
$.ajax({
url: '/upload.html/',
type: 'POST',
data: formdata,
processData: false,
contentType: false,
dataType: "JSON",
success: function(rep){
if(rep.status){
var ele = document.createElement('img');
ele.src = '/' + rep.img_path;
$('#imgs').append(ele);
}
}
})
})
})
</script>
基於form表單和iframe自己實現ajax請求
利用iframe通道用傳統form表單實現刷新數據不刷新頁面——即實現ajax請求
九、其他
chrome插件:postman
裝飾器認證登錄