小白学Django------------------路由控制URL

一.URL

1.Django中路由的作用

URL与要为该URL调用的视图函数之间的映射表,就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行.

from django.urls import path

urlpatterns = [
    path('test', views.test),
]
test,浏览器输入这个链接,就会响应到test这个函数来执行

2.简单的路由配置

from django.conf.urls import url

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
     url(r'^test/', views.test),
]
  • 正则表达式:一个正则表达式字符串
  • views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 参数:可选的要传递给视图函数的默认参数(字典形式)
  • 别名:一个可选的name参数
from django.urls import path,re_path

from app01 import views

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


注意:

1.若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
2.不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
3.每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
4.urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续
APPEND_SLASH
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True

Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。

如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求页面最后不加/就会提示找不到页面。

3.有名分组与无名分组

3.1有名分组

import re
ret = re.search("(?P<year>[0-9]{4})/([0-9]{2})",'2012/12')
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group('year'))

上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL中的值并以位置参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL中的值并以关键字参数传递给视图。

在Python 正则表达式中,命名正则表达式组的语法是**(?Ppattern)**,其中name 是组的名称,pattern 是要匹配的模式。

from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r'^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<day>[0-9]{2})/$', views.article_detail),
]
#捕获到的数据都是str类型
#视图函数里可以指定默认值

url('blog/$', views.blog),
url('blog/?(?P<num>[0-9]{1})', views.blog),
def blog(request,num=1):
    print(num)
    return HttpResponse('ok')

这里捕获的值作为关键字参数而不是位置参数传递给视图函数。

/articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')/articles/2003/03/03/ 请求将调用函数views.article_detail(request, year='2003', month='03', day='03')

这样写意味着URLconf会更加清晰也不容易产生参顺序错误的问题。

3.2无名分组

url(r'^admin/',views.urls)

1 第一个参数,可以写一个正则表达式
2 从上往下匹配,一旦匹配成功,就不往下走了
3 在正则表达式中,用()进行分组,分组出来的数据会当作参数传到视图函数中,所以分了几个组,视图函数中必须要有几个形参接受
4 在ssetting里设置:APPEND_SLASH =False,请求时,浏览器不会自动补全全斜杠,带上斜杠就匹配失败

伪静态,方便搜索引擎收录

	1.urls.py文件里面写:
		url(r'^delete_publish/(\d+).html', views.delete_publish)
		
	2.views.py里面写:
	def delete_publish(request,id):
        Publish.objects.filter(id=id).delete()
        return redirect('/publish_list/')
        
    3.template目录下的index.html里写:
    	<a href="/delete_publish/{{ publish.id }}.html">删除</a>

无名分组会把(\d+)匹配到的当作参数传给views的视图函数中,所以视图函数中一定要写用于接受的形参
注意:

有名分组和无名分组不要混用
有名分组可以用**kwargs接收,无名分组可以用*args接收

4.路由分发

1.在项目的urls里面写:
  from django.conf.urls import url,include
2.#主urls
  from django.urls import path,re_path,include
  from app01 import views
  from app01 import urls
  urlpatterns = [ 
    # re_path(r'^app01/',include('app01.urls')),
    #namespace是指定名称空间,下面会讲解到
    path('app01/',include('app01.urls',namespace='app01')), 
    # path('app01/', include(urls)),

  ]
  
3.在app01里创建一个urls
from django.urls import path,re_path
from app01 import views
urlpatterns = [
  re_path(r'^test/(?P<year>[0-9]{2})/$',views.url_test),
]

5.反向解析

1.路由中,命一个名, url(r'index/',views.index,name='n1'),

2.在视图函数里:
	from django.shortcuts import reverse
	#这样就能拿到我反向解析出来的url
	url = reverse('n1')
def test(request):
    url = reverse('n1')
    # return render(request,'test.html')
    # return redirect('/index/')
    return redirect(url)

def index(request):
    return HttpResponse('欢迎来到首页')
3.在模板里:
	<a href="{% url 'n1' %}">点我跳转首页</a>
    
4.带位置参数反向解析
	urls: url(r'index/([0-9]{4})/([0-9]{1,2})',views.index,name='n1')
	视图:url = reverse('n1',args=(2012,12))
	模板:<a href="{% url 'n1' 2012 12 %}">点我跳转首页</a>
        
5.带关键字参数反向解析
	urls: url(r'index/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})',views.index,name='n1')
	视图:url = reverse('n1',args=(2012,12))
		url = reverse('n1',kwargs={'year':2012,'month':12})
	模板:<a href="{% url 'n1' year=2012 month=12 %}">点我跳转首页</a>:按位置传,顺序是固定的
    
 总结:修改路由中url的时候,其它地方不需要改动

5.名称空间(建议不同app的url里name不要重名,可以用app_名字)

.url(r'app01/',include('app01.urls',namespace='app01')),
 2.	urlpatterns = [
    	url(r'^test1/',views.test1,name='test')
]
 3.视图函数里:
        def test1(request):
            url = reverse('app01:test')
            print('-----app01------',url)
            return HttpResponse('我是app01')
4.模板里:
    <a href="{% url 'app01:test' %}">点我跳转首页</a>
=================================================================.url(r'app02/',include('app02.urls',namespace='app02')),
2. 	urlpatterns = [
    	url(r'^test2/',views.test2,name='test')
]
3.视图函数里:
         def test2(request):
            url = reverse('app02:test')
            print(url)
            return HttpResponse('我是app02的test2')
4.模板里:
    <a href="{% url 'app02:test' %}">点我跳转首页</a>

7.django2.0的path

1.from django.urls import path
2.不支持正则,精准匹配
3.5个转换器,int,str,slug,path,uuid
4.自定义转换器:
	1.先写一个类
	class Test:  # 转换器
    # regex这个变量名不能变,=右边是个正则表达式
    regex = '[0-9]{4}'
    def to_python(self, value):  # 给视图函数用的
        # 写一些逻辑处理
        return int(value)
    def to_url(self, value):
        return '%04d' % value
    2.from django.urls import register_converter
    3.自定义转换器
		register_converter(Test,'yyy')
	4. path(r'index/<yyy:year>', views.index),
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

8.MTV架构与MVC架构

MTV与MVC执行流程是一样的,干的事情也是一样的
MTV:
	M:models
	T:template			模板
	V:views(视图函数) 	 逻辑的处理
MVC:
	M:models
	V(模板):views(对应的模板)
	C(控制器):controler(路由+views)
视图层:request对象
form表单,不写method,默认是get请求
         1.什么情况下用get:请求数据,请求页面
         2.用post请求:向服务器提交数据
     request.GET ==><QueryDict: {'name': ['tom'], 'pwd': ['123']}>
     request.POST ==><QueryDict: {'name': ['tom'], 'pwd': ['123']}>
     request.method 请求类型

     路径
     http://127.0.0.1:8000/index/ppp/?name=tom
     协议:IP地址和端口/路径?参数(数据)
     print(request.path)==>/index/ppp/
     print(request.get_full_path())==>/index/ppp/?name=tom
     print(request.body) ==>就是body体内的东西

猜你喜欢

转载自blog.csdn.net/qq_42721964/article/details/83825807