Python框架—Django

前言

框架(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 創建方法

  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			// 更新數據庫
  1. 創建方法二
    直接在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返回給前端
  • 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所映射到的處理函數

參數三:傳給函數的參數(選用)

  1. 無名參數 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)
  1. 有名參數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)
  1. 默認參數
# 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 常見報錯

  1. 路徑找不到時,導入出錯等,涉及到tuple錯誤時,注意settings中元組類型的變量,最後是不是加了逗號
  2. 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',
]
  1. 提交表單報錯:

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地址改爲斜槓結尾的就可以了

  1. 數據庫錯誤

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

關聯查詢 __雙下劃線用法:

  1. 對主表
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')
  1. 對從表
# 通過從表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的特點:

  1. 可迭代的
  2. 可切片
  • 迭代器
    因爲查詢的對象雖然沒有執行sql語句,但是都是保存在緩存池中,爲了防止緩存過多,都用迭代器取值,
obj = Book.objects.filter(id=2)
for obj.iterator():
	pass
  • 聚合查詢和分組查詢
  1. 聚合查詢:aggregate(*args, **kwargs)
from django.db.models import Avg, Min, Max, Sum
# 求所有書價格平均值
models.Book.objects..all().aggregate(Avg('price'))		# {'price_avg': 123.11}
  1. 分組查詢:annotate
# 根據作者名字分組,再按各個名字出書的價格計算平均值
models.objects.values('authors__name').annotate(Avg('price'))
  • F查詢與Q查詢
  1. F查詢
    對對象中的某列值操作
from django.db.models import F
# 對一列查詢集integer數據全部修改
models.Book.objects.all().update(price=F('price')+20)		# book中所有價格增加20
  1. 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數據庫

  1. 關聯本地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',
        
    }
}
  1. 導入mysql模塊
# FILE: app/__init__.py
import pymysql


pymysql.install_as_MySQLdb()

七、COOKIES/SESSION

7.1 cookie是什麼?

保存在用戶瀏覽器上的鍵值對

服務端根據cookie內容來判斷識別用戶登錄狀態等信息

可以利用來做登錄

  1. 保存在用戶瀏覽器
  2. 可以主動清除
  3. 可以被“僞造”
  4. 跨域名不共享
  5. 瀏覽器可以設置不接受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
裝飾器認證登錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章