Django之URL路由系统

Django下载安装

(day54)

下载Django

pip3 install django== 1.11.9  版本号

创建Django项目

django-admin startproject mysite

创建app

python manage.py startapp xiaoqing

创建的项目文件

manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库,启动关闭项目与项目交互
    等,不管你将框架分了几个文件,必然有一个启动文件,其实他们本身就是一个文件。
settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
urls.py ----- 负责把URL模式映射到应用程序。
wsgi.py ---- runserver命令就使用wsgiref模块做简单的web server,后面会看到renserver命令,所有与
socket相关的内容都在这个文件里面了,目前不需要关注它。

运行项目

python manage.py runserver 127.0.0.1:8080 #此时已经可以启动django项目了,只不过什么逻辑也没有
通过指令运行项目的时候,可以不写ip地址,如果不写,默认是127.0.0.1
    python manage.py runserver 8080
如果连端口都不写,默认是8000端口
    python manage.py runserver

需要在项目的配置文件settings.py中添加一个app的配置

INSTALL_APPS = [
	
	'xiaoqing', app名称
]

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 以下两种写法都可以
    'app01.apps.App01Config',
    #'app01',
]

基于Django简单示例

1 创建项目 first_pro

2 创建app app01
做一个登录页面的web项目,浏览器输入一个网址得到一个web页面

用户: http:127.0.0.1:8001/login/
1 urls.py
        from django.conf.urls import url
        from django.contrib import admin
        from app01 import views
        urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        	url(r'^index/', views.index), #配置路径,r'^/index/',这个前置导航斜杠不需要添加.
        ]
        
2 写逻辑视图
  from django.shortcuts import render,HttpResponse
  # Create your views here.
    def index(request):
    		print(request.method) #'POST' 'GET'
    		if request.method == 'GET':
    				return render(request,'login.html')
    		else:
            # print(request.GET)
            print(request.POST)
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'dazhuang' and password == '123':
            return HttpResponse('登录成功!')
            else:
            return HttpResponse('登录失败!')
3 创建html文件
在templates文件夹中创建一个login.html文件
<!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
      <title>Bootstrap 101 Template</title>
      <!-- Bootstrap -->
    </head>
    <body>
        <h1>欢迎来到登录页面</h1>
        <form action="/index/" method="post">
        用户名:<input type="text" name="username">
        密码:<input type="text" name="password">
        <input type="submit">
        </form>
    </body>
</html>

urls.py里面需要注意的问题
		url(r'^index/', views.index), 第一个参数:路径正则字符串 第二个参数:对应的视图函数
views.py
		def login(request):
      获取请求方法,request.method--'GET','POST'
      request.GET -- GET请求发送来的所有数据,queryDict类型
      request.POST -- POST请求发送来的所有数据,queryDict类型
         <input name='username'>
         request.POST.get('username')
         request.GET.get('username')
      return HttpResponse('字符串') --- 回复字符串数据
      retuen render(request,'login.html')

get请求获取数据

def index(request):
    print(request.GET) #<QueryDict: {'username': ['dazhuang'], 'password': ['123']}>
    username = request.GET.get('username')
    password = request.GET.get('password')
    print(username,password)
    
    if username == 'dazhuang' and password == '123':
    		return HttpResponse('登录成功!')
    else:
    		return HttpResponse('失败!')

post请求提交数据时关掉一个认证机制,settings配置文件中

MIDDLEWARE = [
  'django.middleware.security.SecurityMiddleware',
  'django.contrib.sessions.middleware.SessionMiddleware',
  'django.middleware.common.CommonMiddleware',
  #'django.middleware.csrf.CsrfViewMiddleware',
  'django.contrib.auth.middleware.AuthenticationMiddleware',
  'django.contrib.messages.middleware.MessageMiddleware',
  'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

URL配置

​ URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

基本格式(1.11版本)

from django.conf.urls import url
#循环urlpatterns,找到对应的函数执行,匹配上一个路径就找到对应的函数执行,就不再往下循环了,并给函数传一个参数request,和wsgiref的environ类似,就是请求信息的所有内容
urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]

(2.0版本)

from django.urls import path

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),
]

参数说明:

  • 正则表达式:一个正则表达式字符串
  • views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 参数:可选的要传递给视图函数的默认参数(字典形式)
  • 别名:一个可选的name参数

正则表达式详解

基本配置

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003), #思考:如果用户想看2004、2005、2006....等,你要写一堆的url吗,是不是在articles后面写一个正则表达式/d{4}/就行啦,网址里面输入127.0.0.1:8000/articles/1999/试一下看看
    url(r'^articles/([0-9]{4})/$', views.year_archive), 
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #思考,如果你想拿到用户输入的什么年份,并通过这个年份去数据库里面匹配对应年份的文章,你怎么办?怎么获取用户输入的年份啊,分组/(\d{4})/,一个小括号搞定
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

views.py中视图函数的写法:

第一个参数必须是request,后面跟的三个参数是对应着上面分组正则匹配的每个参数的
def article_detail(request,year,month,day):
    return HttpResponse(year+month+day)

注意事项

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

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

# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True
from django.conf.urls import url
from app01 import views

urlpatterns = [
        url(r'^blog/$', views.blog),
]

分组命名匹配

使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。

  在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

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

无名分组

    url(r'^books/(\d{4})/', views.books),

有名分组

		url(r'^books/(?P<year>\d{4})/(?P<month>\d{1,2})/', views.year_month_books), #匹配年份和月份的
		def year_month_books(request,month,year): #形参名称要和url中的分组名对应好,参数位置就没有要求了
                print(year,month)

                 # return render(request,'books.html')
                 return HttpResponse(year+month)


下面是URLconf 使用命名组的重写:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003), #注意正则匹配出来的内容是字符串,即便是你在url里面写的是2003数字,匹配出来之后也是字符串

  url(r'^articles/(\d{4})/$', views.year_archive),#year_archive(request,n),小括号为分组,有分组,那么这个分组得到的用户输入的内容,就会作为对应函数的位置参数传进去,别忘了形参要写两个了。
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),#某年的,(?P<year>[0-9]{4})这是命名参数,那么函数year_archive(request,year),形参名称必须是year这个名字。而且注意如果你这个正则后面没有写$符号,即便是输入了月份路径,也会被它拦截下拉,因为它的正则也能匹配上
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),#某年某月的
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), #某年某月某日的
]

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。

  例如,针对url /articles/2017/12/相当于按以下方式调用视图函数:

views.month_archive(request, year="2017", month="12"),year和month的位置可以换,因为是按照名字来取数据的,关键字参数

位置参数

    url(r'^books/(\d{4})/', views.year_books), #匹配年份的
    url(r'^books/(\d{4})/(\d{1,2})/', views.year_month_books), #匹配年份和月份的
# http://127.0.0.1:8000/books/2001/
		视图:
	     def year_month_books(request,year,month): #位置参数,第一个参数接收的就是无名分组路径中匹配到的第一个分组的数据,第二个参数接收的就是无名分组路径中匹配到的第二个分组的数据
              print(year,month)
              # return render(request,'books.html')
              return HttpResponse(year+month)

在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

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'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
传递到视图函数`views.year_archive()` 中的`year` 参数永远是一个字符串类型。

默认值

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

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]

# views.py中,可以为num指定默认值
def page(request, num="1"):
    pass

视图函数中指定默认值

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

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]

# views.py中,可以为num指定默认值
def page(request, num="1"):
    pass

在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

url路由分发之include

项目文件夹下的urls.py文件中的url写法:
    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'^$', views.base),

        url(r'^app01/', include('app01.urls')),

        url(r'^app02/', include('app02.urls')),

    ]
    
app01下urls.py内容写法
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^$', views.app01base),
        url(r'^index/', views.index),
    ]
    
app02下urls.py内容写法   
    from django.conf.urls import url
    from django.contrib import admin
    from app02 import views

    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^$', views.app02base),
        url(r'^home/', views.home),

    ]

命名URL(别名)和URL的反向解析

Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

  • 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
  • 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

  第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。
  在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url模板标签。
  • 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
  • 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

  上面说了一大堆,你可能并没有看懂。(那是官方文档的生硬翻译)。

  咱们简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。

  这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。

url(r'^home', views.home, name='home'),  # 给我的url匹配模式起名(别名)为 home,别名不需要改,路径你就可以随便改了,别的地方使用这个路径,就用别名来搞
url(r'^index/(\d*)', views.index, name='index'),  # 给我的url匹配模式起名为index

在模版里还可以这样引用

{% url 'home' %}  #模板渲染的时候,被django解析成了这个名字对应的那个url,这个过程叫做反向解析

在views函数中可以这样引用:

from django.urls import reverse

reverse("index", args=("2018", ))
    #添加书籍
    url(r'^add_book/', views.add_book,name='abook'), #name='abook'  别名

    # 删除书籍
    url(r'^delete_book/(\d+)/', views.delele_book,name='delete_book'),

视图:
	from django.urls import reverse
	reverse('别名')  reverse('abook') -- /add_book/  #不带参数的
	print(reverse('delete_book',args=(71,))) #/delete_book/71/ 带参数的
模板
	{% url 'abook' %}  无参数的
	{% url 'delete_book' book.id %}  有参数的


posted @ 2019-07-22 18:51  七个小矮人  阅读(217)  评论(0编辑  收藏  举报