路由相关操作

1. 路由系统

Django 1.11版本 URLConf官方文档

URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

2. URLconf配置

1. 基本格式

from django.conf.urls import url

urlpatterns = [
     # url() 是包含 请求的url和视图的对应关系的函数
     # def url(regex, view, kwargs=None, name=None):
     url(正则表达式, views视图,参数,别名),
]

9. 根据分组和方向解析合并删除

就是根据所学知识,将作者、书籍、出版社的删除函数由原来的3个函数写成1个函数

知识点:分组是说后端能捕获到url中括号中的内容

第一种方法

url(r'^all_del/(?P<pk>\d+)/(?P<sc>\w{0,20})/', views.all_del,name="all_del")
前端代码:
<a href="{% url 'all_del' pk=publish_obj.pk sc='publisher_list' %}">删除</a>
<a href="{% url 'all_del' pk=author_obj.pk sc='author_list' %}">删除</a>
<a href="{% url 'all_del' pk=book_obj.pk sc='book_list' %}">删除</a>
后端代码:
def all_del(request,**kwargs):

    pk = int(kwargs["pk"])
    sc = kwargs["sc"]
    # print(kwargs)
    # print(sc)
    # print(pk)
    ret = ""
    if sc == "publisher_list":
        ret = models.Publisher.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在1")

    elif sc == "book_list":
        ret = models.Book.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在2")

    elif sc == "author_list":
        ret = models.Author.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在3")
    ret.delete()
    return redirect(sc)  # 自动反向解析

第二种方法

url(r'^(publisher|book|author)_del/(\d+)/', views.delete,name="delete"),
# url(r'^(\w+)_del/(\d+)/', views.delete,name="delete"), # 效果相同
前端代码:
<a href="{% url 'delete' 'publisher' publish_obj.pk %}">删除</a>
<a href="{% url 'delete' 'author' author_obj.pk %}">删除</a>
<a href="{% url 'delete' 'book' book_obj.pk %}">删除</a>
# ****************************第三种也用上边代码*******************************
后端代码
def delete(request,name,pk,*args,**kwargs):
    # 后端能捕获到url括号中的内容
    print(name)
    print(pk)
    print(args)
    print(kwargs)

    # 字典形式*******************获取对象
    dic = {"book":models.Book,
           "publisher":models.Publisher,
           'author':models.Author}

    models_class = dic.get(name)
    ret = models_class.objects.filter(pk=pk)
    if not ret:
        return HttpResponse("输入有误,不存在")
    ret.delete()

    return redirect(name+"_list")

第三种方法

反射形式 models相当于一个模块,外部导入的
    "".capitalize()  # app01.models模块中的属性(类名)都是首字母大写的
    models_class = getattr(models,name.capitalize())
    ret = models_class.objects.filter(pk=pk)
    print(ret)

    if not ret:
        return HttpResponse("输入有误,不存在")
    ret.delete()

    return redirect(name+"_list")
    拼接成展示页面的路径,也可以修改展示的别名为name相同

2. 示例 django 1.x

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

3. 参数说明

# regex正则表达式 : 一个正则表达式字符串
# views视图: 一个可以调用的对象(最终执行的还是view函数), 或者是一个函数
# kwargs参数: 需要传给视图的参数.以字典形式传递
# name 别名 : 给当前的函数起一个名字, 用于做反向解析

4. django 2.x

from django.urls import path,re_path
# 2.0版本中re_path和1.11版本的url是一样的用法
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. 正则表达式详解

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/(\d+)/(\d{2})/$', views.month_archive),
    # (\d+) 至少一个数字,上不封顶,(\d{2})只能2个数字
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
# r"" 表示不转义
# ^XX 以XX开头  以...开头  注意没有/
# $XX 以XX结尾  以...结尾
# () 分组
# + 匹配1个或多个
    \ 下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。
#   \d+ 匹配一个或多个数字
#   \w+ 匹配数字字母下划线
#  [0-9] 0-9数字任意一个
#    [0-9a-zA-z] #大小写字母数字,任意一个.
#    {3} # 3个
#    {0,4} # 范围 0-4个

4. 补充说明

1. 访问时 404 DEBUG = True

DEBUG = True   # 访问路径不存在时报出提示信息404
ALLOWED_HOSTS = []
# DEBUG = False      访问不存在路径,Not Found,无其他提示信息
# ALLOWED_HOSTS = ["*"]

2. 访问路径最后没有 /

当访问的路径没有 / 时,我们也能正常访问,并且访问补全了/,那是因为做了重定向
先访问login  在重定向login/
访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。
APPEND_SLASH = True, 其作用就是自动在网址结尾加'/'。
如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。

5. 分组命名匹配

1. 有名分组和无名分组

from app01 import views
urlpatterns = [
	url(r'^index/',views.index)
	url(r'^index/(\d+)/(\d+)/',views.index),无名分组,分组数据以位置传参的方式给了视图函数
	url(r'^index/(?P<xx>\d+)/(?P<oo>\d+)/',views.index),有名分组,分组数据以关键字传参的方式给了视图函数,不在乎参数位置了,并且视图函数形参的名称要和又名分组的变量名称一样.
]
views.py
def index(request,n,m):       # 无名分组,位置传参
	return HttpResponse('xx')
def index(request,xx,oo):     # 有名分组,关键字传参
	return HttpResponse('xx')

2. 视图函数中指定默认值

# urls.py中
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),   # 没有传num也能访问
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]

# views.py中,可以为num指定默认值. 接收num不存在时,使用默认值
def page(request, num="1"):  
    pass

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

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

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),  # year 参数 始终是一个字符串

4. URLconf匹配的位置

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

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

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

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

5. 传递额外的参数给视图函数(了解)

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。
当传递额外参数的字典中的参数和URL中捕获值的命名关键字参数同名时,函数调用时将使用的是字典中的参数,而不是URL中捕获的参数。

6. 路由分发 include

多个App应用时,为了避免混淆修改错误问题,引入路由分发

1. 创建新应用

​ python manage.py startapp app02

2. 注册app02

3. include 路由分发

from django.conf.urls import url,include   # 引入include
from django.contrib import admin

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    #凡是以app01开头的去app01文件去找
    url(r'^app01/', include("app01.urls")),
    #凡是以app02开头的去app02文件去找
    url(r'^app02/', include("app02.urls")),
]
# 例如,访问 http://127.0.0.1:8000/app01/home/,我们先找到app01/,然后根据include去app01应用下查找路径home/匹配

4. app01下创建urls文件

from django.conf.urls import url
from app01 import views
urlpatterns = [
    url(r'^home/', views.home),]

app01下views文件代码

from django.shortcuts import render,HttpResponse
from django.urls import reverse
def home(request):
    print("app01>>>",reverse("home"))   # reverse解析时出错,命名空间解决,覆盖现象
    return HttpResponse("app01下的路径")

5. app02下创建urls文件

from django.conf.urls import url
from app02 import views
urlpatterns = [
    url(r'^home/', views.home),]

app02下views文件代码

from django.shortcuts import render,HttpResponse
from django.urls import reverse
def home(request):
    print("app02>>>", reverse("home")) # reverse解析时出错,命名空间解决,覆盖现象
    return HttpResponse("app02下的路径")

以上代码存在一个错误,就是不同应用命名同一个别名,反向解析结果都是后一个的路径,这就用到了命名空间解决问题

7. url 别名和反向解析

写法
	url(r'^index2/', views.index,name='index'),
反向解析
	后端: from django.urls import reverse
		 reverse('别名')  例如:reverse('index') -- /index2/
	html: {% url '别名' %} -- 例如:{% url 'index' %} -- /index2/

1. urls文件起别名

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    #url(r'^index/', views.index),    ---------------改名前
    #url(r'^login/', views.login),    ---------------改名前
    url(r'^index2/', views.index,name="index"),  ------改名后
    url(r'^login2/', views.login,name="login"),  ------改名后
]

2. views文件中改名方法

reverse("别名")-----路径

from django.shortcuts import render,redirect,HttpResponse
from django.urls import reverse   # 引入reverse方法

def index(request):
    return render(request,"index.html")

def login(request):
    if request.method == "GET":
        print(reverse("index"))
        print(reverse("login"))
        return render(request,"login.html")
    else:
        name = request.POST.get("username")
        pwd = request.POST.get("password")
        if name == "Alex" and pwd == "123":
            # return redirect("/index2/")---可以
            # return redirect("index")--用别名也可以,redirect方法源码做了反向解析了
            return redirect(reverse("index")) ---此处改变也可以
        else:
            return HttpResponse("用户名或密码错误!!")
            # return redirect("/login/")

3. html文件改名方法

{% url '别名' %} --- 改路径

    <h1>红浪漫spa会所</h1>
    <img src="/static/img/1.webp.jpg" alt="">
{#    <a href="/login2/">登录页</a>#}  --改名前路径
    <a href="{% url 'login' %}">登录页</a>   --改名后写法

8. 命名空间 namespace

上述代码解决方法

项目下urls文件添加 namespace属性

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    #凡是以app01开头的去app01文件去找
    url(r'^app01/', include("app01.urls",namespace="app01")),
    #凡是以app02开头的去app02文件去找
    url(r'^app02/', include("app02.urls",namespace="app02")),]

reverse("app01:home") reverse("app02:home")

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',namespace='app01')),
    url(r'^app02/', include('app02.urls',namespace='app02')),]
使用:
	后端:reverse('命名空间名称:别名') -- reverse('app01:home') 
	hmtl:{% url '命名空间名称:别名' %}  -- {% url 'app01:home' %}

9. 根据分组和方向解析合并删除

*args获取无名分组

**kwargs获取有名分组

就是根据所学知识,将作者、书籍、出版社的删除函数由原来的3个函数写成1个函数

知识点:分组是说后端能捕获到url中括号中的内容

第一种方法

url(r'^all_del/(?P<pk>\d+)/(?P<sc>\w{0,20})/', views.all_del,name="all_del")
前端代码:
<a href="{% url 'all_del' pk=publish_obj.pk sc='publisher_list' %}">删除</a>
<a href="{% url 'all_del' pk=author_obj.pk sc='author_list' %}">删除</a>
<a href="{% url 'all_del' pk=book_obj.pk sc='book_list' %}">删除</a>
后端代码:
def all_del(request,**kwargs):

    pk = int(kwargs["pk"])
    sc = kwargs["sc"]
    # print(kwargs)
    # print(sc)
    # print(pk)
    ret = ""
    if sc == "publisher_list":
        ret = models.Publisher.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在1")

    elif sc == "book_list":
        ret = models.Book.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在2")

    elif sc == "author_list":
        ret = models.Author.objects.filter(pk=pk)
        if not ret:
            return HttpResponse("数据不存在3")
    ret.delete()
    return redirect(sc)  # 自动反向解析

第二种方法

url(r'^(publisher|book|author)_del/(\d+)/', views.delete,name="delete"),
# url(r'^(\w+)_del/(\d+)/', views.delete,name="delete"), # 效果相同
前端代码:
<a href="{% url 'delete' 'publisher' publish_obj.pk %}">删除</a>
<a href="{% url 'delete' 'author' author_obj.pk %}">删除</a>
<a href="{% url 'delete' 'book' book_obj.pk %}">删除</a>
# ****************************第三种也用上边代码*******************************
后端代码
def delete(request,name,pk,*args,**kwargs):
    # 后端能捕获到url括号中的内容
    print(name)
    print(pk)
    print(args)
    print(kwargs)

    # 字典形式*******************获取对象
    dic = {"book":models.Book,
           "publisher":models.Publisher,
           'author':models.Author}

    models_class = dic.get(name)
    ret = models_class.objects.filter(pk=pk)
    if not ret:
        return HttpResponse("输入有误,不存在")
    ret.delete()

    return redirect(name+"_list")

第三种方法

反射形式 models相当于一个模块,外部导入的
    "".capitalize()  # app01.models模块中的属性(类名)都是首字母大写的
    models_class = getattr(models,name.capitalize())
    ret = models_class.objects.filter(pk=pk)
    print(ret)

    if not ret:
        return HttpResponse("输入有误,不存在")
    ret.delete()

    return redirect(name+"_list")
    拼接成展示页面的路径,也可以修改展示的别名为name相同
posted @ 2019-10-31 17:54  lvweihe  阅读(141)  评论(0编辑  收藏  举报