文章目录
Django限制请求方法
常用的请求method
- GET请求:GET请求一般用来向服务器索要数据,但不会向服务器提交数据,不会对服务器的状态进行更改。比如像服务器获取某篇文章的详情。
- POST请求:POST请求一般是用来向服务器提交数据,会对服务器的状态进行更改。比如提交一篇文章给服务器。
当采用GET请求发送时
当采用POST请求方式发送时
需要注意的:在Django中默认会开启CSRF安全防护,我们在暂时可以先关闭这个防护
采用Postman软件方式发送
限制请求装饰器
Django内置的视图装饰器可以给视图提供一些限制。比如这个视图只能通过GET的metho访问等。
- 导入限制请求装饰器
from django.views.decorations.http import require_http_method
# require_http_methods 只能传get请求和post请求
# require_http_methods(['GET']) = require_GET
# require_http_methods(['POST']) = require_POST
require_http_methods['GET','POST']
: 该参数只能传入get、post请求。该装饰器需要传入一个允许访问的方法列表
from django.views.decorators.http import require_http_methods, require_GET, require_POST
# GET要大写
@require_http_methods(['GET']) # 限制请求为GET请求
def index(request):
# 当前情况下发送什么请求都会生效
# 当我们想限制请求时,可以导入限制请求装饰器
articles = Article.objects.all()
context = {
'articles': articles
}
return render(request, 'index.html', context=context)
require_POST
: 这个装饰器是require_http_methods(['POST'])
的简写形式,只允许使用POST的method来访问视图
from django.shortcuts import render
from .models import Article
from django.http import HttpResponse
# decorator : 代表着装饰器
from django.views.decorators.http import require_http_methods, require_GET, require_POST
@require_POST
def add_article(request):
# POST 后面的get是字典的相对应取值,如果没有将返回一个None,并不会报错
title = request.POST.get('title')
content = request.POST.get('content')
price = request.POST.get('price')
Article.objects.create(title=title, content=content, price=price)
return HttpResponse('成功')
require_GET
: 这个装饰器相对于是require_http_method['GET']
的简要形式,只允许使用GET的method来访问视图
from django.shortcuts import render
from .models import Article
from django.http import HttpResponse
# decorator : 代表着装饰器
from django.views.decorators.http import require_http_methods, require_GET, require_POST
# GET要大写
@require_GET # 限制请求为GET请求
def index(request):
# 当前情况下发送什么请求都会生效
# 当我们想限制请求时,可以导入限制请求装饰器
articles = Article.objects.all()
context = {
'articles': articles
}
return render(request, 'index.html', context=context)
简单的提交数据
# 限制请求使用GET和POST请求
@require_http_methods(['GET', 'POST'])
def add_article(request):
if request.method == 'GET':
return render(request, 'add_article.html')
else:
title = request.POST.get('title')
content = request.POST.get('content')
price = request.POST.get('price')
Article.objects.create(title=title, content=content, price=price)
return HttpResponse('成功')
add_artilce.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="{% url 'add_article' %}" method="post">
<table>
<tbody>
<tr>
<td>标题:</td>
<td><input type="text" name="title"></td>
</tr>
<tr>
<td>内容:</td>
<td><input type="content" name="content"></td>
</tr>
<tr>
<td>价格:</td>
<td><input type="text" name="price"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
页面重定向
重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。
永久重定向
永久性重定向:http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。
临时重定向
http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。
在Django中,重定向是使用redirect(to, *args, permanent=False, **kwargs)来实现的。to是一个url,permanent代表的是这个重定向是否是一个永久的重定向,默认是False。
from django.shortcuts import reverse,redirect
def profile(request):
if request.GET.get("username"):
return HttpResponse("%s,欢迎来到个人中心页面!")
else:
return redirect(reverse("user:front"))
HttpRequest对象
WSGIRequest对象
Django在接收http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequest对象,并且作为视图函数第一个参数传给视图函数。也就是我们经常看到的request参数。在这个对象上我们可以找到客户端上传上来的所有信息。这个对象的完整路径就是<class 'django.core.handlers.wsgi.WSGIRequest'>
WSGIRequest对象常用属性
path
: 请求服务器的完整路径,但不包括域名和参数method
: 返回服务器请求的方式COOKIES
: 返回cookie信息SESSION
: 返回session信息META
: 储存在服务器上的所有header信息
from django.http import HttpResponse
def login(request):
"""
WSGIRequest中的属性
该属性都是属于WSGIRequest中的实例化属性
path : 请求服务器的返回的路径,但不包括域名和参数
method : 返回服务器请求所使用的请求方式
COOKIES : 返回服务器的cookie信息
session : 返回服务器的session信息
cookie是存储在浏览器上的,而session是保存在服务器上的
"""
print(request.path) # /login/
print(request.method) # GET
print(request.COOKIES) # {'csrftoken': 'xzVoq0mrFra2zsXR0nXYu31zE21beTQebMmWt66UZqP544N5HbCJ4AXb3GekPDte'}
print(request.session) # <django.contrib.sessions.backends.db.SessionStore object at 0x000002C7F627BDD8>
return HttpResponse('这是登录页面')
WSGIRequest对象常用方法
get_full_path()
: 返回带参数的完整路径get_raw_uri()
: 返回请求完整的urlget_host()
:返回服务器的域名is_ajax()
: 判断该当前是否为ajax请求,如果是返回True,如果不是返回False。原理就是判断请求头中是否存在X-Requested-With:XMLHttpRequest
。is_secure()
: 是否采用http协议,如果是返回True,如果不是返回False。
from django.http import HttpResponse
def login_parameter(request):
"""
WSIGIRequest中的方法
该方法是在HttpRequest类下实现,而WSGIRequest继承于HttpRequest
get_full_path() : 返回完整的path该方法可以打印出带有参数的完整path路径
get_raw_uri() : 返回完整的url
get_host() : 返回域名
is_secure() : 判断当前请求是否为https请求,当为真时返回True,当为假时返回False
is_ajax() : 判断是否为ajax请求,当为真时返回True,当为假时返回False
"""
print(request.get_full_path()) # /login_parameter/?author=Small-J
print(request.get_raw_uri()) # http://127.0.0.1:8000/login_parameter/?author=Small-J
print(request.get_host()) # 127.0.0.1:8000
print(request.is_secure()) # False
print(request.is_ajax())
return HttpResponse('这是带参数登录')
HttpResponse对象
Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成应该HttpRequest对象传给视图函数。那么视图函数在处理完相关的逻辑后,也需要返回一个响应给浏览器。而这个响应,我们必须返回HttpResponseBase或者他的子类的对象。而HttpResponse则是HttpResponseBase用得最多的子类。
常用属性
-
content
: 返回的内容 -
start_code
: 指定返回的编码 -
content_type
: 返回的数据的MIME类型,默认为text/html。浏览器胡根据这个属性,来显示数据。如果是text/html,那么就会解析这个字符串,如果text/plain, 那么就会显示一个纯文本。常用的Conten-Type如下:text/html(默认的,html文件) text/plain(纯文本) text/css(css文件) text/javascript(js文件) multipart/form-data(文件提交) application/json(json传输) application/xml(xml文件)
-
responsep['X-Access-Token'] = xxx
: 设置请求头def front_views(request): """ HttpResponse对象中的属性 content: 返回内容 status_code: 返回的HTTP响应状态码 res['Username'] = 'Small-J' :这相当于在浏览器上直接设置请求对应的参数 """ res = HttpResponse(content_type='text/html;charset=gbk') res.content = '<h1>这是HttpResponse对象</h1>' res.status_code = 400 res['Username'] = 'Small-J' res['Password'] = '******' return res
常用方法
set_cookie
: 用来设置cookie信息delete_cookie
: 用来删除cookie信息write
: HttpResponse是一个类似于文件的对象,可以用来写入数据体content中
JsonResponse类
用来对象dump成json字符串,然后返回json字符串封装成Respone对象返回给浏览器。并且他的Content-Type就是applicatio/json
def json_views(request):
"""
JsonResponse对象的实现
Json对象可传入一个字典
"""
data = {
'Author': 'Small-J',
'create_time': '2020-07-13'
}
return JsonResponse(data=data)
注意:当传入列表的时候,Django会报出这一段信息:In order to allow non-dict objects to be serialized set the safe parameter to False. —> 为了允许序列化非dict对象,请将safe参数设置为False
def json_views(request):
"""
JsonResponse对象的实现
Json对象传入的是个列表的时候,需要使用safe为False情况
"""
data = ['Python', 'Python数据分析', 'PythonDjango实战']
return JsonResponse(data=data, safe=False)
类视图
在写视图的时候,Django除了会使用函数,也可以使用类作为视图。使用类视图可以使用类的一些特性,比如继承等。
View
django.views.generic.base.View
是主要的类视图,所有的类视图都是继承自他。如果我们写自己的类视图,也可以继承自他。然后再根据当前请求的method,来实现不同的方法。
- 这个视图只能使用get的方式来请求 :
get(self, request, *args, **kwargs)
- 这个视图只能使用post的方式来请求 :
post(self, request, *args, **kwargs)
# 类视图需要写一个类并且要继承于
# from django.view import View
class FrontViews(View):
"""
当我们发送请求的时候,发送get请求的时候会接受Get请求的时候
当发送Post请求的时候,会自动去接受post请求的数据,
Django会自动识别类中的方法Getd或者Post
"""
# 类中的方法必须要传入request
def get(self, request, *args, **kwargs):
return HttpResponse('这是类视图的get请求')
def post(self, request):
return HttpResponse('这是类视图的post请求')
类视图写完之后,还应该在urls.py中进行映射,映射的时候就需要调用View的类方法as_view()来进行转换。自动查找指定方法。
from django.urls import path
from . import views
urlpatterns = [
path('front/', views.FrontViews.as_view(), name='front_view')
]
TemplateView
django.views.generic.base.TemplateView
,这个类视图是专门用来返回模板的。在这个类中,有两个属性是经常需要用到的,一个是template_name
,这个属性是用来存储模板的路径,TemplateView
会自动的渲染这个变量指向的模板。另外一个是get_context_data
这个方法是用来返回上下文数据的,也就是在给模板传的参数的。
front/views
# 要继承于模板文件
class IndexTemplateView(TemplateView):
# 模板的名字
# 模板必须带后缀.html
template_name = 'home.html'
# 该方法是返回上下文数据
def get_context_data(self, **kwargs):
context = {'author': 'Small-J'}
return context
front/urls.py
# @Time : 2020/7/14 20:22
# @Author : Small-J
from django.urls import path
from . import views
from django.views.generic.base import TemplateView
urlpatterns = [
# 当使用类视图的时候必须要使用as_view这个方法
path('', views.IndexView.as_view(), name='IndexView'),
# 如果以后在模板中不需要传递任何参数,那么建议在urls中使用TemplatesView模板
# path('about/', views.IndexTemplateView.as_view('home.html'))
# 当需要传递参数时
path('about/', views.IndexTemplateView.as_view())
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>作者: {{ author }}</p>
</body>
</html>
ListView
在网站开发过程中,经常会出现列表某个表的一些数据作为列表展示出来。
model
: 重写model这个类属性,指定这个列表是给哪个模型的template_name
: 指定这个列表对应的模板名字paginate_by
: 指定这个列表一夜中展示多少条数据context_object_name
: 指定这个列表模型在模板中的参数名称ordering
: 指定页面的排序方式page_kwarg
: 获取第几页的数据的参数名称。默认是pageget_content_data
: 获取上下文的数据get_queryset
: 如果你提取数据的时候,并不是要把所有数据都返回,重写这个方法,可以将一些不需要展示的数据给过滤掉
# 继承列表模板
class IndexListView(ListView):
# 列表页要使用的模型
model = Article
# 对应映射的模板文件
template_name = 'article_list.html'
# 指定列表中在模板中的参数名称
context_object_name = 'articles'
# 展示页面的排序方式
ordering = 'create_time'
# 每次页面翻页的数据
paginate_by = 10
# 对应的翻页参数
page_kwarg = 'page'
# 该方法重写上下文数据
def get_context_data(self, **kwargs):
content = super(IndexListView, self).get_context_data(**kwargs)
print('-'*100)
print(content)
print('-'*100)
return content
# 该方法限制返回的参数
def get_queryset(self):
return Article.objects.filter(pk__lte=89)
from django.urls import path
from . import views
urlpatterns = [
path('list/', views.IndexListView.as_view())
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{# 该for循环中的articles为类中的context_object_name的值#}
{% for article in articles %}
<p>{{ article.title }}</p>
{% endfor %}
</ul>
</body>
</html>
Paginator 和Page类
Paginator和Page类都是用来做分页的。他们在Django中的路径为djngo.core.paginator.Paginator
和 django.core.paginator.Page
。以下对两个类的常用属性和方法做解释。
Paginator常用属性和方法
count
: 总共有多少条数据num_page
: 总共有多少页数据page_range
: 页面的区间
# 继承列表模板
class IndexListView(ListView):
# 列表页要使用的模型
model = Article
# 对应映射的模板文件
template_name = 'article_list.html'
# 指定列表中在模板中的参数名称
context_object_name = 'articles'
# 展示页面的排序方式
ordering = 'create_time'
# 每次页面翻页的数据
paginate_by = 10
# 对应的翻页参数
page_kwarg = 'page'
# 该方法重写上下文数据
def get_context_data(self, **kwargs):
"""
Paginotar
count : 总共有多少条数据 ---> 对应数据库100条数据
num_pages:总共有多少页数据 ---> 因为数据库中一共有一百条数据,然后paginate_by每翻一次页的数据为10条
page_range:页面的区间--->左闭右开的原则
"""
content = super(IndexListView, self).get_context_data(**kwargs)
print('-'*100)
paginator = content.get('paginator')
# print(paginator.count) # 100
# print(paginator.num_pages) # 10
print(paginator.page_range) # range(1, 11)
print('-'*100)
return content
Page常用属性和方法
has_next()
: 是否还有下一页,有的返回Truehas_previous()
: 是否还有上一页number
: 当前页数start_index()
: 返回当前页数的第一条数据索引值end_index()
: 返回当前页数的最后一条数据的索引值next_page_number()
: 下一页的页码previous_page_number
: 上一页的页码
# 继承列表模板
class IndexListView(ListView):
# 列表页要使用的模型
model = Article
# 对应映射的模板文件
template_name = 'article_list.html'
# 指定列表中在模板中的参数名称
context_object_name = 'articles'
# 展示页面的排序方式
ordering = 'create_time'
# 每次页面翻页的数据
paginate_by = 10
# 对应的翻页参数
page_kwarg = 'page'
# 该方法重写上下文数据
def get_context_data(self, **kwargs):
"""
page_obj常用属性和方法
has_next() :是否含有下一页,有的话返回True
has_previous():是否还有上一页
next_page_number(): 下一页的页码
previous_page_number(): 上一页的页码
number:当前页
start_index() : 返回当前这一页的第一条数据的索引值
end_index() : 返回当前这一页的最后一条数据的索引值
"""
content = super(IndexListView, self).get_context_data(**kwargs)
print('-'*100)
page_obj = content.get('page_obj')
# print(page_obj.has_next())
# print(page_obj.has_previous())
# print(page_obj.next_page_number())
# print(page_obj.previous_page_number())
# print(page_obj.number)
print(page_obj.start_index())
print('-'*100)
return content
错误处理
在一些网站开发中。经常会需要捕获一些错误,然后将这些错误返回比较优美的界面,或者是将这个错误的请求做一些日志保存。
常见的错误码
- 404 : 服务器没有指定URL
- 403 : 没有权限访问相关的数据
- 405 : 请求的method错误
- 500 : 服务器内部错误
- 502 : 一般部署的时候见得比较多,一般是nginx启动了,然后uwsgi有问题
自定义错误模板
在碰到比如404,500错误的时候,想要返回自己定义的模板。那么可以直接在templates文件夹下创建相对应错误代的html模板文件。那么以后在发生相应错误后,会将指定的模板返回回去。注意:当想返回什么错误就使用相对应错误码命名html
修改配置文件
DEBUG = False
ALLOWED_HOSTS = ["127.0.0.1"]
404.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>页面不存在</p>
</body>
</html>
错误处理的解决方案
对于404和500这种自动抛出的错误。我们可以直接在templates文件夹下新建相应错误代码的模板文件。而对于其他的错误,我们可以专门定义一个app,用来处理这些错误。
views.py
from django.http import HttpResponse
from django.shortcuts import render
def view_405(request):
return render(request,"errors/405.html",status=405)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("405",views.view_405,name="405")
]