一、有名无名的反向分解
1.1无名分组的反向解析.
通过前端或者后端给无名分组传递变量,通常传递的变量为数据的主键值,用来处理数据的增加或者删除
views.index:指定视图函数,index为设定的函数
url(r'^edit/(d+)/',views.edit,name='xxx') #建立无名分组 def edit(request,edit_id): #前端传递数据 reverse('xxx',args=(edit_id,)) {%for user_obj in user_queryset%} #后端传递数据 <a href="{% url 'xxx' user_obj.id %}">编辑</a> {%endfor%}
1.2、有名分组反向解析
url(r'^func/(?P<year>d+)/',views.func,name='ooo') #建立有名分组 # 前端 <a href="{% url 'ooo' year=123 %}">111</a> 了解 <a href="{% url 'ooo' 123 %}">222</a> 记忆 # 后端 # 有名分组反向解析 写法1 了解 print(reverse('ooo',kwargs={'year':123})) # 简便的写法 减少你的脑容量消耗 记跟无名一样的操作即可 print(reverse('ooo',args=(111,)))
二、路由分发
2.1、路由分发的原因
每一个Django项目中每一个应用都有templates文件夹、urls.py文件、static文件夹
路由分发就是将应用拆分给多个人开发,写自己的app,通常我们命名为app01
最终使用Django中的url文件将各个app中的url文件链接起来,从而减轻总路由的压力。
所以总路由不再做路由与视图函数之间的连接,只负责总路由与分路由之间的连接
2.2、总路由
总路由连接子路由的语句,使用include:
URL(r'^app01/',include (app01.urls))
总路由里面的URL后面不加$
2.3、子路由
子路由则负责与相关的视图函数views连接
from Django.conf.urls import url
from app01 import views
urlpatterns = [url(r'^res/',views.res)]
# 总路由 from app01 import urls as app01_urls from app02 import urls as app02_urls urlpatterns = [ url(r'^admin/', admin.site.urls), # 1.路由分发 url(r'^app01/',include(app01_urls)), # 只要url前缀是app01开头 全部交给app01处理 url(r'^app02/',include(app02_urls)) # 只要url前缀是app02开头 全部交给app02处理 # 2.终极写法 推荐使用 url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls')) # 注意事项:总路由里面的url千万不能加$结尾 ] # 子路由 # app01 urls.py from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^reg/',views.reg) ] # app02 urls.py from django.conf.urls import url from app02 import views urlpatterns = [ url(r'^reg/',views.reg) ]
三、名称空间解析
3.1、名称空间的建立
当多个应用出现相同的别名时,反向分析的时候无法自动识别前缀
需要在总路由里面建立名称空间,namespace = ‘app01
# 总路由 url(r'^app01/',include('app01.urls',namespace='app01')), url(r'^app02/',include('app02.urls',namespace='app02')) # 解析的时候 # 子路由app01 urlpatterns = [ url(r'^reg/',views.reg,name='reg') ] # 子路由app02 urlpatterns = [ url(r'^reg/',views.reg,name='reg') ] reverse('app01:reg') reverse('app02:reg') {% url 'app01:reg' %} {% url 'app02:reg' %}
3.2、解决别名重复的方法
子路由中的别名重复是使用名称空间的原因,而在子路由中别名的前面添加子路由的名字,就可以避免子路由中的别名重复问题:name = 'app01_reg'
urlpatterns = [ url(r'^reg/',views.reg,name='app01_reg') ] urlpatterns = [ url(r'^reg/',views.reg,name='app02_reg') ]
四、伪静态
4.1、什么是伪静态
静态网页是写死的,改不了,将一个动态网页伪装成一个静态的网页,即在网址后面加.html
urlpatterns = [ url(r'^reg.html',views.reg,name='app02_reg') ]
4.2、为什么要伪装静态网页
内容搜索时会优先提供静态网页,可以提高本网站的SEO查询力度,并且增加搜索引擎将本网站添加入收藏的可能性
4.3、总结
再怎么优化也比不上RMB玩家
五、虚拟环境
5.1、什么是虚拟环境
虚拟环境:一个纯净的解释器环境,每个项目都会配备一个虚拟环境,只安装需要的模块
5.2、虚拟环境的影响
没建立一个虚拟环境,相当于装了一个解释器,会占用硬盘空间
5.3、虚拟环境中模块的安装
开发中我们给每一个项目配备一个requirements.txt文件只需要输入一条命令就能安装所有的模块
六、Django版本的区别
6.1、路由层的URL
Django01.x路由层使用的是URL方法,URL()第一个参数支持正则
Django02.x和03.x路由层使用的是path方法,path()第一个参数不支持正则,写什么就匹配什么
在Django02.x和03.x中可以使用re_path等同于path
from django.urls import path, re_path from django.conf.urls import url re_path(r'^index/',index), url(r'^login/',login)
6.2、path不支持正则但是支持五种装换器
path第二个路由将内容转换成整型,以关键字的形式传递给后面的视图函数
可以转换的五种类型:
1.str:可以匹配除了/以外的非空字符,为默认形式
2.int:匹配正整数,包括0
3.slug:匹配字母、数字、横杠、下划线组成的字符串
4.uuid:匹配格式化的uuid,例如:075194d3-6885-417e-a8a8-6c931e272f00
5.path:匹配非空字符串
path('index/<int:id>/',index) # 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数 def index(request,id): print(id,type(id)) return HttpResponse('index')
6.3、除了五种转换器以外,还支持自定义转换器(了解)
class MonthConverter: regex='d{2}' # 属性名必须为regex def to_python(self, value): return int(value) 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'), ]
6.4、模型层中的外键
Django01.x中的外键都是联级更新删除的,Django2.0x和3.0x需要手动配置参数 on_delete = models.CASCADE()
models.ForeignKey(to='Publish') models.ForeignKey(to='Publish',on_delete=models.CASCADE())
七、视图层
7.1、视图层三板斧
HttpResponse:返回字符串类型
render:返回HTML页面,并在返回浏览器前还能给HTML文件传值
redirect:重定向
视图函数必须要返回一个HttpResponse
#研究三者源码可得
The view app01.views.index didn't return an HttpResponse object. It returned None instead. # render简单内部原理 from django.template import Template,Context res = Template('<h1>{{ user }}</h1>') con = Context({'user':{'username':'jason','password':123}}) ret = res.render(con) print(ret) return HttpResponse(ret)
7.2、jsonResponse对象
前端序列化:json.stringify() json.parse()
后端序列化:json.dumps() json.loads()
jsonResponse必定会返回一个httpresponse,需要进行转码,在序列化时添加ensure_ascii = False
import json from django.http import JsonResponse def ab_json(request): user_dict = {'username':'jason好帅哦,我好喜欢!','password':'123','hobby':'girl'} l = [111,222,333,444,555] # 先转成json格式字符串 # json_str = json.dumps(user_dict,ensure_ascii=False) # 将该字符串返回 # return HttpResponse(json_str) # 读源码掌握用法 # return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False}) # In order to allow non-dict objects to be serialized set the safe parameter to False. # return JsonResponse(l,safe=False) # 默认只能序列化字典 序列化其他需要加safe参数
7.3、form表单上传文件及后端操作
7.3.1、from表单上传文件
form表单上传文件时,需要将method指定成post,将enctype换成formdata
7.3.2、后端操作
先将请求改成post,再获取文件对象,打开文件文件,写入文件。
def ab_file(request): if request.method == 'POST': #将请求改成post # print(request.POST) # 只能获取普通的简直对数据 文件不行 print(request.FILES) # 获取文件数据 # <MultiValueDict: {'file': [<InMemoryUploadedFile: u=1288812541,1979816195&fm=26&gp=0.jpg (image/jpeg)>]}> file_obj = request.FILES.get('file') # 文件对象 print(file_obj.name) with open(file_obj.name,'wb') as f: for line in file_obj.chunks(): # 推荐加上chunks方法 其实跟不加是一样的都是一行行的读取 f.write(line) return render(request,'form.html')
7.4、request的对象方法
request.method == :获取请求方式
request.post:只能获取普通的键值对数据,不能获取文件
request.get:获取get请求
request.files:专门获取文件
request.body:原生浏览器发过来的数据
request.path:只能拿到路由,不能拿到路由后面的参数
request.path_info:只能获取URL后面路由,不能拿到路由后面的参数
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