路由层:
在路由匹配的时候,第一个参数是一个正则表达式,这也就意味着在路由匹配的时候按照正则匹配的规则去匹配,路由匹配的顺序是从上往下依次匹配的,只要匹配到一个,就会执行对应的函数,就不会执行下面的函数了。
urlpatterns = [ url('^$', views.home), # 网站首页路由 url(r'^admin/', admin.site.urls), url(r'^test/', views.test), url(r'^test_add/', views.test_add), url(r'^reg/', views.reg), url(r'', views.error), # 网站不存在路由 ] # 注意第一个参数正则表达式,匹配规则按照从上往下依次匹配,,匹配到一个之后,就立即执行对应的视图函数 # 如果路由特别多的情况下,要考虑路由位置的放置,以免匹配到别的路由(要么更换路由的位置,要么跟换路由的路径)
无名分组
将加括号的正则表达式匹配到的内容当作位置参数自动传递给对应的视图函数
url(r'^test/(\d+)/', views.test), # 匹配一个或者多个数字
def test(request, a):
print(a)
return HttpResponse("test")
有名分组
将加括号的正表表达式匹配到的内容当作关键字参数自动传递给对应的视图函数
url(r'^test/(?P<year>\d+)/', views.test), def test(request, year): print(year) return HttpResponse("test")
注意:无名分组和有名分组不能混合使用,但是可以使用多个无名分组,或者多个有名分组
反向解析:根据名字动态获取到对应路径
无名分组反向解析:
url(r'^test/(\d+)/',views.test,name='list')
后端使用:
print(reverse('list',args=(10,)))
前端使用:
{% url 'list' 10 %}
user_list = models.User.objects.all()
url(r'^edit/(\d+)/',views.edit,name='edit')
前端模版语法:
{%for user_obj in user_list%}
<a href='edit/{{ user_obj.pk }}/'></a>
{% endfor %}
视图函数:
from django.shortcuts import reverse
def edit(request,edit_id):
url = reverse('edit',args=(edit_id,))
模版:
{% url 'edit' edit_id %}
有名分组反向解析:
后端使用:
# 后端有名分组和无名分组都可以用这种形式
print(reverse('list',args=(10,)))
# 下面这个了解即可
{% url 'list' year=10 %}
总结:针对有名分组和无名分组的反向解析统一采用一种格式就可以了
后端:
reverse('list',args=(10,)) # 这里的数字通常都是数据的主键值
前端:
{% url 'list' 10 %}
反向解析的本质:就是获取到一个能够访问名字所对应的视图函数
定义:随着功能的增加会出现更多的视图,可能之前配置的正则表达式不够准确,于是就要修改正则表达式,但是正则表达式一旦修改了,之前所有对应的超链接都要修改
,那还是一件很麻烦的事情,而且可能会有一些超链接忘记修改。这时候就出现了反向解析,能够让连接根据正则表达式动态生成
应用范围:
模版中的超链接
视图中的重定向
使用的方法:
定义url时,需要为include定义namespace属性,为url定义name属性
使用的时候,在模版中使用url标签,在视图中使用reverse函数,根据正则表达式动态生成地址,减轻了后期维护的成本
from django.shortcuts import render, HttpResponse, redirect, reverse
可以给每一个路由与视图函数对应关系起一个名字,这个名字能够唯一标识出对应的关系,但是要注意这个名字不能够重复,要唯一的。
根据某一个名字获取到对应的路径
前端使用:
{ % url 'index'% }
{ % url '你给路由与视图函数对应关系起的别名' % }
后端使用:
reverse(‘你给路由与视图函数对应关系起的别名’)
无名分组的反向解析:
后端使用:
模版:
{% url 'edit' edit_id %}
前端使用:
路由分发:
django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹
这时候项目名下面的urls.py(总路由)不再做路由与视图函数的匹配关系而是做路由的分发
# 其别名避免发生冲突
from app01 import urls as app01_urls from app02 import urls as app02_urls from django.conf.urls import url, include urlpatterns = [
# 在路由分发的时候,总路由千万不要用$结尾 url(r'^admin/', admin.site.urls), url(r'^app01/', include(app01_urls)), # include是用来帮你做分发的 url(r'^app02/', include(app02_urls)) ]
在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可
from django.conf.urls import url from app01 import views urlpatterns = [ url('^index', views.index) ]
名称空间:(了解)
url(r'^app01/', include(app01_urls, namespace="app01")), url(r'^app02/', include(app02_urls, namespace="app02")) app01下的urls: urlpatterns = [ url('^index', views.index, name='index') ] app01下的views: def index(request): print('app01:', reverse('app01:index')) return render(request, 'index.html') app02下的urls: urlpatterns = [ url(r'^index/', views.index, name='index') ] app02下的views: def index(request): print('app02:', reverse('app02:index')) return HttpResponse('这个是app02的index!!!')
思考题:
import importlib importlib.import_module('app01.urls') # 等价于 from app01 import urls
伪静态页面:
搜索优化:seo
在路由的最后加上.html
虚拟环境:
不同的项目配置不同的python解释器
django1.0和django2.0之间的区别
django2.0里面的path的第一个参数不支持正则,你写什么就匹配什么,100%精准匹配
django2.0里面的re_path对应着django1.0里面的url
虽然2.0里面的path不支持正则表达式,但是它提供了五个默认的转换器:(了解)
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
自定义转换器:
class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value # 占四位,不够用0填满,超了则就按超了的位数来! register_converter(FourDigitYearConverter, 'yyyy')
PS:前端匹配到的内容默认都是字符串形式
视图层:
JsonReponse
小白必会的三板斧:
HttpResponse
render
redirect
def index(request): return JsonResponse(res, json_dumps_params={'ensure_ascii': False})
FBV与CBV
FBV:基于函数的视图
CBV:基于类的视图
要先将settings里面的'django.middleware.csrf.CsrfViewMiddleware',这句话注释掉,
from django.views import View class MyCls(View): def get(self, request): return render(request, 'index.html') def post(self, request): return HttpResponse('post')
无论是FBV还是CBV路由层都是路由对应视图函数内存地址
然后在路由层:url(r'^mycls/', views.MyCls.as_view())
文件上传:
<form action="" method="post" enctype="multipart/form-data"> <input type="file" name="my_file"> <input type="submit"> </form>
def upload_file(request): if request.method == 'POST': print('path:', request.path) # 获取到的是一个相对的路径 print('full_path:', request.get_full_path()) # 获取到的是一个完整的路径 print(request.FILES) file_obj = request.FILES.get('my_file') with open(file_obj.name, 'wb') as f: for line in file_obj.chunks(): # 自动将光标移动到首行,一行一行读... f.write(line) return HttpResponse('OK') return render(request, 'index.html')