1、HttpRequest对象
WSGIRequest对象
Django在接收到http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequest对象,并且作为视图函数第一个参数传给视图函数。也就是我们经常看到的request参数。在这个对象上我们可以找到客户端上传上来的所有信息。这个对象的完整路径是django.core.handlers.wsgi.WSGIRequest。
WSGIRequest对象常用属性
WSGIRequest
对象上大部分的属性都是只读的。因为这些属性是从客户端上传上来的,没必要做任何的修改。
path
:请求服务器的完整“路径”,但不包含域名和参数。比如http://www.baidu.com/xxx/yyy/,那么path就是/xxx/yyy/。method
:代表当前请求的http方法。比如是GET还是POST。GET
:一个django.http.request.QueryDict对象。操作起来类似于字典。这个属性中包含了所有以?xxx=xxx的方式上传上来的参数。POST
:也是一个django.http.request.QueryDict对象。这个属性中包含了所有以POST方式上传上来的参数。FILES
:也是一个django.http.request.QueryDict对象。这个属性中包含了所有上传的文件。COOKIES
:一个标准的Python字典,包含所有的cookie,键值对都是字符串类型。session
:一个类似于字典的对象。用来操作服务器的session。META
:存储的客户端发送上来的所有header信息。
CONTENT_LENGTH:请求的正文的长度(是一个字符串)。
CONTENT_TYPE:请求的正文的MIME类型。
HTTP_ACCEPT:响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING:响应可接收的编码。
HTTP_ACCEPT_LANGUAGE: 响应可接收的语言。
HTTP_HOST:客户端发送的HOST值。
HTTP_REFERER:在访问这个页面上一个页面的url。
QUERY_STRING:单个字符串形式的查询字符串(未解析过的形式)
REMOTE_HOST:客户端的主机名。
REQUEST_METHOD:请求方法。一个字符串类似于GET或者POST。
SERVER_NAME:服务器域名。
SERVER_PORT:服务器端口号,是一个字符串类型。
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
# request属性
print(type(request)) # <class 'django.core.handlers.wsgi.WSGIRequest'>
print(request.path) # 当前页面url,去除掉http://127.0.0.1:8000/的部分
print(request.method) # GET,POST方法
print(request.GET.get('pag')) # 接收路由地址中的参数pag
print(request.FILES) # <MultiValueDict: {}>
print(request.COOKIES) # Python字典,包含所有的cookie
print(request.session) # <django.contrib.sessions.backends.db.SessionStore object at 0x000002034BFB85C0>
print(request.META) # 存储的客户端发送上来的所有header信息
for key,value in request.META.items():
print(key, value)
return HttpResponse("index")
WSGIRequest对象常用方法
is_secure()
:是否是采用https协议。is_ajax()
:是否采用ajax发送的请求。原理就是判断请求头中是否存在X-Requested-With:XMLHttpRequest。get_host()
:服务器的域名。如果在访问的时候还有端口号,那么会加上端口号。比如www.baidu.com:9000。get_full_path()
:返回完整的path。如果有查询字符串,还会加上查询字符串。比如/music/bands/?print=True。get_raw_uri()
:获取请求的完整url。
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
# request方法
print(request.is_secure()) # 是否是采用https协议。
print(request.is_ajax()) # 是否采用ajax发送的请求
print(request.get_host()) # 服务器的域名
print(request.get_full_path()) # 返回完整的path
print(request.get_raw_uri()) # 获取请求的完整url。
return HttpResponse("index")
2、HttpResponse对象
Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个HttpRequest对象传给视图函数
。那么视图函数在处理完相关的逻辑后,也需要返回一个响应给浏览器。而这个响应,我们必须返回HttpResponseBase或者他的子类的对象。而HttpResponse则是HttpResponseBase用得最多的子类。
常用属性
- 1.
content
:返回的内容。
def front(request):
res = HttpResponse()
res.content = '123'
return res
- 2.
status_code
:返回的HTTP响应状态码。
# 状态码
res = HttpResponse()
res.content = "front" # .content实例的属性
res.status_code = 404
return res
# 另一种 状态码
return HttpResponse("123", status=400)
- 3.
content_type
:返回的数据的MIME类型,默认为text/html。浏览器会根据这个属性,来显示数据。如果是text/html,那么就会解析这个字符串,如果text/plain,那么就会显示一个纯文本。常用的Content-Type如下:
text/html(默认的,html文件)
text/plain(纯文本)
text/css(css文件)
text/javascript(js文件)
multipart/form-data(文件提交)
application/json(json传输)
application/xml(xml文件)
res = HttpResponse()
res.content = '<h1>hello</h1>'
return res
# 另一种
return HttpResponse("<h1>hello</h1>", content_type="text/plain;charset=utf-8")
- 4.设置请求头
response['X-Access-Token'] = 'xxxx'
。
res = HttpResponse()
res['X-Access-Token'] = '12345'
res.content = '<h1>hello</h1>'
return res
常用方法
1.set_cookie:用来设置cookie信息。
2.delete_cookie:用来删除cookie信息。
3.write:HttpResponse是一个类似于文件的对象,可以用来写入数据到数据体(content)中。
res = HttpResponse()
res['X-Access-Token'] = '12345'
res.content = '<h1>hello</h1>'
res.write("xxxx")
return res
JsonResponse类
用来对象dump成json字符串,然后返回将json字符串封装成Response对象返回给浏览器。并且他的Content-Type是application/json。
def json_view(request):
info = {
"name": "xxx",
"age": 18,
"gender": 1,
}
print(type(json.dumps(info)))
return HttpResponse(json.dumps(info), content_type="application/json")
默认情况下JsonResponse只能对字典进行dump,如果想要对非字典的数据进行dump,那么需要给JsonResponse传递一个safe=False
参数。
def json_view(request):
info = {
"name": "xxx",
"age": 18,
"gender": 1,
}
# print(type(json.dumps(info)))
# return HttpResponse(json.dumps(info), content_type="application/json")
# 另一种返回json数据类型,info必须是字典类型的数据,否则需要添加safe=False
# return JsonResponse(info)
book = ['1', '2', '3', '这是列表数据类型']
return JsonResponse(book, safe=False, json_dumps_params={"ensure_ascii": False})
# json_dumps_params={"ensure_ascii": False}中文编码问题
3、类视图
在写视图的时候,Django除了使用函数作为视图,也可以使用类作为视图。使用类视图可以使用类的一些特性,比如继承等。
View
django.views.generic.base.View
是主要的类视图,所有的类视图都是继承自他。如果我们写自己的类视图,也可以继承自他。然后再根据当前请求的method,来实现不同的方法。比如这个视图只能使用get的方式来请求,那么就可以在这个类中定义get(self,request,args,kwargs)
方法。以此类推,如果只需要实现post方法,那么就只需要在类中实现post(self,request,args,kwargs)
。
视图文件:views.py
from django.views import View # 类视图
class FrontView(View):
def get(self, request):
# return HttpResponse("FrontView get请求")
return render(request, "add_data.html")
def post(self, request):
name = request.POST.get("name")
author = request.POST.get("author")
print(name, author)
# 导入模型,保存数据
# 表单验证
return HttpResponse("FrontView post请求")
类视图写完后,还应该在urls.py中进行映射,映射的时候就需要调用View的类方法as_view()来进行转换,as_view()功能是将请求的路由判断是哪种类型(POST、GET等),再在类视图中执行。自动查找指定方法。
路由绑定文件:urls.py
from django.contrib import admin
from django.urls import path
from front import views
urlpatterns = [
# 类视图路由
path('front_view/', views.FrontView.as_view(), name="front_view"),
]
除了get方法,View还支持以下方法['get','post','put','patch','delete','head','options','trace']
。
如果用户访问了View中没有定义的方法。比如你的类视图只支持get方法,而出现了post方法,那么就会把这个请求转发给http_method_not_allowed(request,*args,**kwargs)
。
class FrontListView(View):
# def get(self, request, *args, **kwargs):
# return HttpResponse("123")
# def get(self, request, book_id):
# return HttpResponse("图书id:%s" % book_id)
def post(self, request):
return HttpResponse("321")
# 当前网页请求只有post时候,会返回http_method_not_allowed方法,此时我们可以重写该方法进行提示
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse("您当前的请求不被允许,请修改请求方法")
urls.py中的映射如下
from django.contrib import admin
from django.urls import path
from front import views
urlpatterns = [
# 类视图路由
# path('front_list/<book_id>', views.FrontListView.as_view(), name="front_list"),
path('front_list/', views.FrontListView.as_view(), name="front_list"),
]
TemplateView
django.views.generic.base.TemplateView
,这个类视图是专门用来返回模版的。在这个类中,有两个属性是经常需要用到的,一个是template_name,这个属性是用来存储模版的路径,TemplateView会自动的渲染这个变量指向的模版。另外一个是get_context_data,这个方法是用来返回上下文数据的,也就是在给模版传的参数的。一般是静态页面,不会经常改动。
# TemplateView传参需要定义类视图,只有post方法
class HomePageView(TemplateView):
template_name = "home.html"
# 传参
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # super()调用父类的方法get_context_data()
context['username'] = 'xxx'
return context
urls.py中的映射如下
from django.contrib import admin
from django.urls import path
from front import views
from django.views.generic import TemplateView
urlpatterns = [
# 类视图专门用于返回模版,能够直接渲染前端界面,省去了类视图和类方法定义的事情
path('about/', TemplateView.as_view(template_name='about.html')),
path('home/', views.HomePageView.as_view(), name='home'), # 传参需要定义类视图
]
ListView
在网站开发中,经常会出现需要列出某个表中的一些数据作为列表展示出来。比如文章列表,图书列表等等。在Django中可以使用ListView
来帮我们快速实现这种需求。
from django.shortcuts import render
from django.views.generic import ListView
from .models import Article
from django.http import HttpResponse
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
paginate_by = 10
context_object_name = 'articles'
ordering = 'create_time'
page_kwarg = 'page'
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
print(context)
return context
def get_queryset(self):
return Article.objects.filter(id__lte=89) # 小于89的id,限制查询数据
对以上代码进行解释
- 首先
ArticleListView
是继承自ListView。 model
:重写model类属性,指定这个列表是给哪个模型的。template_name
:指定这个列表的模板。paginate_by
:指定这个列表一页中展示多少条数据。context_object_name
:指定这个列表模型在模板中的参数名称。ordering
:指定这个列表的排序方式。page_kwarg
:获取第几页的数据的参数名称。默认是page。get_context_data
:获取上下文的数据。get_queryset
:如果你提取数据的时候,并不是要把所有数据都返回,那么你可以重写这个方法。将一些不需要展示的数据给过滤掉。
Paginator和Page类
Paginator和Page类都是用来做分页的。他们在Django中的路径为django.core.paginator.Paginator
和django.core.paginator.Page
。以下对这两个类的常用属性和方法做解释.
Paginator常用属性和方法
count:总共有多少条数据。
num_pages:总共有多少页。
page_range:页面的区间。比如有三页,那么就range(1,4)。
Page常用属性和方法
has_next:是否还有下一页。
has_previous:是否还有上一页。
next_page_number:下一页的页码。
previous_page_number:上一页的页码。
number:当前页。
start_index:当前这一页的第一条数据的索引值。
end_index:当前这一页的最后一条数据的索引值。
实例如下:
from django.shortcuts import render
from django.views.generic import ListView
from .models import Article
from django.http import HttpResponse
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
paginate_by = 10
context_object_name = 'articles'
ordering = 'create_time'
page_kwarg = 'page'
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
# count:总共有多少条数据。
# num_pages:总共有多少页。
# page_range:页面的区间。比如有三页,那么就range(1,4)。
# paginator = context.get('paginator')
# print(paginator.count) # 89
# print(paginator.num_pages) # 9
# print(paginator.page_range) # range(1, 10)
# return context
'''
has_next:是否还有下一页。
has_previous:是否还有上一页。
next_page_number:下一页的页码。
previous_page_number:上一页的页码。
number:当前页。
start_index:当前这一页的第一条数据的索引值。
end_index:当前这一页的最后一条数据的索引值。
'''
page = context.get('page_obj')
print(page.has_next) # <bound method Page.has_next of <Page 5 of 9>>
print(page.has_previous) # <bound method Page.has_previous of <Page 5 of 9>>
print(page.next_page_number) # <bound method Page.next_page_number of <Page 5 of 9>>
print(page.previous_page_number) # <bound method Page.previous_page_number of <Page 5 of 9>>
print(page.number) # 5
print(page.start_index) # <bound method Page.start_index of <Page 5 of 9>>
print(page.end_index) # <bound method Page.end_index of <Page 5 of 9>>
def get_queryset(self):
return Article.objects.filter(id__lte=89)
def index(request):
for i in range(1,101):
article = Article(title='标题%s'% i, content='内容:%s' % i)
article.save()
return HttpResponse("index")
实例分页代码
https://v3.bootcss.com/components/#pagination
article_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
{% for article in articles %}
<p>{{ article.title }}-{{ article.content }}-{{ article.create_time }}</p>
{% endfor %}
<nav aria-label="Page navigation">
<ul class="pagination">
<!-- 判断是否有上一页 -->
{% if page_obj.has_previous %}
<li>
<!-- previous_page_number如果有上一页,点击后进入上一页页面url -->
<a href="{% url 'list' %}?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% else %}
<li class="disabled">
<!-- 如果没有上一页,页面按钮上显示禁止点击符号url -->
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for page in paginator.page_range %}
<!-- 当前页 -->
{% if page_obj.number == page %}
<li class="active"><a href="{% url 'list' %}?page={{ page }}">{{ page }}</a></li>
{% else %}
<!-- ?page={{ page }}字符拼接,传递page参数到url中 -->
<li><a href="{% url 'list' %}?page={{ page }}">{{ page }}</a></li>
{% endif %}
{% endfor %}
<!-- 判断是否是最后一页 -->
{% if page_obj.has_next %}
<li>
<a href="{% url 'list' %}?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</body>
</html>
实现效果如下: