路由, 是一种映射关系!是把客户端请求的 url 路径和用户请求的应用程序
指django里面的视图进行绑定映射的一种关系。
注意:请求路径和视图函数不是一对一映射关系!
在django中所有的路由最终都被保存到一个变量 urlpatterns
中, urlpatterns必须声明在主应用下的urls.py总路由中。
这是由配置文件settings设置的
当客户端发送了一个 http 请求到服务端,服务端的web服务器则会从http协议中提取url地址, 从程序内部找到项目中添加到urlpatterns里面的所有路由信息的url进行遍历匹配。如果相等或者匹配成功,则调用当前url对象的视图方法。
在给urlpatterns路由列表添加路由的过程中,django一共提供了2个函数给开发者注册路由.
from django.urls import path # 字符串路由
from django.urls import re_path # 正则路由,会把url地址看成一个正则模式与客户端的请求url地址进行正则匹配
# path和re_path 使用参数一致.仅仅在url参数和接收参数时写法不一样
STATIC_URL = '/static/'
# /static/代表页面去访问的地址
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
这里的static代表它在你项目中的路径
static
下的文件,比如创建一个 test.txt
url : http://127.0.0.1:8000/static/test.txt
在前面说到过
from django.urls import path
是用于字符串路由控制的,也就是普通的路由配置
from django.contrib import admin
from django.urls import path
from ntime.views import times
urlpatterns = [
path('admin/', admin.site.urls),
path('times',times) # 当请求 /times/ 路径时,会被 times/ 所匹配,去执行 times 这个视图函数
]
注意:如果我想匹配
/times/
下的任意数字(比如:/times/123
),都想被index函数去执行,就没法办到了!
如果需要匹配/times/
下的任意数字,就需要使用正则匹配
from django.urls import re_path # 正则路由
from django.urls import re_path
urlpatterns = [
path('admin/', admin.site.urls),
path('times',times),#当请求 /times/ 路径时,会被 times/ 所匹配,去执行 times 这个视图函数
re_path(r'times/\d/',times)
]
使用正则表达式进行路径匹配
比如:访问
times/任意数字
都会被times/\d/
进行成功匹配 从而去执行times
函数
如果在times
函数中,我想接收所匹配的内容,就需要要使用到分组匹配(就是需要接收到路由传递的数据)
re_path(r'times/(\d\d)',times)# 将 (\d\d) 所匹配的值,传递给 times 函数
此时,需要 times 函数进行接收
def times(request,str):
now = datetime.datetime.now().strftime("%Y-%m-%d %X")
print(str)
return HttpResponse(now+"::"+str,)
# return render(request, "timer.html", {"now": now})
由于是无名分组,这里
times``函数的接收参数str
,可以随便写
from ntime import views
urlpatterns = [
......
re_path('book/(?P\w\w)/' , views.book),
]
将(?P\d\d)匹配的内容以
booke_name
的关键字传递给book这个函数,那么book这个函数的参数必须是booke_name
def book(request, booke_name):
print(booke_name)
return HttpResponse(booke_name)
比如我这里有两个子应用
这个时候如果需要在 urls.py
进行路由跳转等,就需要使用路由分发 include
先在子应用 app01
中创建 utls.py
在此 urls.pt
中添加路由代码
from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path('book/(?P\w\w)/' , views.book),
]
app01 的 views
:
from django.shortcuts import render, HttpResponse
# Create your views here.
def book(request, booke_name):
print(booke_name)
return HttpResponse("这是app01:"+booke_name)
同理,ntime 子应用中 也需要 创建 urls.py
ntime 的 urls
:
from django.urls import path,re_path
from ntime import views
urlpatterns = [
re_path('book/(?P\w\w)/' , views.book),
]
ntime 的 views
:
def book(request, booke_name):
print(booke_name)
return HttpResponse("这是ntime:" + booke_name)
主应用的 urls
:
urlpatterns = [
......
re_path('^app01/',include('app01.urls')),
re_path('^ntime/',include('ntime.urls')),
]
比如:
请求
app01/book/ss
, 将会被app01/
所匹配,并将请求导向到app01 的 urls.py
在4.4 的re_path的时候,在里面可以写正则表达式,进行匹配路径,特别的方便
在path路径分发的时候,也可以进行随意匹配
写法如下:
path('login//' , views.login),
这里的
就是一种通用匹配方式
- str:匹配任何非空字符串,不包括路径分隔符’/'。如果转换器不包含在表达式中,这是默认值。
- int:匹配零或任何正整数。返回一个int。
- slug:匹配由ASCII字母或数字组成的字符串,以及横线和下划线字符。例如, building-your-1st-django_site可以匹配,django_@site是不可以匹配的。
- uuid:匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,并且字母必须是小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。
- path:匹配任何非空字符串,包括路径分隔符 ‘/’,可以匹配完整的URL路径,而不仅仅是URL路径的一部分str,使用时要谨慎,因为可能造成后续的所有url匹配都失效。
使用path中的通用匹配,就好比re_path中的有名分组,将匹配的内容传递给y
并且需要注意的是,int这个匹配规则,会将匹配上的数字,转换为int类型(这个写法为 转换器)
使用django自带的path方法中的匹配规则,有点不太够用的时,就需要自定义转换器
步骤:
converters.py
文件,里面新建一个类MonConvert
- to_python(self, value)方法,它处理匹配的字符串转换成要传递到视图函数的类型。
- to_url(self, value)方法,用于处理将Python类型转换为URL中使用的字符串。
from django.urls import path, register_converter
from app01 import views
# 自定义转换器
class MonConvert:
# 自定义规则(正则表达式)
regex = '\d\d'
def to_python(self, value):
# 这里的value就是匹配的值
# 可以在这里对匹配的值进行一个操作
return int(value)
# 反向解析
def to_url(self, value):
return value
编写好之后,最好是将这个类放入到一个公共的地方
例如我放在app01
下的converter.py
中
我需要在app01
下的__init__.py
中注册这个模块
# init.py
from app01 import converter
如果需要编写多个自定义转换器,只需要写多个类即可
# 注册转换器 类,转换器名称
register_converter(MonConvert, 'yyy')
urlpatterns = [
# <转换器名称:关键字参数名称>
path('login//' , views.login, name='login'),
]
app01 的 urls
中配置路由 login/
:from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path('book/(?P\w\w)/' , views.book),
re_path('login/',views.login),
re_path('index/',views.index)
]
app01 的 views
中编写登陆函数:import datetime
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def book(request, booke_name):
print(booke_name)
return HttpResponse("这是app01:" + booke_name)
def index(request):
now = datetime.datetime.now().strftime("%Y-%m-%d %X")
return render(request, "timer.html", {"now": now})
def login(request):
# 获取get请求参数用这个
# name = request.GET.get('name')
# pwd = request.GET.get('pwd')
# print(name, pwd)
# 获取post请求参数用这个
name = request.POST.get('name')
pwd = request.POST.get('pwd')
print(name, pwd)
if name == '张三' and pwd == '1234':
return redirect('/app01/index/') # 重定向
return render(request, 'login.html')
templates
模板中创建 登陆页面 login.html
:DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆title>
head>
<body>
<form action="" method="post">
<label for="name">用户名:label>
<input type="text" value="请输入用户名" name="name" id="name">
<br>
<label for="pwd">密码:label>
<input type="text" value="请输入密码" name="pwd" id="pwd">
<br>
<input type="submit" value="登陆">
form>
body>
html>
http://127.0.0.1:8000/app01/login
当点击登陆时会报错:
这是由于Django的
CSRF安全机制
,跨域POST请求时不允许直接使用
将 settings.py
中的 MIDDLEWARE
的 CsrfViewMiddleware
注释掉
重新输入
请求对象:
request.path
request.method
request.GET
get请求参数request.get
_host()响应对象:
return render(request, 'index.html') # index.html是在templates中的路径
return HttpResponse("hello world") # 直接写要返回的字符串
return rediect('/login/') # 直接写跳转的路径, 如果使用了include,也要补全app的路径