小谈Django中的路由系统

Django的路由系统

URLconf配置

from django.conf.urls import url

urlptterns = [
	url(正则表达式,views视图,参数,别名),
]

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^publisher/', views.publisher),
    url(r'^add_publisher/', views.add_publisher),
    url(r'^del_publisher/', views.del_publisher),
    url(r'^edit_publisher/', views.edit_publisher),

    url(r'^book/', views.book),
    url(r'^add_book/', views.add_book),
    url(r'^del_book/', views.del_book),
    url(r'^edit_book/', views.edit_book),

    url(r'^author/', views.author),
    url(r'^add_author/', views.add_author),
    url(r'^del_author/', views.del_author),
]

settings.py中的ROOT_URLCONF

ROOT_URLCONF = 'bookmanager.urls'
# 上面这个指定的就是urls.py中的urlpatterns

示例一

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # ^ 以什么开头 ; $ 以什么结尾
    url(r'^blog/$', views.blog),
    # [0-9]{4} 4位0-9之间的数字(可以代表年份) ; \d{2} 2位数字(可以代表月份)
    # 想要访问此页面,网址:http://127.0.0.1:8000/blog/2019/12/
    url(r'^blog/[0-9]{4}/\d{2}', views.blogs),
]
# urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^blog/$', views.blog),
    # 继上面的操作后又加入了分组
    # 分组后网页无法显示,显示函数缺少两个参数
    # 所以要在views.py中的blogs加入两个参数
    url(r'^blog/([0-9]{4})/(\d{2})/$', views.blogs),
]


# views.py

def blog(request):
    return HttpResponse('blog')

# request后面的两个参数是必须要加的,因为urls中的路径分组了
def blogs(request,year,month):
    print(year,type(year))
    print(month)
    return HttpResponse('blogs')

# 登录后print出来的结果:
2019 <class 'str'>
12
# 这两个值可以直接拿到,也可以直接用在函数中.下面以del_publisher为例

示例二

# urls页面
urlpatterns = [
    url(r'^admin/', admin.site.urls),

    ...
    url(r'^del_publisher/(\d+)', views.del_publisher),
    ...

# views页面
def del_publisher(request,pk):
    # pk = request.GET.get('pk')
    obj = models.Publisher.objects.filter(pk=pk).first()
    if not obj:
        return HttpResponse('您所查询的出版社不存在!')
    obj.delete()
    return redirect('/publisher/')
    
# publisher.html
    {% for publisher in all_publishers %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ publisher.id }}</td>
            <td>{{ publisher.name }}</td>
{#            <td><a href="/del_publisher/?pk={{ publisher.pk }}">删除</a></td>#}
            <td><a href="/del_publisher/{{ publisher.pk }}/">删除</a></td>
            <td><a href="/edit_publisher/?pk={{ publisher.pk }}">编辑</a></td>
        </tr>
    {% endfor %}

分组后:

url(r'^del_publisher/(\d+)', views.del_publisher),

# 分组后从url中捕获参数,捕获的参数会按照  位置传参  传递给函数

命名分组

示例一:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^blog/$', views.blog),
    url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blogs),
]

# 分组后从url中捕获参数,捕获的参数会按照  关键字传参  传递给函数

def blogs(request,month,year):
    print(year,type(year))
    print(month)
    return HttpResponse('blogs')

# print结果:
2019 <class 'str'>
99
# 关键字传参:传参时位置变化没影响,但是参数名字要一致

注意事项:

  1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  3. 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  4. 每个正则表达式前面的'r' 是可选的但是建议加上。

URLconf匹配的位置

URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

例如,http://www.example.com/myapp/ 请求中,URLconf 将查找 /myapp/ 。

在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找 /myapp/ 。

URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POSTGETHEAD等等 —— 都将路由到相同的函数。

捕获的参数永远都是字符串

每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blogs)

传递到视图函数views.year_archive() 中的year month参数永远是一个字符串类型

视图函数中指定默认值

比如:路由中两个路径指向同一个函数时,一个不需要传参,一个需要传参,这个时候可以给参数指定默认值,如下:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^blog/$', views.blog),
    url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blog),
]


def blog(request,*args,**kwargs):
    return HttpResponse('blog')

include其他的URLconfs

比如有多个app时,所有的路由还都写在urls.py中,耦合性太高,这个时候需要把路由分发,给路由解耦

做法:把urls.py复制到app01中,然后把和settings.py同级的urls中除了admin,把其他都删掉(或者注释),再利用include把路由再一次分发

# 和settings.py同级的urls
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r'^blog/$', views.blog),
    # url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blog),
    url(r'^', include('app01.urls')),
]


# app01中的urls
from django.conf.urls import url
# from django.contrib import admin
from app01 import views

urlpatterns = [
    
    url(r'^blog/$', views.blog),
    url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blog),
]

# 如果第一个urls中的include前面^后面加上app01 ==> 启动项目后每个路径都要加上app01这个前缀
# 至于为什么^后面要加上app01 ==> 因为有可能有多个app

# 为什么要用include,因为以后项目不是一个人开发时(需要协同开发时),有可能每个人开发一个app,这样利于管理

url的命名和反向解析

静态的

命名

app01的urls
    url(r'^login/', views.login, name='login'),

反向解析

模板中:

{% url 'login' %}

# 1.如果settings.py同级的urls中是这样:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('app01.urls')),

{% url 'login' %}  ==>  反向解析成 "/login/"

# 2.如果settings.py同级的urls中是这样:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/', include('app01.urls')),

{% url 'login' %}  ==>  反向解析成 "/app01/login/"

py文件中:

from django.urls import reverse

reverse('login')  ==>  "/app01/login/"

示例:

app01的urls
url(r'^classes/', views.classes, name='class'),

views中
from django.shortcuts import render, redirect, HttpResponse,reverse
add_classes函数中重定向到classes.html页面的代码:
        # return redirect('/classes/')
        url = reverse('class')
        return redirect(url)

分组的

(命名分组都一样,就是有没有?P<year>?P<month>, 这个还意味着传参方式的区别,命名分组是关键字传参)

命名

# app01中的urls
urlpatterns = [
    url(r'^blog/$', views.blog),
    url(r'^blog/(?P<year>[0-9]{4})/(?P<month>\d{2})/$', views.blog, name='blog'),
]

反向解析

模板中

<a href="{% url 'blog' 2019 10 %}">2019-10</a>    ==>    /blog/2019/10/
# 要提供相应的参数

# 下面是命名分组的关键字传参
<a href="{% url 'blog' month=10 year=2019 %}">2019-10</a>

py文件中

def blog(request,*args,**kwargs):
    print(reverse('blog',args=(2019,10)))

/blog/2019/10/

# 命名分组的关键字传参方式
print(reverse('blog',kwargs={'year':2019,'month':10}))
posted @ 2020-10-12 20:28  richard_A  阅读(103)  评论(0编辑  收藏  举报