• Django基础-url控制器


    MTV模型

    • Model: 和数据库相关, 负责业务对象和数据库对象(ORM)
    • Template: 放所有的html文件, 通过模板语法将数据库当中的数据渲染到页面中, 以便在前端页面展示
    • View: 负责业务逻辑, 并在适当的时候调用ModelTemplate

    此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

    Django基础命令

    1. 下载Django

    pip install django==2.0.1  # 本文使用的django版本为2.0.1
    

    2. 创建一个Django project

    django-admin.py startproject mysite
    

    会生成如下目录结构

    • manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
    • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
    • urls.py ----- 负责把URL模式映射到应用程序。

    3. 进入project目录创建一个应用

    python3 manage.py startapp blog(应用名称)
    

    4. 启动Django项目

    python3 manage.py runserver  8080
    

    5. 配置静态文件目录

    修改项目的settings.py, 加入STATICFILES_DIRS部分的代码

    STATIC_URL = '/static/'               # 静态文件路径别名, django对引用名和实际名进行映射,引用时,只能按照引用名来,                                       # 不能按实际名去找
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'statics')  # statics为实际目录, 这个目录的名字可以自定义
    ]
    

    路由控制和分发(include)

    项目全局urls.py文件

    from django.urls import path,re_path,include    # re_path通过正则匹配路径, include可以把请求分发到不同的app下的                                                 # url分发器
    from app01 import views                         # 导入应用app01的视图文件
    
    urlpatterns = [
        # path('admin/', admin.site.urls),
        # path('timer/', views.timer),
        # 路径(timer/)----------->视图函数(views.timer)
        re_path(r'^articles/([0-9]{4})',views.articles), # 会给articles这个视图传入request和([0-9]{4})两个参数, 所                                                      # 以articles这个视图需要接收两个参数
        path('login/', views.login),
        re_path(r'^',include('app01.urls'))
    ]
    
    # 1 一旦匹配成功则不再继续
    # 2 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
    # 3 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
    # 4 每个正则表达式前面的'r' 是可选的但是建议加上。
    

    app01下的urls, 由上一段代码的include分发到这里

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    urlpatterns = [
        re_path(r'^articles/([0-9]{4})',views.articles)
    ]
    

    有名分组

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

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

    from django.contrib import admin
    from django.urls import path,re_path,include
    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),
    ]
    

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

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

    在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序

    反向解析

    在使用Django项目时, 一个常见的需求是获取url的最终形势, 以嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。

    如果通过硬编码写死到代码中会产生很多问题, 影响代码的扩展性

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="{% url 'Log' %}" method="post">
        name: <input type="text" name="user">
        pass: <input type="password" name="pwd">
        <input type="submit">
    </form>
    </body>
    </html>
    
    # urls.py
    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    
    urlpatterns = [
        path('login.html/', views.login, name='Log')
    ]
    

    urlpatterns中给path起一个别名name='Log', 然后在html文件中引用<form action="{% url 'Log' %}" method="post">

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    
    # Create your views here.
    def timer(request):
        import time
        ctime=time.time()
        url=reverse('Log')
        print(url)
        return render(request,"timer.html",{'ctime':ctime})
    

    在django中需要引入reverse方法来实现反向解析

    如果urls.py中的路径是带有正则表达式的, 则reverse的时候就要给一个参数, 只要这个参数符合正则表达式的匹配规则即可

    # urls.py
    
    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    urlpatterns = [
        re_path(r'^articles/([0-9]{4})',views.articles,name='articles_reverse')
    ]
    
    # views.py
    
    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    
    # Create your views here.
    def timer(request):
        import time
        ctime=time.time()
        url=reverse('articles_reverse',args=(1111,))         # 给出一个四位数字的元组即可
        print(url)
        return render(request,"timer.html",{'ctime':ctime})
    

    名称空间(namespace)

    命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

    由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回

    我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

    没有定义namespace的情况

    项目urls.py分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    from app02 import views
    
    urlpatterns = [
        re_path(r'^app01/', include('app01.urls')),
        re_path(r'^app02/', include('app02.urls')),
    ]
    

    app01的urls.py分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    urlpatterns = [
        re_path(r'^index/', views.index,name="index"),
    ]
    

    app02的urls分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app02 import views
    urlpatterns = [
        re_path(r'^index/', views.index,name="index"),
    ]
    

    app01的views.py

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    def index(request):
        return  HttpResponse(reverse("index"))
    

    app02的views.py

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    def index(request):
        return  HttpResponse(reverse("index"))
    

    按照以上配置, 没有namespace的情况下, 在两个app同时定义了index这个访问路径, django就没有办法区分用户要访问的是那个index了, 所以他只能按照优先顺序, 返回第一个匹配到的index, 在这里访问以下链接得到的结果都是/app02/index/

    定义namespace的情况

    项目urls.py分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    from app02 import views
    
    urlpatterns = [
        re_path(r'^app01/', include(("app01.urls","app01"))),    #("app01.urls","app01") 这是一个元组
        re_path(r'^app02/', include(("app02.urls","app02"))),
    ]
    

    app01的urls.py分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app01 import views
    urlpatterns = [
        re_path(r'^index/', views.index,name="index"),
    ]
    

    app02的urls分发器

    from django.contrib import admin
    from django.urls import path,re_path,include
    from app02 import views
    urlpatterns = [
        re_path(r'^index/', views.index,name="index"),
    ]
    

    app01的views.py

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    def index(request):
        return  HttpResponse(reverse("app01:index"))
    

    app02的views.py

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    def index(request):
        return  HttpResponse(reverse("app02:index"))
    

    按照以上配置, 定义了namespace的情况下, 在两个app同时定义了index这个访问路径, django就可以通过namespace区分用户要访问的是那个index了, 在这里访问以下链接得到的结果分别是/app01/index//app02/index/

    path方法

    path转换器

    如下代码, 所有传入视图的参数默认均为字符串类型, 如果我们需要处理的数据不是字符串类型, 我们就要在视图函数中自行处理, 比如第一个year, 如果视图函数中需要的类型是整形, 我们就要在视图函数中做一个类型转换year=int('year'), 那么有没有一种方法,在url中,使得这一转化步骤可以由Django自动完成?

    urlpatterns = [  
        re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
        re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
        re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
        re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
    ]
    

    通过使用path转换器可以解决上述问题, 代码如下

    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>/', views.article_detail),  
    ]  
    

    基本规则

    • 使用尖括号(<>)从url中捕获值。
    • 捕获值中可以包含一个转化器类型(converter type),比如使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
    • 无需添加前导斜杠。

    自定义path转换器

    对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:

    • regex 类属性,字符串类型

    • to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。

    • to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。

    示例

    自定义转换器urlconvert.py, 转换器名字自定义, 代码中的regex, to_python, to_url为固定写法

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    class MonConvert:
        regex='[0-9]{2}'
        def to_python(self,value):
            return int(value)
        def to_url(self,value):
            return '%04d' %value
    

    通过register_converter模块注册我们自定义的转换器MonConvert

    from django.urls import path,re_path,include,register_converter
    from app01 import views
    from app02 import views
    from app01.urlconvert import MonConvert
    
    register_converter(MonConvert,'mm')  # mm为我们给自定义转换器起的别名
    
    urlpatterns = [
    	path('articles/<mm:mon>',views.articles),
    ]
    

    view.articles代码

    from django.shortcuts import render,HttpResponse
    from django.urls import reverse
    def articles(request,mon):
        return HttpResponse(mon)
    

    当我们在浏览器输入127.0.0.1:8000/articles/22, 就会在web页面返回22了, 并且代码中获得的mon的字符类型为int类型

  • 相关阅读:
    Hyperledger Fabric的容灾备份及恢复方法
    Sentinel使用
    Fabric1.4 架构和原理
    centos开放指定端口
    Python使用ProtoBuffer
    C++动态创建对象
    Shell笔记
    Go语言基础(二)
    Go语言基础(一)
    git常用命令
  • 原文地址:https://www.cnblogs.com/peitianwang/p/14247818.html
Copyright © 2020-2023  润新知