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
装饰器认证登录

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