Django
1 路由分发
django中每一个app都可以拥有自己的templates文件夹、static文件夹以及urls.py。
- 基于路由分发,django项目可以进行多人分组开发,每个人只编写自己的app。
整合app时,可以将所有app全部拷贝到一个新的django项目中,然后在配置文件settings.py中注册所有的app,再利用路由分发的特点在总路由中将所有的app整合起来。 - 当一个django项目的项目文件夹下的总路由urls.py中的路由url特别多时,总路由的代码非常冗余,不便于维护,此时可以通过路由分发来减轻总路由的压力。
利用路由分发,总路由不再处理请求路由与视图函数的直接对应关系,而是做分发处理,识别当前的请求url是属于哪个应用的,再分发给对应的应用去处理。
在app的文件夹中新建urls.py。
app01 urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^test/', views.func_test),
]
app02 urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^test/', views.func_test),
]
路由分发关键字 include
总路由 urls.py
from django.conf.urls import url, include
from django.contrib import admin
from app01 import urls as app01_urls # 起别名
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 如果请求url是以app01开头,就交给app01处理。
url(r'^app01/', include(app01_urls)),
# 如果请求url是以app02开头,就交给app02处理。
url(r'^app02/', include(app02_urls)),
]
当访问127.0.0.1:8080/app01/test/
时,请求urlapp01/test/
与总路由中的r'^app01/'
实现匹配,因此交给app01处理,请求url后端的test/
与app01中的子路由r'^test/'
实现匹配,执行相应的视图函数。
总路由 urls.py 简便写法
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
注意,总路由中的url的正则表达式不要使用$
,否则就会在$
处停止匹配,即无法去各个app中继续匹配。
2 名称空间
对于反向解析,不同的app中可能为路由匹配起了相同的别名。
app01 urls.py
urlpatterns = [
url(r'^test/', views.func_test, name='test_name'),
]
app02 urls.py
urlpatterns = [
url(r'^test/', views.func_test, name='test_name'),
]
一般反向解析是没有办法自动识别前缀的。
2.1 名称空间
可以通过在总路由中设置名称空间来解决反向解析中别名冲突的问题。
总路由 urls.py
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
反向解析
app01 views,py
def func_test(request):
reverse('app01:func_test')
app02 views,py
def func_test(request):
reverse('app02:func_test')
test.html
{% url 'app01:func_test' %}
{% url 'app02:func_test' %}
2.2 为别名添加app名的前缀
只要保证不同的app中的路由匹配的别名不冲突,就没有必要使用名称空间了。
规则:
app中为路由匹配起别名时需要添加app名的前缀。
app01 urls.py
urlpatterns = [
url(r'^test/', views.func_test, name='app01_test_name'),
]
app02 urls.py
urlpatterns = [
url(r'^test/', views.func_test, name='app02_test_name'),
]
3 伪静态
- 静态网页,html代码生成后,页面的内容和显示效果就基本上不会发生变化了,除非修改页面代码。
静态网页有一个固定的URL,其后缀一般是.html
,而且一般不含有问号。 - 动态网页,在不修改页面代码的前提下,页面显示的内容可以随着时间、环境或者数据库操作的结果而发生改变。
伪静态,是指将一个动态网页伪装成静态网页。
目的:增加本网站的seo查询力度,增加搜索引擎收录本网页的概率。
SEO (Search Engine Optimization),搜索引擎优化,利用搜索引擎的规则提高网站在相关搜索引擎内的自然排名。
静态网页一般不会经常修改,因此搜索引擎一般会优先收录静态网页。
urlpatterns = [
url(r'^test.html', views.func_test, name='app01_test_name'),
]
4 虚拟环境
4.1 介绍
正常开发中会为每个项目开设一个项目独有的解释器环境,该环境中只安装该项目使用的模块,用不到的模块一概不装。
虚拟环境
创建一个虚拟环境就相当于重新下载了一个纯净的python解释器。
虚拟环境是需要消耗硬盘空间的,因此不要创建太多虚拟环境。
4.2 requirements.txt
不同的项目可能使用不同的模块,即使模块相同,模块版本也可能不同。
开发中会为每一个项目单独配备一个requirements.txt文件,其内部包含了该项目所需的所有模块及版本,
使用requirements.txt文件可以在新环境上快速构建项目所需的运行环境依赖模块,便于配置生产环境。
虚拟环境 生成requirements.txt
方法1
pip freeze > requirements.txt
方法2 pipreqs模块
# 安装pipreqs模块
pip install pipreqs
# 在当前目录生成requirements.txt
pipreqs . --encoding=utf8 --force
安装模块
pip install -r requirements.txt
4.3 使用pycharm创建虚拟环境
在pycharm中,新建项目,选择Virtualenv。
选项说明
- Inherit global site-packages
新环境是否需要继承本机中已存在环境的所有模块,如果需要纯净的虚拟环境就不要勾选。 - Make available to all projects
新创建的环境是否需要被所有项目使用,建议勾选。
如果项目中存在venv文件夹,说明该项目正在使用虚拟环境。
5 django版本区别
5.1 url,path和re_path
- django 1.X中,
路由层使用url方法,url方法的第一个参数支持正则; - django 2.X 和 3.X中,
路由层一般使用path方法;
path方法的第一个参数不支持正则,即精准匹配,写什么就匹配什么;
路由层也可以使用re_path方法。
re_path方法的第一个参数支持正则,相当于django 1.X中的url方法。
urls.py
from django.urls import path, re_path
urlpatterns = [
re_path(r'^index/', index),
]
补充,也可以在django 2.X 和 3.X中使用url,但不推荐。
from django.conf.urls import url
urlpatterns = [
url(r'^index/', index),
]
5.2 path支持五种转换器
path方法的内部支持五种转换器。
示例,访问http://127.0.0.1:8080/index/123
views.py
# 以关键字参数的方式接收路由参数。
def index(request, id):
print(id, type(id)) # 123, <class 'int'>
return HttpResponse('index')
urls.py
from django.urls import path
urlpatterns = [
path('index/<int:id>/', index),
# 将第二个路由参数转换成整形,再以关键字参数的形式传给对应的视图函数。
]
str:匹配除了路径分隔符(/)之外的非空字符串,默认的形式;
int:匹配正整数,包含0;
slug:匹配字母、数字以及横杠、下划线组成的字符串;
uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00;
path:匹配任何非空字符串,包含了路径分隔符(/)。
5.3 path支持自定义转换器
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
from app01 import views
# 先注册转换器
register_converter(MonthConverter, 'mon')
urlpatterns = [
path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'),
]
5.4 级联更新和级联删除
模型层中,django 1.X默认是级联更新和级联删除;
django 2.X 和 3.X 中需要手动配置参数来实现级联更新和级联删除。
# django 1.X
models.ForeignKey(to='Publish')
# django 2.X 和 3.X
models.ForeignKey(
to='Publish',
on_update=models.CASCADE,
on_delete=models.CASCADE
)
6 视图层
6.1 视图层的三板斧
HttpResponse
返回字符串类型
render
返回html页面,支持为html页面传值
redirect
重定向
视图函数必须返回一个HttpResponse对象。
shortcuts.py
def render(request, ...):
...
return HttpResponse(content, content_type, status)
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))
# 类HttpResponsePermanentRedirect和类HttpResponseRedirect都是类HttpResponse的子类。
render如何为http页面传值
views.py
def index(request):
from django.template import Template, Context
res = Template('<h1>{{ user }}</h1>')
con = Context({'user': {'username': 'Tom', 'password': 123}})
# 将Template和Context结合起来。
ret = res.render(con)
print(ret) # <h1>{'username': 'Tom', 'password': 123}</h1>
return HttpResponse(ret)
6.2 JsonResponse对象
json格式,用于跨语言传输数据,一般前后端数据交互使用json进行过渡。
6.2.1 使用json模块
view.py
def index(request):
import json
user_dict = {'username': '刘翠英', 'password': 123}
json_str = json.dumps(user_dict, ensure_ascii=False) # 默认ensure_ascii=True,json.dumps序列化时对中文默认使用的ascii编码,需要指定为False。
return HttpResponse(json_str)
6.2.2 使用JsonResponse对象
字典序列化
from django.http import JsonResponse
def index(request):
user_dict = {'username': '刘翠英', 'password': 123}
return JsonResponse(user_dict) # {"username": "\u5218\u7fe0\u82f1", "password": 123}
from django.http import JsonResponse
def index(request):
user_dict = {'username': '刘翠英', 'password': 123}
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
列表序列化
注意:默认只能对字典进行序列化,对于其它数据类型需要修改safe参数为False。
from django.http import JsonResponse
def index(request):
user_list = ['刘翠英', '马永强', '谢广坤',]
# 默认只能对字典进行序列化,对于其它数据类型需要修改safe参数。
return JsonResponse(user_list, json_dumps_params={'ensure_ascii': False}) # 报错
TypeError at /index/
In order to allow non-dict objects to be serialized set the safe parameter to False.
from django.http import JsonResponse
def index(request):
user_list = ['刘翠英', '马永强', '谢广坤',]
return JsonResponse(user_list, json_dumps_params={'ensure_ascii': False}, safe=False)
6.3 form表单上传文件
上传文件,form标签要求:
- method指定为post;
- enctype指定为multipart/formdata。
def upload_file(request):
if request.method == 'POST':
# 获取文件数据
print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 0.jpg (image/jpeg)>]}>
# 文件对象
file_obj = request.FILES.get('file')
print(file_obj.name) # 0.jpg
with open(file_obj.name,'wb') as f:
for line in file_obj.chunks(): # 推荐使用chunks方法。
f.write(line)
return render(request,'form.html')
6.4 request对象方法总结
方法 | 介绍 |
---|---|
request.method | 获取请求方法,GET/POST |
request.POST | 返回querydict对象,包含通过POST请求提交的普通键值对数据,不包括文件。 |
request.GET | 返回querydict对象,包含所有GET请求参数。 |
request.FILES | 返回querydict对象,包含所有上传的文件。 |
request.body | 获取http请求主体,二进制格式。 |
request.path | 请求页面的路由,不包括协议以及域名,即相对于网站根目录的路径。 |
request.path_info | 在某些Web服务器配置下,主机名后的URL部分被分成脚本前缀部分和路径信息部分。path_info属性始终包含路径信息部分,不论使用的Web 服务器是。使用path_info代替path属性可以让代码在测试和开发环境中更容易进行切换。例如,如果应用的WSGIScriptAlias 设置为 “/minfo”,那么当 path 是"/minfo/music/bands/the_beatles/" 时,path_info 将是"/music/bands/the_beatles/"。 |
request.get_full_path() | 返回完整路径,包括问号后面的参数。 |
6.5 FBV 与 CBV
视图函数广义上既可以是函数也可以是类。
- FBV
Function Base Views,基于函数的视图,
在视图中使用函数处理请求。
def index(request):
return HttpResponse('index')
- CBV
Class Base Views,基于类的视图,
在视图中使用类处理请求。
urls.py
url(r'^login/', views.MyLogin.as_view()) # as_view()注意要加括号。
views.py 处理业务逻辑的视图函数,形参中一般都会包括request。
from django.views import View
class MyLogin(View):
def get(self, request):
return render(request, 'form.html')
def post(self, request):
return HttpResponse('post方法')
CBV的路由能够直接根据请求方式找到并执行对应的方法。