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 }}

浙公网安备 33010602011771号