django3基础入门-p03-视图层View

Django 具有 “视图” 的概念,负责处理用户的请求并返回响应

django的MTV模式

M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。 模板渲染功能
V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。

除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:

image-20220323103108758

本节,主要介绍URL控制器和视图view.py

处理URL请求过程

  1. Django从配置文件settings.py中,根据ROOT_URLCONF找到 主路由文件;默认情况下,该文件在项目同名目录下的urls,例如 djstart/djstart/urls.py
  2. Django加载主路由文件中的urlpatterns变量[包含很多路由的数组]
  3. 从上往下,依次匹配urlpatterns中的path,匹配到第一个合适的,中断后续匹配
  4. 匹配成功-调用对应的视图函数处理请求,返回响应
  5. 匹配失败-返回404响应

匹配成功

image-20220325114616042

匹配失败

image-20220325114734648

djstart/djstart/urls.py

from django.urls import path
from app_demo import views

urlpatterns = [
    # ...
    path('blog/',views.blog_list_view,name='blog_list')
]

djstart/app_demo/views.py

from django.http import HttpResponse

def blog_list_view(request):
    html='blogs 列表页'
    return HttpResponse(html)

URL控制器

路由配置-path()路径匹配

  • 导入 - from django.urls import path
  • 语法 - path(route,views,name=None)
    1. route:字符串类型,匹配的请求路径
    2. views:匹配的请求路径对应的视图处理函数的名称
    3. name:为地址起别名,在模板中地址反向解析时使用

djstart/djstart/urls.py

from django.urls import path
from app_demo import views

urlpatterns = [
    # 匹配 http://localhost:8000/blog/,调用app_demo.views中的blogs_view视图函数进行处理
    path('blog/',views.blog_list_view,name='blog_list')
]

路由配置-path路径转换器

  • 语法 <转换器类型:自定义形参名>
  • 作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传递给视图函数

djstart/djstart/urls.py

from django.urls import path
from app_demo import views

urlpatterns = [
    # ...
    # 匹配 http://localhost:8000/blog/1 ,调用相应视图函数 blog_detail_view(request,blog_id=1)
    path('blog/<int:blog_id>',views.blog_detail_view,name='blog_detail')
]

djstart/app_demo/views.py

from django.http import HttpResponse

def blog_detail_view(request,blog_id):
    html=f'blog 详情页,blog_id:{blog_id}'
    return  HttpResponse(html)
  • 内置的路径转换器有:strintsluguuidpath

路由匹配-re_path() 正则表达式匹配

  • 导入 - from django.urls import re_path

  • 语法 re_path(reg,views,name=None)

    正则表达式为命名分组模式 (?P<name>pattern) ,其中 name 是组名,pattern 是要匹配的模式。

  • 作用:

    1. 在url的匹配过程中可以使用正则表达式进行精确匹配
    2. 匹配提取参数后,数据按照关键字传参的方式传递给视图函数

djstart/djstart/urls.py

from django.urls import path, re_path
from app_demo import views

urlpatterns = [
    # ...
    # 匹配/blog/arch/2022-03 ,调用视图entry_archive_view(request,year=2022,month=03)
    re_path(r'^blog/arch/(?P<year>\d{4})-(?P<month>\d{1,2})$',views.entry_archive_view)
]

djstart/app_demo/views.py

def entry_archive_view(request, year,month):
    html = f'文章归档,年份:{year},月份:{month}'
    return HttpResponse(html)

image-20220325165830834

包含其它的URLconfs - include()

在任何时候,你的 urlpatterns 都可以 “include” 其它URLconf 模块。这实际上将一部分URL 放置于其它URL 下面。

在项目开发中,为了保持app的独立性,往往会在各自app中创建一个独立的URLconf 模块,然后在根URLconf 模块中通过include() 加载。

djstart/djstart/urls.py

from django.urls import path, re_path,include

urlpatterns = [
    path('blog/',include('app_demo.urls'))
]

djstart/app_demo/urls.py

from django.urls import path, re_path
from . import views

urlpatterns = [
    path('', views.blog_list_view, name='blog_list'),
    path('<int:blog_id>', views.blog_detail_view, name='blog_detail'),
    re_path(r'^arch/(?P<year>\d{4})-(?P<month>\d{1,2})$', views.entry_archive_view, name='entry_archive')
]

每当 Django 遇到 include() ,它会将匹配到该点的URLconf的任何部分切掉,并将剩余的字符串发送到包含的URLconf进行进一步处理。

传递额外选项给视图函数

djstart/app_demo/urls.py

from django.urls import path, re_path
from . import views

urlpatterns = [
    #..
    # 匹配 /blog/1 , 调用视图函数 blog_detail_view(request,blog_id=1,lang='EN')
    path('<int:blog_id>', views.blog_detail_view, {'lang':'EN'},name='blog_detail')
]

djstart/app_demo/views.py

def blog_detail_view(request, blog_id,**kwargs):
    html = f'blog 详情页,blog_id:{blog_id},lang:{kwargs.get("lang")}'
    return HttpResponse(html)

视图函数

  • 视图函数是用于接收一个浏览器请求(HttpRequest对象)并通过HttpResponse对象返回响应的函数。此函数可以接收浏览器请求并根据业务逻辑返回相应的响应内容给浏览器

  • 语法

    def xxx_view(request[,其他参数...]):
        return HttpResponse(content=响应体,content_type=响应体数据类型,status=状态码)

为了将代码放置在某处,约定将视图放在名为 views.py 的文件里,这个文件放置在项目或应用目录里。

如:djstart/app_demo/views.py

image-20220327210142575

Django中的请求

请求在Django中,实则为视图函数的第一个参数,即HttpRequest对象

Django接收到http协议的请求后,会根据请求数据报文创建HttpRequest对象,HttpRequest对象通过属性描述了请求的所有相关信息

  • path_info: URL字符串
  • method:字符串,表示HTTP请求方法,常用值:’GET’,’POST’
  • GET:QueryDict查询字典,包含get请求方式的所有数据
  • POST:QueryDict查询字典,包含post请求方式的所有数据
  • FILES:类似于字典的对象,包含所有的上传文件信息
  • COOKIES:Python字典,包含所有的cookie,键和值都为字符串
  • session:表示当前会话
  • body:字符串,请求体的内容(POST或PUT)
  • scheme:请求协议(’http’/‘https’)
  • get_full_path():请求的完整路径
  • META:请求中的元数据(消息头)
    • request.META[‘REMOTE_ADDR’]:客户端IP地址

Django中的响应

构造函数格式

HttpResponse(content=响应体,content_type=响应体数据类型,status=状态码)
  • content_type:返回的数据的MIME类型,默认为text/html。浏览器会根据这个属性,来显示数据。

    常用的Content-Type有:text/htmlapplication/jsonapplication/xml

  1. djstart/app_demo/views.py
def get_info_view(request):
    info={
        "path_info":request.path_info,
        "method":request.method,
        "GET": request.GET,
        "COOKIES": request.COOKIES,
        "scheme": request.scheme,
        "full_path": request.get_full_path(),
        "REMOTE_ADDR": request.META.get('REMOTE_ADDR'),
        "host": request.get_host(),
        "port": request.get_port(),
        "headers": str(request.headers),
        "User-Agent":request.headers.get('User-Agent')
    }


    return HttpResponse(content=json.dumps(info),content_type='application/json')

注意使用HTTPResponse响应json字符串时,我们需要把返回的数据先dumps成json字符串。如果我们直接使用**JsonResponse方式会更简单**,实质上JsonResponse也是继承HttpResponse

return JsonResponse(info)

注意:为了对 dict 以外的对象进行序列化,你必须将 safe 参数设置为 False,如

response = JsonResponse([1, 2, 3], safe=False)
  1. 将URL映射到视图

djstart/app_demo/urls.py

from django.urls import path, re_path
from . import views

urlpatterns = [
    # ...
    path('get_info',views.get_info_view,name='get_info')
]
  1. 浏览器器访问:http://localhost:8000/blog/get_info?b_id=1&b_name=test&b_filter=测试

image-20220328091419568

文件上传

djstart/app_demo/views.py

from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods

from app_demo.models import Blog
from djstart.settings import BASE_DIR

#视图装饰器,该视图只允许POST请求
@require_http_methods(["POST"]) 
#视图被**免除了中间件csrf所确保的保护**  (测试目的)
@csrf_exempt 
def blog_edit_view(request):
    """ 创建或更新blog """
    # 根据blog_id 获取或创建Blog实例
    blog, created = Blog.objects.get_or_create(pk=request.POST.get("blog_id"))

    # 获取文件对象f
    f = request.FILES.get("logo_img")
    # 重命名,避免文件名相同相互覆盖
    file_name = str(int(time.time())) + "-" + f.name
    # 指定文件存储路径
    file_path = os.path.join(BASE_DIR, 'media', file_name)
    # 将文件写到本地
    with open(file_path, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)
	# 存储到数据库
    blog.name = request.POST.get("name")
    blog.tagline = request.POST.get("tagline")
    blog.logo = file_name  # 数据库存储文件保存路径(不带根目录)
    blog.save()
    
    return HttpResponse('编辑blog成功!')

djstart/app_demo/urls.py

from django.urls import path, re_path
from . import views

urlpatterns = [
    # 编辑blog
    path('edit',views.blog_edit_view,name='blog_edit')
]

通过POSTMAN进行测试

image-20220328105336148

image-20220328105450371


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
My Show My Code