文章目录
Django框架的第四次握手
路由分发
用法:
# 总路由导入各app中路由和模块
from django.conf.urls import url, include
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 1.路由分发方式1
url(r'^app01/',include(app01_urls)), # 只要url前缀是app01开头 全部交给app01处理
url(r'^app02/',include(app02_urls)) # 只要url前缀是app02开头 全部交给app02处理
# 2.路由分发方式2(推荐) 不用起别名
url(r'^app01/',include('app01.urls'))
url(r'^app02/',include('app02.urls'))
# 子路由中
# 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)
]
注意:
总路由里面的url千万不能加$符结尾
名称空间
- 当多个应用出现了相同的别名 正常情况下的反向解析是没有办法自动识别前缀的
解决方法:
1. 名称空间
# 总路由
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' %}
# 但只要保证名字不冲突 就没有必要使用名称空间
2. 有多个app的时候,起别名的时候加上app的前缀,这样的话就能保证多个app之间名字不冲突
app01:
urlpatterns = [
url(r'^reg/',views.reg,name='app01_reg')
]
app02:
urlpatterns = [
url(r'^reg/',views.reg,name='app02_reg')
]
伪静态
虚拟环境
pycharm创建虚拟环境
- 点击红框所选内容即可
Django版本区别
当然也有相应的方法使用正则:
# 推荐使用re_path
from django.urls import path, re_path
from django.conf.urls import url
re_path(r'^index/',index)
url(r'^login/',login)
在2.x 和 3.x 里面的re_path就等价于1.x里面的url
# 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数
path('index/<int:id>/',index)
str : 匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int : 匹配正整数,包含0。
slug : 匹配字母、数字以及横杠、下划线组成的字符串。
uuid : 匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path : 匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
1. app下新建一个.py文件写入
class MonthConverter:
regex='\d{2}' # 属性名必须为regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
2. urls.py 中
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'),
]
3. views.py中的视图函数
from django.shortcuts import render,HttpResponse,reverse
def article_detail(request,year,month,other):
print(year,type(year))
print(month,type(month))
print(other,type(other))
print(reverse('xxx',args=(1988,12,'hello'))) # 反向解析结果/articles/1988/12/hello/
return HttpResponse('xxxx')
models.ForeignKey(to='Publish',on_delete=models.CASCADE,on_update=models.VASCADE)
视图层
三板斧
"""
HttpResponse
返回字符串类型
render
返回html页面 并且在返回给浏览器之前还可以给html文件传值
redirect
重定向
"""
注意: 视图函数必须要返回一个HttpResponse对象 通过查看源码可知,render和redirect都继承了 HttpResponse
render 简单内部原理:
def myrender(request):
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)
JsonResponse对象
'''
json格式数据,能够实现前后端跨语言传输数据
前端序列化
JSON.stringify() 对应 json.dumps()
JSON.prase() 对应 json.loads()
'''
给前端返回字符串
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]
# 1. 方式1
# 先转成json格式字符串
json_str = json.dumps(user_dict,ensure_ascii=False)
# 将该字符串返回
return HttpResponse(json_str)
# 2. 方式2
# 读源码掌握用法
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})
注意:
# JsonResponse默认只能序列化字典 序列化其他需要加safe参数
return JsonResponse(l,safe=False)
form表单上传文件
'''
form 表单上传文件类型数据需要注意以下两点
1. method必须指定成post
2. enctype必须换成formadta
'''
前端代码
<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" value="提交">
</form>
views.py
def ab_file(request):
if request.method == 'POST':
print(request.POST)
print(request.FILES) # 获取文件数据
file_obj = request.FILES.get('file') # 获取文件对象
with open(file_obj.name,'wb') as f:
for line in file_obj.chunks(): # 推荐加上chunks方法 其实跟不加是一样的
f.write(line)
return render(request, 'form.html')
request对象方法
"""
request.method
request.POST
request.GET
request.FILES
request.body # 原生的浏览器发过来的二进制数据 后面详细的讲
request.path # 获取完整url
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
FBV和CBV
# 视图函数既可以是函数也可以是类
def index(request):
return HttpResponse('index')
FBV
def index(request):
return HttpResponse('FBV')
CBV
# CBV路由
url(r'^login/',views.MyLogin.as_view())
# views.py
from django.views import View
class MyLogin(View):
def get(self,request):
return render(request,'form.html')
def post(self,request):
return HttpResponse('post方法')
"""
FBV和CBV各有千秋,request形参是必不可少的
CBV特点
能够直接根据请求方式的不同直接匹配到对应的方法执行
"""
CBV源码剖析总结
注意: 不要轻易修改源码
通过urls.py中的路由分发
url(r'^login/',views.MyLogin.as_view())
'''
函数名/方法名 加括号执行优先级最高
'''
as_view()主要源码
@classonlymethod # 继承了classmethod 方法 只能被类调用
def as_view(cls, **initkwargs):
'''
as_view 被类方法修饰,cls就是我们自己写的类
'''
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls是我们自己写的类
# self = MyLogin(**initkwargs) 产生一个我们自己写的类的对象
return self.dispatch(request, *args, **kwargs)
return view
'''
as_view方法返回值是view方法,此时
views.MyLogin.as_view() 等同于 views.view
这时,我们可以发现view方法返回值是self.dispatch(request, *args, **kwargs)
'''
dispatch(request, *args, **kwargs)主要源码
# CBV的精髓所在
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
"""
反射:通过字符串来操作对象的属性或者方法
handler = getattr(自己写的类产生的对象,'get',当找不到get属性或者方法的时候就会用第三个参数)
handler = 我们自己写的类里面的get方法
"""
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
'''自动调用get方法'''