文章目录
前言
框架(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
装饰器认证登录