视图的基本概念
在Django框架中,视图是指一个Python函数或类,它处理来自客户端的请求,并返回相应的响应。视图可以处理各种类型的请求,如GET、POST、PUT、DELETE等。视图通常用于渲染HTML模板、查询数据库、处理表单数据等。视图是Django框架中最重要的组成部分之一,因为它们负责处理来自客户端的请求,然后返回相应的响应。
在前面的内容中已经提到,创建视图可以通过视图函数和视图类两种方式。
视图函数是一个Python函数,它接收一个HttpRequest类型的参数,并返回一个HttpResponse类型的响应。
from django.http import HttpResponse
def index(request):
return HttpResponse("视图函数")
视图类是一个Python类,它继承自Django框架的View类,并实现了View类中定义的方法。视图类通常用于创建复杂的视图。
from django.views import View
from django.http import HttpResponse
class IndexView(View):
def get(self, request):
return HttpResponse("视图类")
限制请求method装饰器
Django内置的视图装饰器可以给视图提供一些限制,比如某个视图只能通过GET的方式访问。
django.views.decorators.http.require_http_methods
,这个装饰器需要传递一个允许访问的方法的列表。django.views.decoratorshttp.require_GET
,这个装饰器相当于是require_http_methods(['GET'])
的简写形式,只允许GET的方式来访问视图。django.views.decoratorshttp.require_POST
,这个装饰器相当于是require_http_methods(['POST'])
的简写形式,只允许POST的方式来访问视图。django.views.decoratorshttp.require_safe
,这个装饰器相当于是require_http_methods(['GET','HEAD'])
的简写形式,只允许使用相对安全的方式来访问视图。(GET和HEAD不会对服务器产生增删改的行为,相对安全的请求方式)。
from django.http import HttpResponse
from django.shortcuts import render
from .models import Article
from django.views.decorators.http import require_http_methods
@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")
Article.objects.create(title=title, content=content)
return HttpResponse("success")
WSGIRequest对象
Django在接收到http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequset
对象,并且作为视图函数第一个参数传递给视图函数。这个对象完整的路径是django.core.handlers.wsgi.WSGIRequest
。
from django.http import HttpResponse
def index(request):
print(request)
print(type(request))
return HttpResponse('index')
<WSGIRequest: GET '/index/'>
<class 'django.core.handlers.wsgi.WSGIRequest'>
WSGIRequest对象常用属性
WSGIRequest
对象上大部分的属性都是只读的,因为这些属性是从客户端上传过来的,没有必要做任何修改。
path
:请求服务器的完整路径,但不包括域名和参数。比如上面的例子,只是‘http://127.0.0.1:8000/index/’中的‘/index/’;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
:响应可接收的语言;HTTPS_HOST
:客户端发送的HOST值;HTTP_REFERER
:在访问这个页面上一个页面的url;QUERY_STRYING
:单个字符串形式的查询字符串;REMOTE_ADDR
:客户端的IP地址;REMOTE_HOST
:客户端的主机名;REQUEST_METHOD
:请求方法,一个字符串类似于GET或POST;SERVER_NAME
:服务器域名;SERVER_PORT
:服务器端口号。
WSGIRequest对象常用方法
is_secure()
:是否采用https协议;is_ajax()
:是否采用ajax发送请求。原理就是判断请求头中是否存在X-Requested-With:XMLHttpRequest
;get_host()
:服务器的域名。如果在访问的时候还有端口号,那么会加上端口号;get_full_path()
: 返回完整的path。如果有查询字符串,也会加上查询字符串;get_raw_uri()
:获取请求的完整url。
QueryDict对象
经常用到的request.GET
和request.POST
都是QueryDict对象,这个对象继承自dict,因此用法跟dict差不多。其中用得比较多的是get方法和getlist方法。
get()
:用来获取指定key的值,如果没有这个key,那么会返回None;name = request.GET['name'] # 若没有取到name的值,将报错:django.utils.datastructures.MultiValueDictKeyError: 'name' 尽量不要使用上面的方式,而是使用GET.get()的形式进行获取 name = request.GET.get('name') # 若没有取到name的值,返回None
getlist()
:如果浏览器上传过来的key对应的值有多个,name就需要通过这个方法获取。
HttpResponse对象
Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个HttpRequest
对象传给视图函数。视图函数在处理完相关的逻辑后,也需要返回一个响应结果给浏览器。而这个响应结果,必须返回HttpResponseBase
对象或者它的子类的对象。HttpResponse
是HttpResponseBase
用得最多的子类。
HttpResponse对象常用属性
content
:返回的内容;status_code
:返回的HTTP响应状态码;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文件)
- 设置请求头:
response['X-Access-Token'] = 'xxxx'
。
def index(request):
# print(request)
# print(type(request))
response = HttpResponse()
response1 = HttpResponse("<h1>AILynn</h1>", content_type='text/html;charset=utf-8')
response.content = "plscript"
print(response.status_code)
response1['X-Token'] = 'plscript'
return response1
HttpResponse对象常用方法
set_cookie
:用来设置cookie信息;delete_cookie
:用来删除cookie信息;write
:HttpResponse
是一个类似于文件的对象,可以用来写入数据到数据体(content)中。
JsonResponse类
用来将对象dump成json字符串,然后将字符串封装成Response对象返回给浏览器,对应的Content-Type是application/json。默认情况下JsonResponse只能对自定进行dump,如果想要对非字典的数据进行dump,需要给JsonResponse传递一个safe=False
参数。
import json
from django.http import HttpResponse, JsonResponse
def jsonresponse_view(request):
user = {
"name": "艾琳",
"age": 18,
}
# user_json = json.dumps(user, ensure_ascii=False)
# response = HttpResponse(user_json, content_type="application/json")
# return response
response = JsonResponse(user, json_dumps_params={'ensure_ascii': False})
return response
这里需要注意,python讲数据保存为json格式时,默认情况下会将非ASCII字符(比如中文)转换为Unicode编码的转义序列。这种转换时通过设置ensure_ascii=True
来实现的。若要显示为原始的字符,可以通过将ensure_ascii=True
来实现。
类视图
View
django.views.generic.base.View
是主要的类视图,所有的类视图都是继承自他。我自己设计的类视图,也可以继承他,然后再根据当前请求的method,来实现不同的方法。
from django.http import HttpResponse
from django.views.generic import View
def index(request):
return HttpResponse("success")
class BookListView(View):
def get(self, reqeust, *args, **kwargs):
return HttpResponse("book list")
class AddBookView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("get success")
def post(self, request, *args, **kwargs):
book_name = request.POST.get("name")
book_author = request.POST.get("author")
print("name:{},author:{}".format(book_name, book_author))
return HttpResponse("post success")
与之对应的路由
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index, name='index'),
path('book_list/', views.BookListView.as_view(), name="book_list"),
path('add_book/', views.AddBookView.as_view(), name="add_book"),
]
需要注意的是,在配置路由时,对应函数视图时,是视图的名称不加括号。而对应类视图时,是视图类名加.as_view()
,需要加上括号。
如果用户访问了View中没有定义的方法,比如只支持get方法,而调用了post方法,那么可以在代码中增加http_method_not_allowed(request, *args, **kwargs)
去处理
class AddBookView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("get success")
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse("您当前发送的是:%s请求,当前视图不支持!" % request.method)
其实不管是get请求还是post请求,都会去调用dispatch(request, *args, **kwargs)
方法,也就是实现了这个方法,将能够对所有请求都处理到。
给类视图添加装饰器
前面的函数视图可以通过装饰器进行修饰实现增多的功能,类视图也可以添加装饰器。
- 装饰dispatch方法
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from django.views.generic import View
from django.utils.decorators import method_decorator
def login_required(func):
def wrapper(request, *args, **kwargs):
username = request.GET.get('username')
if username:
return func(request, *args, **kwargs)
else:
return redirect(reverse('login'))
return wrapper
def login(request):
return HttpResponse('book:login')
class ProfileView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("个人信息页面")
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(ProfileView, self).dispatch(request, *args, **kwargs)
- 直接装饰类
def login_required(func):
def wrapper(request, *args, **kwargs):
username = request.GET.get('username')
if username:
return func(request, *args, **kwargs)
else:
return redirect(reverse('login'))
return wrapper
def login(request):
return HttpResponse('book:login')
@method_decorator(login_required, name='dispatch')
class ProfileView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("个人信息页面")