5.13python笔记

diango虚拟环境、路由层版本区别、视图层基础操作

虚拟环境

eg:
    项目1 
    	django2.2 pymysql3.3 requests1.1
    项目2 
    	django1.1
    项目3
    	flask
问:如何让诸多项目使用不同环境并且无障碍地打开运行?
	方式1:下载所有模块,如果有相同模块不同版本每次都重新下载替换  >>>  不合理
    方式2:提前准备好多个解释器环境,针对不同的项目切换即可  >>>  虚拟环境
    
# 创建虚拟环境
	相当于在下载一个全新的解释器
    new project
    	pure python	
        	new environment using
            	选择解释器版本
                	不勾选 Inherit global site-packages(继承本地解释器环境)
                    勾选 Make avaiable to all projects(让所有项目使用该环境)
                    	create
# 识别虚拟环境
	文件目录中有一个venv文件夹
# 如何切换环境
	选择不同的解释器即可,全文不要再次勾选new environment using

django路由层版本区别

# django1.x 与 2.x、3.x有些许区别
	1.路由匹配方法不一样
        1.x      >>>   url()     支持正则
        2.x/3.x  >>>   path()    不支持正则
                如果想使用正则,也提供了方法:
                from dnango.urls import path,re_path
                re_path()  # 方法与url完全一致
	2.path方法提供了转换器功能 
    	path('index/<int:id>/', index)
        <>  # 匹配对应位置的数据并自动转换类型,共五种转换类型

# 五种转换类型
    str:匹配任何非空字符串,但不含斜杠/,如果你没有专门指定转换器,那么这个是默认使用的;
    int:匹配0和正整数,返回一个int类型
    slug:可理解为注释、后缀、附属等概念,是url拖在最后的一部分解释性字符。该转换器匹配任何ASCII字符以及连接符和下划线,比如“ building-your-1st-django-site”;
    uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用破折号,所有字母必须小写,例如’075194d3-6885-417e-a8a8-6c931e272f00‘ 。返回一个UUID对象;
    path:匹配任何非空字符串,重点是可以包含路径分隔符“/”。这个转换器可以帮助你匹配整个url而不是一段一段的url字符串 

视图函数返回值

在django框架中,调用视图函数必须有返回值,且必须返回一个HttpResponse对象;

在视图层中,HttpResponse、render、redirect,这三个都是返回HttpResponse对象;

#HttpResponse
	class HttpResponse(HttpResponseBase):
    streaming = False

#render
	def render(request, template_name, context=None, content_type=None, status=None, using=None):
    content = loader.render_to_string(template_name, context, request, using=using)
    return HttpResponse(content, content_type, status)

#redirect
def redirect(to, *args, **kwargs):
    if kwargs.pop('permanent', False):
        redirect_class = HttpResponsePermanentRedirect
    else:
        redirect_class = HttpResponseRedirect
    return redirect_class(resolve_url(to, *args, **kwargs))

# 查看源码得知,redirect通过层层嵌套也是间接继承和返回了HttpResponse

JsonResponse对象

django中的JsonResponse模块相当于对json序列化的数据类型的范围做了扩充,查看源码,其实还是使用的原始的json模块;
# JsonResponse源码
class JsonResponse(HttpResponse):
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError(
                'In order to allow non-dict objects to be serialized set the '
                'safe parameter to False.'
            )
        if json_dumps_params is None:
            json_dumps_params = {}
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)  # 还是使用json方法
        super(JsonResponse, self).__init__(content=data, **kwargs)

代码验证

from django.http import JsonResponse


def ab_json(request):
    1.HttpResponse传递字典  >>>  无法json序列化
    user_dict = {"name":'jason','pwd':123,'hobby':'好好学习'}
    dict_json = json.dumps(user_dict,ensure_ascii=False)
    return HttpResponse(dict_json)
	2.JsonResponse传递字典
    
    user_dict = {'name': 'jason', 'pwd': 123, 'hobby': '好好学习'}
    return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})  # 为防止乱码,需要设置json_dumps_params

	3.JsonResponse传递列表
    user_list = [11, 22, 33, 44, 55]
    return JsonResponse(user_list, safe=False)  # 为防止乱码,需要设置safe=False

form表单上传文件

form表单上传的数据中如果含有文件 那么需要做以下几件事
  1.method必须是post
  2.enctype必须修改为multipart/form-data
  	默认是application/x-www-form-urlencoded
  3.后端需要使用request.FILES获取
前端:
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="f1">   
    <button>上传</button>
</form>

后端:
def index(request):
    if request.method == 'POST':
        file = request.FILES.get('f1') # 获取文件对象
        with open(file.name, 'wb') as f: #file.name上传文件的源文件名
            for i in file:
                f.write(i)
    return HttpResponse('ok')

request其他方法

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

针对这个网址:https://pythondjango.cn/blog/articles/?page=2
request.path
	获取路径
'''
  request.path仅提供相对于根目录的url相对路径,不包含参数。它的输出是一个字符串,结果如下所示:

  '/blog/articles/'
'''


request.path_info
	获取路径
'''
  request.path_info也仅提供相对于根目录的url相对路径,不含参数。它的输出也是一个字符
串,与request.path相同:

  '/blog/articles/'
'''
request.get_full_path()
	获取路径并且还可以获取到路径后面携带的参数
'''
  request.get_full_path

  该方法用于获取包含完整参数的相对于根目录的相对url路径。它的直接输出内容是个WSGI请求对
象。如果要获取字符串形式的完整url路径,一定要不要忘了在后面加括号。

  request.get_full_path()的输出结果为:

  'blog/articles/?page=2'
'''

FBV与CBV

#FBV:
	基于函数的视图
#CBV:
	基于类的视图
就是在视图里使用类方法处理请求。
需要导入一个View类,通过自定义一个子类继承这个类,我们可以利用View里面的dispatch()方法来判断请求是get还是post。dispatch方法的本质是一个反射器,可以根据名字来调用同名的方法。

CBV案例

from django.views import View
class Home(View):  
    def get(self,request):
        print(request.method)
        return render(request, 'home.html')
        
    def post(self,request):
        print(request.method,'POST')
        return render(request, 'home.html')

为了调用自定义的类里面的方法,在url里面,我们需要调用View类的as_view()方法作为入口。

from django.conf.urls import url
from myapp.views 
import MyView
urlpatterns = [
    url(r'^about/', MyView.as_view()),
]

CBV执行原理

以上面的案例为例
1.首先在项目启动时就会执行一次as_view方法,通过对as_view方法源码的查看,我们可以得知是返回一个闭包函数名view。
'''
源码
@classonlymethod
    def as_view(cls, **initkwargs):
          ......
          def view(request, *args, **kwargs):
              ......
          return view
'''
那么此时的urls.py文件中的配置就相当与,url('^Myviews$',views.Myviews.view),这也说明了CBV与FBV在路由匹配本质是一样的。
2.在路由匹配成功后,会执行view函数会return self.dispatch(request, *args, **kwargs),也就是会执行dispatch函数。
'''
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
'''
3.dispatch():中  通过 getattr 反射 拿到 子类的 get 或post 方法   给到handler 再返回执行,
          1.判断请求方法 是否存在于  http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

          2. 如果存在 就执行子类 中对应的方法(get,post.......)

          3.handler = getattr(self, request.method.lower(), self.http_method_not_allowed) 

               此时handler 就是一个 方法    return  handler (request ,*args,**kwargs) 加括号执行

'''
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
'''

模板语法传值

"""
django提供的模板语法只有两个符号
	{{}}:主要用于变量相关操作(引用)
	{%%}:主要用于逻辑相关操作(循环、判断)
"""

1.传值的两种方式
	# 传值方式1:指名道姓的传,适用于数据量较少的情况,节省资源
    return render(request, 'ab.html', {'name':name})
	# 传值方式2:打包传值,适用于数据量较多的情况(偷懒),浪费资源
      '''locals() 将当前名称空间中所有的名字全部传递给html页面'''
    return render(request, 'ab_temp.html', locals())

2.传值的范围
	基本数据类型都可以;
    函数名:
        模板语法会自动加括号执行并将函数的返回值展示到页面上;
        不支持传参(模板语法会自动忽略有参函数);
    文件名:
  		直接显示文件IO对象;
    类名:
  		自动加括号实例化成对象;
    对象名:
  		直接显示对象的地址,并且具备调用属性和方法的能力;

# django模板语法针对容器类型的取值 只有一种方式>>>:句点符
	data1 = {'info':{'pro':[11, 22, 33, {'name':'jason','msg':'努力就有收获'}]}};
	既可以点key值也可以点索引,django内部会自动识别;
  	{{ data1.info.pro.3.msg }}
posted @ 2022-06-05 15:39  槐序八  阅读(40)  评论(0)    收藏  举报