django路由分发、名称空间、虚拟环境、视图层之FBV与CBV及模板层
路由分发
django支持每个应用都可以有自己独立的路由层、静态文件、模板层。基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起
多个应用都有很多路由与视图函数的对应关系 这个时候可以拆分到各自的路由层中
使用路由分发之前 总路由直接干路由与视图函数的匹配
path('index/', index)
使用路由分发之后 总路由只按照应用名分配匹配方向
path('app01/', include('app01.urls'))
代码:
创建2个app,分别是app01和app02,并注册到settings.py里面.
app01:
urls.py:
from django.urls import path
from app01 import views
urlpatterns = [
path('index/',views.index)
]
views.py:
from django.shortcuts import render,HttpResponse
# Create your views here.
def index(request):
return HttpResponse('from app01 index view')
app02:
urls.py:
from django.urls import path
from app02 import views
urlpatterns = [
path('index/',views.index)
]
views.py:
from django.shortcuts import render,HttpResponse
# Create your views here.
def index(request):
return HttpResponse('from app02 index view')
django项目:
urls.py:
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
#路由分发
path('app01/',include('app01.urls')),
path('app02/',include('app02.urls')),
]
验证:
名称空间
路由分发之后 针对相同的别名能否自动反向解析出不同的应用前缀
默认情况下是无法直接识别应用前缀的
如果想要正常识别区分有两种方式
方式1:名称空间
总路由
path('app01/', include(('app01.urls', 'app01'), namespace='app01')),
path('app02/', include(('app02.urls', 'app02'), namespace='app02')),
反向解析(后端views.py)
reverse('app01:index_view')
reverse('app02:index_view')
方式2:别名不冲突即可
多个应用别名不冲突可以用应用名作为别名的前缀
path('index/', views.index, name='app01_index_view')
path('index/', views.index, name='app02_index_view')
虚拟环境
项目1需要使用:django1.11 python38
项目2需要使用:django2.22 pymysql requests python38
项目3需要使用:django3.22 request_html flask urllib3 python38
实际开发项目中我们只会给项目配备所需的环境,不需要的一概不配!!!
虚拟环境:能够针对相同版本的解释器创建多个分身 每个分身可以有自己独立的环境
pycharm创建虚拟环境:(每创建一个虚拟环境就相当于重新下载了一个全新的解释器)
命令行的方式: python -m venv pyvenv38
注意:python命令此处不支持多版本共存的操作 python27 python36 python38
激活
activate
关闭
deactivate
pip install --index-url http://mirrors.aliyun.com/pypi/simple/ django==1.11.11 --trusted-host mirrors.aliyun.com
视图层之必会三板斧
用来处理请求的视图函数都必须返回HttpResponse对象 完全正确
class HttpResponse:
pass
return HttpResponse()
def render():
return HttpResponse()
return render()
def redirect():
redirect_class = 类(祖先有个类是HttpResponse)
return redirect_class()
return redirect()
JsonResponse对象
from django.http import JsonResponse
# Create your views here.
def index_func(request):
# 返回给浏览器一个json格式的字符串
user_dict = {'name':'jason老师','age':18}
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
ps:以后写代码很多时候可能需要参考源码及所学知识扩展功能
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs):
data = json.dumps(data, cls=encoder, **json_dumps_params)
JsonResponse主要序列化字典 针对非字典的其它可以被序列化的数据需要修改safe参数为False
代码:
项目urls.py
from app01 import views
path('index/',views.index_func),
app01.views.py
from django.http import JsonResponse
# Create your views here.
def index_func(request):
# 返回给浏览器一个json格式的字符串
user_dict = {'name':'jason老师','age':18}
# import json #手动json序列化
# user_json = json.dumps(user_dict,ensure_ascii=False)
# return HttpResponse(user_json)
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
视图层之request对象获取文件
form表单携带文件类型的数据需要做到以下几点
1.method必须是post
2.enctype必须是multipart/form-data
django后端需要通过request.FILES获取文件类型的数据
验证:
views.py:
def index_func(request):
if request.method == 'POST':
file_obj = request.FILES.get('file')
print(file_obj.name) # 获取文件名称
print(file_obj)
with open(r'%s' % file_obj.name,'wb') as f:
for line in file_obj: # 文件对象支持for循环一行行读取内容
f.write(line)
return render(request,'indexPage.html')
indexPage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<h1>获取数据</h1>
<form action="" method="post" enctype="multipart/form-data">
<p>username:
<input type="text" name="username">
</p>
<p>hobby:
<input type="checkbox" name="hobby" value="basketball">篮球
<input type="checkbox" name="hobby" value="football">足球
<input type="checkbox" name="hobby" value="doublecolorball">双色球
</p>
<p>file:
<input type="file" name="file">
</p>
<input type="submit" value="选我">
<button>点我</button>
</form>
</body>
</html>
视图层之FBV与CBV
FBV
基于函数的视图
def index(request):return HttpResponse对象
CBV
基于类的视图
from django import views
class MyLoginView(views.View):
def get(self, request):
return HttpResponse('from CBV get function')
def post(self, request):
return HttpResponse('from CBV post function')
path('login/', views.MyLoginView.as_view())
会自动根据请求方法的不同自动匹配对应的方法并执
urls:
# CBV
path('login/',views.MyLoginView.as_view())
# views.py
from django import views
class MyLoginView(views.View):
def get(self,request):
return HttpResponse('from CBV get function')
def post(self,request):
return HttpResponse('from CBV post function')
CBV源码剖析(重点)
1.从CBV的路由匹配切入
path('login/',views.MyLoginView.as_view())
1.类名点名字(名字的查找问题,先从当前对象找,找不到到对象所在类->父类)
2.类名点名字并加括号调用(静态方法、绑定给类的方法)
2.函数名加括号执行优先级最高,项目一启动就会自动执行as_view方法
path('login/',views.view) # CBV路由本质还是FBV
#views.MyLoginView.as_view()--》views.view
3.浏览器地址访问login路由需要执行view函数
1.产生我们自己编写类的对象
2.对象调用dispatch方法(注意查找顺序)
4.研究父类中的dispatch方法
获取当前请求方法并转小写 之后利用反射获取类中对应的方法并执行
1.首先在项目启动时就会执行一次as_view方法,通过对as_view方法源码的查看,我们可以得知是返回一个闭包函数名view。
'''
源码
@classonlymethod
def as_view(cls, **initkwargs):
......
def view(request, *args, **kwargs):
......
return self.dispatch(request, *args, **kwargs)
# self是我们自己定义的类产生的对象
return view
'''
那么此时的urls.py文件中的配置就相当于,url('login/',views.MyLoginView.as_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)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
self:对象
request.method.lower():字符串,对象属性
self.http_method_not_allowed:默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError
'''
模板层(需要多练习理解)
"""
{{}}:主要与数据值相关
{%%}:主要与逻辑相关(循环、判断)
django的模板语法是自己写的 跟jinja2不一样
1.针对需要加括号调用的名字 django模板语法会自动加括号调用你只需要写名字就行
2.模板语法的注释前端浏览器是否无法查看的(##)
"""
1.模板语法传值
传值方式1:指名道姓的传 适用于数据量较少的情况 节省资源
return render(request, 'damo02.html', {'n1':name,'a1':age})
传值方式2:打包传值 适用于数据量较多的情况(偷懒) 浪费资源
'''locals() 将当前名称空间中所有的名字全部传递给html页面'''
return render(request, 'damo02.html', locals())
2.模板语法传值特性
1.基本数据类型正常展示
2.文件对象也可以展示并调用方法
3.函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
4.类名也会自动加括号调用
5.对象则不会
ps:针对可以加括号调用的名字模板语法都会自动加括号调用
3.模板语法之过滤器(内置函数)
| 过滤器 | 用法 | 代码 |
| --------------- | ---------------------------------------- | ------------------------------- |
| last | 获取列表/元组的最后一个成员 | {{liast \| last}} |
| first | 获取列表/元组的第一个成员 | {{list\|first}} |
| length | 获取数据的长度 | {{list \| length}} |
| defualt | 当变量没有值的情况下, 系统输出默认值, | {{str\|default="默认值"}} |
| safe | 让系统不要对内容中的html代码进行实体转义 | {{htmlcontent\| safe}} |
| upper | 字母转换成大写 | {{str \| upper}} |
| lower | 字母转换成小写 | {{str \| lower}} |
| title | 每个单词首字母转换成大写 | {{str \| title}} |
| date | 日期时间格式转换 | `{{ value| date:"D d M Y" }}` |
| cut | 从内容中截取掉同样字符的内容 | {{content \| cut:"hello"}} |
| list | 把内容转换成列表格式 | {{content \| list}} |
| add | 加法 | {{num\| add}} |
| filesizeformat | 把文件大小的数值转换成单位表示 | {{filesize \| filesizeformat}} |
| `join` | 按指定字符拼接内容 | {{list\| join("-")}} |
| `random` | 随机提取某个成员 | {list \| random}} |
| `slice` | 按切片提取成员 | {{list \| slice:":-2"}} |
| `truncatechars` | 按字符长度截取内容 | {{content \| truncatechars:30}} |
| `truncatewords` | 按单词长度截取内容 | 同上 |
代码
urls.py:
path('func/', views.func),
views.py:
def func(request):
# python基本数据类型
f = 1.11
i = 666
s = 'hello ja son big ha'
l = [11, 22, 33, 44, 55]
d = {'name': 'jason', 'age':18}
t = (11, 22, 33, 44)
se = {11, 22, 33, 44}
b = True
# 文件对象
f_obj = open(r'D:\pythonProject\djangoday04\djangoday04\wsgi.py','rb')
# 函数
def func1():
print('上午很好 下午很好')
return '真的很好'
# 类
class MyClass(object):
def get_obj(self):
return '绑定给对象的方法'
@classmethod
def get_cls(cls):
return '绑定给类的方法'
@staticmethod
def get_static():
return '静态方法'
obj = MyClass()
from datetime import datetime
ctime=datetime.today()
return render(request,'funcPage.html',locals())
funcPage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<P>{{ f }}</P>
<P>{{ i }}</P>
<P>{{ s }}</P>
<P>{{ l }}</P>
<P>{{ d }}</P>
<P>{{ se }}</P>
<P>{{ b }}</P>
<P>{{ t }}</P>
<P>{{ f_obj }}</P>
<P>{{ func1 }}</P>
<p>{{ obj }}</p>
<p>{{ obj.get_obj }}</p>
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_static }}</p>
<P>{{ MyClass }}</P>
<p>{{ i|add:10 }}</p>
<p>{{ s|add:'baby'}}</p>
<p>{{ l|length }}</p>
<p>{{ s|truncatechars:5 }}</p>
<p>{{ s|truncatewords:3 }}</p>
<p>{{ ctime|date:'Y-m-d H:i:s' }}</p>
</body>
</html>
分类:
Django
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗