Django框架学习——12—(HttpRequest对象、HttpResponse对象、类视图)

1、HttpRequest对象

WSGIRequest对象

Django在接收到http请求之后,会根据http请求携带的参数以及报文信息创建一个WSGIRequest对象,并且作为视图函数第一个参数传给视图函数。也就是我们经常看到的request参数。在这个对象上我们可以找到客户端上传上来的所有信息。这个对象的完整路径是django.core.handlers.wsgi.WSGIRequest。

WSGIRequest对象常用属性

WSGIRequest对象上大部分的属性都是只读的。因为这些属性是从客户端上传上来的,没必要做任何的修改。

  1. path:请求服务器的完整“路径”,但不包含域名和参数。比如http://www.baidu.com/xxx/yyy/,那么path就是/xxx/yyy/。
  2. method:代表当前请求的http方法。比如是GET还是POST。
  3. GET:一个django.http.request.QueryDict对象。操作起来类似于字典。这个属性中包含了所有以?xxx=xxx的方式上传上来的参数。
  4. POST:也是一个django.http.request.QueryDict对象。这个属性中包含了所有以POST方式上传上来的参数。
  5. FILES:也是一个django.http.request.QueryDict对象。这个属性中包含了所有上传的文件。
  6. COOKIES:一个标准的Python字典,包含所有的cookie,键值对都是字符串类型。
  7. session:一个类似于字典的对象。用来操作服务器的session。
  8. 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对象常用方法

  1. is_secure():是否是采用https协议。
  2. is_ajax():是否采用ajax发送的请求。原理就是判断请求头中是否存在X-Requested-With:XMLHttpRequest。
  3. get_host():服务器的域名。如果在访问的时候还有端口号,那么会加上端口号。比如www.baidu.com:9000。
  4. get_full_path():返回完整的path。如果有查询字符串,还会加上查询字符串。比如/music/bands/?print=True。
  5. 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,限制查询数据

对以上代码进行解释

  1. 首先ArticleListView是继承自ListView。
  2. model:重写model类属性,指定这个列表是给哪个模型的。
  3. template_name:指定这个列表的模板。
  4. paginate_by:指定这个列表一页中展示多少条数据。
  5. context_object_name:指定这个列表模型在模板中的参数名称。
  6. ordering:指定这个列表的排序方式。
  7. page_kwarg:获取第几页的数据的参数名称。默认是page。
  8. get_context_data:获取上下文的数据。
  9. get_queryset:如果你提取数据的时候,并不是要把所有数据都返回,那么你可以重写这个方法。将一些不需要展示的数据给过滤掉。

Paginator和Page类

Paginator和Page类都是用来做分页的。他们在Django中的路径为django.core.paginator.Paginatordjango.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">&laquo;</span>
            </a>
        </li>
        {% else %}
        <li class="disabled">
            <!--     如果没有上一页,页面按钮上显示禁止点击符号url       -->
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</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">&raquo;</span>
            </a>
        </li>
        {% else %}
        <li class="disabled">
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
        {% endif %}


    </ul>
</nav>

</body>
</html>

实现效果如下:

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值