Django 前端基础汇总
Day 62 Django细讲
视频列表
- 无名有名反向解析
- 路由分发
- 名称空间
- 伪静态概念
- 虚拟环境
django 请求生命周期流程图
非常重要,每个人必会
- 浏览器 -> web服务网关接口(django自带的是 wsgiref )
- 请求来的时候解析封装
- 响应走的时候打包处理
-
django 自带的wsgiref模块
本身能够支持的并发量很小,1k左右
上线后,会换成uwsgi,并且添加nginx(暂时不讲)
WSGI 和 wsgiref 和 uwsgi 什么关系?
大写的 WSGI 是协议
小写的 wsgiref 和 uwsgi 是实现该协议的功能模块 -
wsgiref 作用:
- 请求来的时候解析封装,
- 走的时候打包处理
-
扩展知识点:缓存数据库
- 数据提前给你准备好了,你要的时候直接拿就可以。
提升效率和响应时间
当你修改数据的时候,不是立刻修改完成的,而是过一段时间才会修改。因为你访问的是缓存的数据。
Django 框架
- 中间件 : 1-2-3
类似 Django 保安
可以先去缓存数据库,不去框架。
如果缓存没有,再去框架。
返回的时候,先给缓存丢一份,再给你。
1. urls.py 路由层
# 路由匹配
urlpatterns = [
url(r'^test/', views.test),
url(r'^testadd/', views.testadd),
]
路由匹配 注意事项 | 说明 |
---|---|
1. 第一个参数是正则表达式。 | 只要第一个能匹配到,那么就会直接返回,所以要以 / 结尾。 |
2. 自动加 / 。 | 如果没匹配到,可能会帮你自动加一个 / (不是浏览器加的) |
3. 严谨:r'^test/$' | 加个美元符号。 |
4. 也可以取消自动加/ | APPEND_SLASH = False |
5. 匹配首页 | r'^$' |
6. 匹配尾页(404) | r’’,啥都不写,放在最后面,容易出bug。 |
分组
给某一段正则表达式,括号()扩起来
无名分组 () 未知参数
路由匹配
r'^test/(\d+)/'
def test(request, xx):
pass
pass
有名分组 ?P<名字> 关键字参数
url(r'^testadd/(?P<year>\d+)', views.testadd)
def testadd(request, year):
pass
嘻嘻,无名有名不能混用。但是同一个分组,可以使用n多次
/123/234/235/45636/53/6
url(r’^index/(\d+)/(\d+)/(\d+)/’, views.index)
s
url(r’^index/(?P\d+)/(?P\d+)/(?P\d+)/’, views.index)
def index(request, *args, **kwargs)
反向解析
通过一些方法,得到一个结果,
该结果可以直接访问对应的 url ,
从而触发视图函数运行。
<!-- home.html -->
<a href="/func/">111</a>
<a href="/func/">222</a>
<a href="/func/">333</a>
<a href="/func/">444</a>
url(r'^$', v2.home),
url(r'^func/', v2.func),
def func(request):
return HttpResponse('func')
def home(request):
return render(request, 'home.html')
- 如果修改 func 这个名字, 那么home 页面的所有 <a> 标签都会失效
- 对于写死的参数,先给视图函数起别名
前端反向解析
<a href="{% url 'ooo' %}">111</a>
- 替换 a 标签 里面的 href
- 那么路由(网址)还是前面的路由
# 点击 href 带有 ooo 的标签,都会走到 对应的 views
url(r'^func_k/', v2.func, name='ooo'),
后端反向解析
from django.shortcuts import render, HttpResponse, redirect,reverse
def home(request):
print(reverse('ooo'))
return render(request, 'home.html')
注意
- 别名不能冲突!
无名分组的反向解析
url(r'^edit/', 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 %}
有名分组的反向解析(视图函数要参数)
url(r'^func/(?P<year>\d+)/', views.func, name='ooo'),
<a href="{% url 'ooo' year=123 %}">了解</a>
<a href="{% url 'ooo' 123 %}">记忆</a>
def func(request, year):
# 有名分组 - 反向解析 - 写法1(了解,不必记)
# print(reverse('ooo', kwargs={'year': 123}))
# 简便写法(记忆)
print(reverse('ooo', args=(111, )))
return render(request, 'func.html')
2. views.py 视图层
走的时候直接返回中间件,不经过路由层了。
3. 模板层 templates 文件夹
4.模型层 models.py ORM
去数据库拿到文件
路由层
## 路由分发
每个 app 新建一个自己的 urls.py。
把总路由的拷过来,然后不要的清空。
## 有什么用?
### 第一种情况:分组开发,每个人开发自己的app。
- django 的应用,每个都可以拥有自己的 templates 文件夹,urls.py 和 static 文件夹
- 组长是要把每个人写的app,copy到一个项目中,然后在配置文件中注册所有app,
- 再利用《路由分发》的特点,将所有的app整合起来。
### 第二种情况当一个项目中的 url 特别多,总路由特别多,怎么办?
利用路由分发,减轻总路由的压力。
# app01.urls
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^reg/', views.reg) # app01 的 reg
]
总路由:先识别哪个app的,类似医院分诊台
# 只要 app01 开头,全部找 app01
from app01 import urls as app01_urls
from app02 import urls as app02_urls
...
url(r'^app01/', include(app01_urls)),
url(r'^app02/', include(app02_urls)),
# 终极写法
# 点一下,import 都不用了
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
# 注意,总路由的 url 不能加 $ 结尾。
名称空间
问题:如果两个人开发的,多个应用的name起成一样的
,反向解析还能识别吗?
答:不能。
解决办法:
- 保证名字不冲突。(别名加上app前缀)
- 实在冲突了,用名称空间
名称空间。
# 总路由,加个 namespace
url(r'^app01/', include('app01.urls', namespace='app01')),
# 解析的时候,加个 name
urlpatterns = [
url(r'^reg/', views.reg, name='reg') # app01 的 reg
]
# app01/views.py
def reg(request):
# 名称空间解析
print(reverse('app01:reg'))
return HttpResponse('app01:reg')
# home.html
{% url 'app01:reg' %}
{% url 'app02:reg' %}
加前缀写法
# 总路由,加个 namespace
url(r'^app01/', include('app01.urls')),
# 解析的时候,加个 name
urlpatterns = [
url(r'^reg/', views.reg, name='app01_reg') # app01 的 reg
]
# app01/views.py
# 名称空间解析
print(reverse('app01_reg'))
伪静态
## 静态网页
数据是写死的,万年不变
## 伪静态网页
动态网页伪装成静态网页。比如xxx.html网页
## 为什么要伪装呢?
增大本网站的 SEO 查询力度,并增加搜索引擎收藏本网站的概率。
搜索引擎本质是一个巨大的爬虫程序,被搜索到了会被优先展示
## 总结:
无论你怎么优化,始终干不过rmb玩家优化。
优化方法:乍一看,静态网页
url(r'^reg.html', views.reg, name='app02_reg') # app02 的 reg
虚拟环境
-
什么是虚拟环境?
每开发一个项目,会给该项目一个独有的解释器环境
只有它需要的模块,用不到的一概没有。
Linux:缺什么才装什么。
每创建一个虚拟环境,相当于重新下载一个纯净的 Python 解释器。
虚拟环境不要太多,消耗硬盘空间的。 -
每一个项目都要很多模块,每个模块版本可能不太一样,我该如何安装?
开发中我们会给每个项目配备一个 requirements.txt 文件,
书写了所有需要的模块
只需一句命令,即可全部运行安装, -
创建方法
- New Project --》 Pure Python --》 new environment using Virtualenv
- 两个按钮,不需要 inhert(继承)。要勾上make availab,可以被其他项目所使用。
- 如果左侧有 venv 文件夹,说明用的是虚拟环境。
- 重新新建一个 django 项目,勾选 existing interpreter。
-
注意事项
- 不要每次新建项目都是 New environment,否则越来越卡
django版本区别
1. url 的区别
- 【1.x】使用的是 url() 方法,正则匹配
- 【2.x】,【3.x】使用的是 path() 方法,精准匹配
【2.x】,【3.x】中使用正则匹配:
from django.urls import path, re_path 用 re_path()
2. path 内部支持5种转换器(纯了解)
path('index/<int:id>/', index)
def index(request, id):
print(id, type(id))
return HttpResponse('index'')
将第二个路由,转成整形,以关键字参数的形式,传递给后面的视图函数。
而原先的 url() 方法,转换成字符串
剩下的参考博客:小猿取经。
3. 除了五个默认的转换器以外,支持《自定义转换器》
例如:转两位数字,变成月份。
参考博客。
4. 第二版、第三版的级联更新级联删除需要手动配置
models.ForeignKey(to='Publish'', on_delete=models.CASCADE)
视图层
三板斧
- HttpResponse
- render
- redirect
(正确)视图函数必须要返回一个 HttpResponse 对象
因为看源码,无论哪一板斧,都继承了 h-r-。
JsonResponse
前后端数据交互的时候,需要Json作为过度,作为跨语言传输数据。
第一步,给前端浏览器返回一饿 Json 格式的字符串。
import json
def ab_json(request):
user_dict = {'username': 'jason好帅哦', 'password': '123', 'hobby': 'girl'}
# 改成json格式,拒绝自动转码
json_str = json.dumps(user_dict, ensure_ascii=False)
return HttpResponse(json_str)
第二种方法
from django.http import JsonResponse
def ab_json(request):
user_dict = {'username': 'jason好帅哦', 'password': '123', 'hobby': 'girl'}
# 读源码,这里打散,可以加参数
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
第三种方法:非字典序列化,设置safe参数
from django.http import JsonResponse
def ab_json(request):
l = [111, 222, 333, 444]
return JsonResponse(l, safe=False)
form 表单上传文件
- method 必须是 post
- enctype 必须是 formdata
<!-- form 表单上传文件 -->
<form action="" method="post" enctype="multipart/form-data">
<p>username <input type="text" name="username" id=""></p>
<p>file: <input type="file" name="file"></p>
<input type="submit" name="">
</form>
def ab_file(request):
if request.method == 'POST':
# request.post 只能拿数据,拿不到文件
print(request.POST)
# <QueryDict: {'username': ['jason']}>
# request.FILES 获取文件
print(request.FILES)
# < MultiValueDict: {'file': [ < InMemoryUploadedFile: WechatIMG746.jpeg(image / jpeg) >]} >
file_obj = request.FILES.get('file')
print(file_obj.name)
# 存文件
with open(file_obj.name, 'wb') as f:
# 推荐加上 chunks() 方法
for line in file_obj.chunks():
f.write(line)
return render(request, 'form.html')
FBV 和 CBV
CBV 类的写法
针对视图函数,既可以是函数,也可以是类。
from django.views import View
class MyLogin(View):
# 根据get还是post请求,来匹配对应的方法执行
def get(self, request):
return render(request, 'form.html')
def post(self, request):
return HttpResponse('post 方法')
# CBV 路由
url(r'^login/', views.MyLogin.as_view())
CBV 内部实现