Loading

Django框架之路由层

【一】Django的路由系统

【1】什么是URL配置

【2】基本格式

## Django1.x版本语法

from django.conf.urls import url

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]
## Django2.x+版本语法
from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

【3】URL转换器

  • 在Django2.x+版本中,路由层支持URL转换器,可以从url中提取变量,传递到视图函数中。
  • 以下是一些常见的URL转换器
  1. int:匹配零或正整数。
  2. str:匹配除了斜杠之外的任何非空字符串。
  3. slug:匹配由ASCII字母或数字,以及连字符和下划线组成的字符串。
  4. uuid:匹配 UUID 格式的字符串。
  5. path:匹配任何非空字符串,包括斜杠。
## 这些转换器可以通过在URL模式中使用尖括号来指定,例如:

## urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('blog/<int:year>/', views.show_year_archive),
    path('blog/<int:year>/<str:month>/', views.show_month_archive),
]

## views.py
from django.http import HttpResponse

def show_year_archive(request, year):
    return HttpResponse("Year: " + str(year))

def show_month_archive(request, year, month):
    return HttpResponse("Year: " + str(year) + ", Month: " + month)

【4】使用正则表达式

  • 在django2.0版本之前,路由层url配置都是用url的,它本身就是支持正则表达式的
  • 而在2.0版本之后,关键字变成了path,它是不支持正则表达式的
  • 为了兼容老版本项目,需要手动导入re_path方法以此支持正则表达式
from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

【二】路由匹配

【1】路径参数相似

# 路由匹配
path('test', views.test),
path('testadd', views.testadd),
  • 如果路由层这样子配置的话,会发现无论如何都匹配不到testadd对应的内容
  • 是因为在匹配路由的时候,是从头到尾的顺序进行的,当输入testadd时,就已经满足了匹配test的条件
  • 当匹配成功后就会停止匹配,紧接着执行对应的视图函数

【2】解决办法

# 路由匹配
path('test/', views.test),
path('testadd/', views.testadd),
  • 只需要在匹配的路由后面加上一个斜杠即可
  • 这样做就意味着匹配的对象必须是以斜杠结尾,这样子testadd就不满足test/的匹配条件了

【3】django自动匹配两次

  • 当在网址输入test,或者testadd都会获得到test/或者testadd/的内容
  • 这是因为django在匹配路由时会自动匹配两次,第一次匹配就是以浏览器输入的内容为基准
  • 如果没有匹配成功,django会自动申请以浏览器输入的内容加上斜杠为条件,进行二次匹配

【4】关闭自动二次匹配

  • 如果有特殊需求可以关闭二次匹配的功能,只需要在配置文件加上一行代码即可
APPEND_SLASH = True

【5】首页匹配内容

  • 如果没有进程首页URL匹配的话,每次打开127.0.0.1这个地址时都会显示404 not found,这非常不美观
  • 只需要把首页对应的路由设置为空即可
path('', views.test),

【三】无名分组

  • 分组就是将某段正则表达式用括号括起来
  • 当输入的url与正则表达式匹配上后就会传递给视图函数
  • 对于无名分组而言,视图函数需要以任意一个形参来接收
# 无名分组
re_path(r'^text/(\d+)/', views.test),

【四】有名分组

  • 有名分组在语法上和无名分组不同,使用有名分组时需要给它取一个名字
  • 传递给视图函数的时候,视图函数需要用这个名字作为形参接收
# 有名分组
re_path(r'^testadd/(?P<year>\d+)', views.testadd),

【五】反向解析

【1】反向解析的本质

  • 本质上是通过一些方法得到一个结果,该结果可以访问到对应的url从而触发相应的视图和功能

  • 首先要给路由起一个别名

re_path(r'index/(\d+)/(\d+)/', views.func,name="index"),

【2】后端反向解析

from django.shortcuts import render, HttpResponse,reverse
def home(request):
  reverse('index', args=(1, 2)))

【3】前端反向解析

<a href="{% url 'index' 123 234 %}">111</a>

【六】无名有名分组反向解析

【1】有名分组反向路由解析

  • 本质上还是通过一些方法得到一个结果,该结果可以访问到对应的url从而触发相应的视图和功能
## urls.py
# 无名分组反向解析
re_path(r'^index/(\d+)/', views.index, name='xxx'),

## views.py
def home(request):
    print(reverse('xxx')
    return render(request, 'home.html')
          
## html
<a href="">{% url 'xxx' %}</a>
  • 以这样的配置,访问对应的url会发现报错
  • 因为路由配置的正则表达式规定了我们需要在后面跟数字
## 解决办法
## views.py
def home(request):
    print(reverse('xxx', args=(1,)))
    return render(request, 'home.html')

## html
<a href="">{% url 'xxx' 123 %}</a>

【2】案例

  • 通常方向解析的意义都是拿到想要的数据
  • 如表中的主键
  • 比如我在页面上有一张学生信息表的数据,有一个编辑按钮可以编辑每个学生的信息
  • 这时候就可以在前端页面的那个数字换成对应学生的ID,然后后端就可以方便快捷的操作对应学生的信息
## urls
re_path(r'^edit_info/(\d+)', views.edit_info, name='edit')

## html
<a href="{% url 'edit' user.id %}" class="btn btn-info btn-xs">编辑</a>

## views.py
def edit_info(requests, args):
    user_id = args
    user_obj = models.Student.objects.filter(id=user_id).first()
    username = user_obj.username
    password = user_obj.password
    if requests.method == 'POST':
        username = requests.POST.get('username')
        password = requests.POST.get('password')
        user_obj = models.Student.objects.filter(id=user_id)
        user_obj.update(username=username, password=password)
        return redirect('/user_info/')
    return render(requests, 'edit_info.html', locals())

【七】路由分发

【1】前言

  • Django项目的每一个应用都可以拥有属于自己的templates文件夹,static文件夹,urls文件
  • 正是基于上诉特点,一个django项目可以很方便的做到分组开发,每个人只写自己的app
  • 最后只需要将这些app拷贝到一个新项目当中,将app全部都进行注册,
  • 在利用路由分发,将每个app的路由对应到根目录下的urls.py文件即可

【2】语法

  • 首先要导入include方法from django.urls import include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', include('app1.urls')),
    path('app2/', include('app2.urls'))
]

【3】捕获参数

  • 目的地URLconf会收到来自父URLconf捕获的所有参数,看下面的例子:
# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]
  • 在以上的例子中,当在浏览器输入xxx/blog时,对应的视图函数就可以捕获到xxx的内容,以username作为形参接收

【4】向视图函数传递额外的参数

  • 在路由配置后面还可以传一个字典,字典的键将作为视图函数的形参
  • 也可以以同样的方式给主路由层传递额外的字典
from django.urls import path
from . import views

urlpatterns = [
    path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]
  • 在以上的例子中,如果浏览器输入blog/2024
  • 对应的视图函数将调用views.year_archive(request, year='2005', foo='bar')

【八】名称空间

【1】应用命名空间(app_name)

  • 当两个app的路由的name属性相同时
  • 通过反向解析得到的url就会造成错乱,django不能够识别这两个不同app下的相同路由name
  • 这时候就需要名称空间加以区分

【2】使用方法

  • 首先在不同的app下的urls.py加一行代码来指定当前app下的名称空间
  • 再进入到总路由文件下配置相应的代码
## app1下的urls.py
app_name = 'app01'

## app2下的urls.py
app_name = 'app02'

## 根路由urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', include(('app1.urls', 'app1'), namespace='app01')),
    path('app2/', include(('app2.urls', 'app2'), namespace='app02'))
]
posted @ 2024-03-25 17:27  HuangQiaoqi  阅读(7)  评论(0编辑  收藏  举报