django视图层

django视图层

虚拟环境

# 针对的问题
    项目1 
    	django2.2 pymysql3.3 requests1.1
    项目2 
    	django1.1
    项目3
    	flask
诸多项目在你的机器上如何无障碍的打开并运行
在实际开发过程中,我们会给不同的项目配备不同的环境,项目用到什么就装什么,用不到的一概不装,不同的项目解释器环境都不一样

# 创建虚拟环境 
	相当于在下载一个全新的解释器
# 识别虚拟环境
	文件目录中有一个venv文件夹
# 如何切换环境
	选择不用的解释器即可 全文不要再次勾选new enviroment...

django版本区别

# django中1.x与2.x,3.x之间路由的区别
django1.X路由层使用的是url方法
django2.X和3.X版本中路由层使用的是path方法

1.X第一个参数正则表达式
url()
2.X和3.X第一个参数不支持正则表达式,写什么就匹配什么,100%精准匹配
path()

# 如果想要使用正则,那么2.X与3.X也有相应的方法
from django.urls import path,re_path

re_path 	# 等价于 1.X里面的url方法
re_path(r'^index/',index),

# url 2.x和3.x不推荐使用 但是可以用
from django.conf.urls import url
url(r'^login/',login)

path支持五种转换器

# 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数
path('index/<int:id>/',views.index)

def index(request,id):  # id当作关键字进来
    print(id,type(id))
    return HttpResponse('index')

# 五种转换器
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

自定义转换器(了解)

class MonthConverter:
     # 属性名必须为regex
    regex='\d{2}'  # 匹配两个数字

    def to_python(self, value):
        return int(value)  # int类型

    def to_url(self, value):
        return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
	
# 使用转换器	
from django.urls import path,register_converter
from app01.path_converts import MonthConverter

# 先注册转换器
register_converter(MonthConverter,'mon')

from app01 import views


urlpatterns = [
    path('articles/<int:year>/<mon:month>/<slug:other>/', 	views.article_detail, name='aaa'),

]

视图函数的返回值

# 视图函数必须返回一个HttpResponse对象
HttpResponse
  	class HttpResponse(...):
      pass
	返回字符串类型
render
	def render(...):
      return HttpResponse(...)
	返回html页面 并且在返回给浏览器之前还可以给html文件传值
redirect
	def redirect(...):
	重定向

JsonResponse对象

# json格式的作用
前后端数据交互需要使用到json作为序列化,实现跨语言数据传输

# 前后端序列化
前端js序列化								后端序列化
JSON.stringify()						json.dumps()
JSON.parse()							json.loads()

json序列化

# 导入模块
import json

def ab_json(request):
    # 将后端字典序列化发送到前端
    user_dict = {'username':'jason', 'password':'123', 'hobby':'study'}
   # 先转成json格式字符串
    json_str = json.dumps(user_dict,ensure_ascii=False)
    # 将该字段返回
    return HttpResponse(json_str)

'ensure_ascii 内部默认True自动转码,改为False不转码,只生成json格式,双引号'

JsonResponse序列化

# 导入JsonResponse模块
from django.http import JsonResponse

def ab_json(request):
    # 将后端字典序列化发送到前端
    user_dict = {'username':'jason','password':'123', 'hobby':'study'}
# JsonResponse自动编码并返回给前端页面
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

# 内部的源码
class JsonResponse(HttpResponse):
	def __init__(self, data,json_dumps_params=None, **kwargs):
		data = json.dumps(data, **json_dumps_params)

JsonResponse序列化(列表注意事项)

# 导入JsonResponse模块
from django.http import JsonResponse

def ab_json(request):
    l = [111,222,333,444,555]
    # 默认只能序列化字典 序列化其他需要加safe参数 safe=False
    return JsonResponse(l,safe=False)  

form表单上传文件

# form表单上传文件类型的数据
前端:
    1.method必须指定成post
    2.enctype必须修改为multipart/form-data
    默认是application/x-www-form-urlencoded
后端:
    3.后端需要使用request.FILES获取
'django会根据数据类型的不同自动帮你封装到不同的方法中'

#具体代码: 
def ab_file(request):
    # 判断前端请求
    if request.method == 'POST':
        print(request.FILES)  # 获取文件数据
        file_obj = request.FILES.get('file')   
        # (拿到最后一个元素)  文件对象  
        print(file_obj.name)  # 拿到文件名字
        with open(file_obj.name, 'wb') as f:
            for line in file_obj:  
                f.write(line)
    # get请求返回
    return render(request, 'from.html')

# form
<form action="" method="post" enctype="multipart/form-data">
    <p>username: <input type="text" name="username"></p>
    <p>file: <input type="file" name="file"></p>
    <input type="submit">
</form>

request对象方法

# request.method 获取请求方式POST/GET
一个字符串,表示请求使用的HTTP 方法 必须使用大写

# request.POST 获取POST请求提交普通的键值对数据
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装

# request.GET 获取GET请求
获取GET请求	一个类似于字典的对象,包含 HTTP GET 的所有参数

# request.FILES 获取文件
一个类似于字典的对象,包含所有的上传文件信息

# request.body 接收最原始的二进制数据
request.POST、request.GET、request.FILES这些获取数据的方法其实都从body中获取数据并解析存放的

# request.path ,request.path_info 
获取路径 拿到路由

# request.get_full_path() 
能过获取完整的url及问号后面的参数 

# 代码:
print(request.path)  # /app01/ab_file/
print(request.path_info)  # /app01/ab_file/
print(request.get_full_path())  # /app01/ab_file/?username=jason

FBV与CBV

# FBV:基于函数的视图
'我们前面写的视图函数都是FBV'
  url(r'^index/',函数名)
    
# CBV:基于类的视图
from django import views # 导入CBV模块

class MyLoginView(views.View): # 继承模块
    
    def get(self, request): # get请求走get函数
        return HttpResponse("from CBV get view")
    
    def post(self, request): # post请求走该post函数
        return HttpResponse("from CBV post view")
    
url(r'^ab_cbv/', views.MyLoginView.as_view())
    
"""
如果请求方式是GET 则会自动执行类里面的get方法
如果请求方式是POST 则会自动执行类里面的post方法
""" 
# CBV特点
能够直接根据请求方式的不同直接匹配到对应的方法执行

CBV源码剖析

# CBV于FBV在路由匹配上本质是一样的 都是路由 对应 函数内存地址
urlpatterns = {
	 url(r'^login/', views.MyLogin.as_view()) # CBV
	 url(r'^login/', views.view)  # FBV
}
# 切入点:路由匹配
  类名点属性as_view并且还加了括号
as_view可能是普通的静态方法  就是个普通函数没有形参 
as_view可能是绑定给类的方法  类来调用自动将类传入当做第一个参数传入

步骤一

'函数名加括号执行优先级最高'
urlpatterns = [
    # MyLogin类 点 方法
    url(r'^login/', views.MyLogin.as_view())  
]
# 源码显示    
@classonlymethod  # 绑定给类的方法
	def as_view(cls, **initkwargs):  
    	pass
as_view: 绑定给类的方法,类来调用把类传进去

步骤二

'项目已启动就会执行as_view方法 查看源码返回了一个闭包函数名view'
  def as_view(cls):
    def view(cls):
      pass
    return view
    
# 代码在启动django的时候  就会立刻执行as_view方法 			
url(r'^login/', views.MyLogin.as_view())  # as_view 返回值 view

# django代码运行 以上代码就等价于以下代码段
url(r'^login/', views.view)  django项目启动就等价于这个方法

'当用户在浏览器输入login的时候就自动执行 view方法'

步骤三

# 闭包函数(内部函数引用外部函数名称空间中的名字) 
def view(request, *args, **kwargs):
    self = cls(**initkwargs)  # cls是我们自己写的类的对象
    # self = MyLogin(**initkwargs)  产生一个我们自己写的类对象
    
    # hasattr 映射 判断对象是否包含对应属性 (对象有该属性返回True 否则返回False)
    if hasattr(self, 'get') and not hasattr(self, 'head'):
        # 给对象赋值属性
        self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs
        # 对象点dispatch 
        return self.dispatch(request, *args, **kwargs)
    
    # 面向对象属性方法查找顺序
    1.先从对象自己名称空间找
    2.在去产生类对象的类里面找
    3.在去父类里面找

    MyLogin >>名称空间中查找 >>产生类对象的类里面找 >>父类查找

    class MyLogin(View):  # 父类查找

步骤四

def dispatch(self, request, *args, **kwargs):
	# 判断 request.method将当前请求方式转成小写 在不在 self内 self==MyLogin 
        "http_method_names 内有八个请求方式 "
    ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    if request.method.lower() in self.http_method_names:
    """
    # getattr 反射: 通过字符串来操作对象的属性或者方法
    # handler = getattr(self,'get'),你写的类的get方法的内存地址
    # handler = getattr(自己写的类产生的对象,'get',当找不到get属性或者方法的时候就会用第三个参数)
    """    
    	handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs) # 执行get(request)

模板语法传值

# 模板语法两种书写方式
{{}}:变量相关

{%%}:逻辑相关
1.fro循环
2.反向解析配置load
'模板文件中取值一律使用点语法'

# 传值的两种方式
传值方式1:指名道姓的传
return render(request, 'ab_temp.html', {'name':name})
'适用于数据量较少的情况       节省资源'

传值方式2:打包传值  
locals() 将当前名称空间中所有的名字全部传递给html页面
  return render(request, 'ab_temp.html', locals())
'适用于数据量较多的情况(偷懒)     浪费资源'

# 传值的范围 (基本数据类型都可以)
 1.函数名
  	模板语法会自动加括号执行并将函数的返回值展示到页面上
    不支持传参(模板语法会自动忽略有参函数)
 2.文件名
  	直接显示文件IO对象
 3.类名
  	自动加括号实例化成对象
 4.对象名
  	直接显示对象的地址 并且具备调用属性和方法的能力
    
# django模板语法针对容器类型的取值 只有一种方式>>>:句点符
	既可以点key也可以点索引  django内部自动识别
.key
.index
.key.index.index.key

posted @ 2022-05-13 20:25  洛阳城门听风雨  阅读(49)  评论(0)    收藏  举报