美文网首页
Django - urls与视图详解

Django - urls与视图详解

作者: 前端程序猿 | 来源:发表于2018-12-04 23:56 被阅读0次

    环境 Windows10

    一、准备工作

    • 使用 virtualenvwrapper 创建并进入虚拟环境

      mkvirtualenv myenv
      
    • 安装 Django2.0

      pip install django==2.0
      
    • 查看是否安装成功

      pip list
      
    • 创建一个名为 mysitedjango 项目

      django-admin startproject mysite
      
    • 进入虚拟环境所在目录

      cdvirtualenv
      
    • 打开当前目录

      start %cd%
      
    • mysite 目录拖到 pycharm 打开

    • 设置 pycharmpython 环境 具体设置: 点击查看

    二、项目结构分析

    • manange.py 项目的管理与交互都基于这个文件, 如启动项目:

      python manange.py runserver
      
    • __init__.py 表示这是一个 python 模块

    • setting.py 保存项目的所有配置信息

    • urls.py 编写路由与视图的映射规则

    • wsig.py 项目部署文件

    三、DEBUG 模式 与 ALLOWED_HOSTS

    • mysite/settings.py 中 默认是开启了 DEBUG 模式的

      DEBUG = True
      
    • DEBUG 模式的作用

      • 修改后自动重启项目
      • 详细的报错详细
    • 关闭了 DEBUG 模式,必须设置 ALLOWED_HOSTS, 否则项目起不来

      ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '192.168.0.108']
      
    • DEBUG 模式, 默认是以 IP 0.0.0.0 启动服务的, 但只要设置了 ALLOWED_HOSTS, 就只能通过ALLOWED_HOSTS 中的 IP 或 域名进行访问

    • 开发阶段,开启 DEBUG, 线上环境必须关闭 DEBUG 模式

    四、ROOT_URLCONF 设置 urls 匹配的入口文件

    ROOT_URLCONF = 'mysite.urls'
    

    五、初识视图函数

    • 视图函数的第一个参数永远是 HttpRequest 对象
    • 视图函数只能返回 HttpResponseBase的子类对象
      from django.http import HttpResponse
      
      
      def index(request):
          return HttpResponse('cms首页')
      

    六、urls 分层模块化

    • 每个独立的模块对应 Django 的一个 app

    • 创建两个 app : frontcms

      # 创建前台模块
      python manange.py startapp front
      
      # 创建后台cms模块
      python manange.py startapp cms
      
    • 编写 front/views.py

      # from django.shortcuts import render
      from django.http import HttpResponse
      
      # Create your views here.
      
      
      def index(request):
          return HttpResponse('前台首页')
      
      
    • 编写 cms/views.py

      # from django.shortcuts import render
      from django.http import HttpResponse
      
      # Create your views here.
      
      
      def index(request):
          return HttpResponse('cms首页')
      
      
    • 创建 front/urls.py

      from django.urls import path
      from . import views
      
      app_name = 'front'
      
      urlpatterns = [
          path('', views.index, name='index')
      ]
      
    • 创建 cms/urls.py

      from django.urls import path
      from . import views
      
      app_name = 'cms'
      
      urlpatterns = [
          path('', views.index, name='index')
      ]
      
    • 编写 mysite/urls.py

      from django.contrib import admin
      from django.urls import path, include
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('', include('front.urls')),
          path('cms/', include('cms.urls')),
      ]
      
    • 启动项目

      python manange.py runserver
      
    • 访问 front 应用: http://127.0.0.1:8000

    • 访问 cms 应用: http://127.0.0.1:8000/cms/

    七、url中的参数传递

    • 通过 path 传递

      • 编写视图函数 front/views.py

        def detail(request, article_id):
        return HttpResponse('当前文章id: %s' % article_id)
        
      • 编写urls front/urls.py

        path('detail/<article_id>', views.detail, name='detail'),
        
      • 访问方式: http://localhost:8000/detail/1

    • 通过 查询字符串 传递

      • 编写视图函数 front/views.py

        def article_list(request):
          author = request.GET.get('author')
          return HttpResponse('%s 相关的文章' % author)
        
      • 编写urls front/urls.py

        path('list/', views.article_list, name='list'),
        
      • 访问方式: http://localhost:8000/list/?author=%E6%9D%8E%E7%99%BD

    八、 内置的 path 转换器

    • int 类型:

      • 实现原理如下

        class IntConverter:
          regex = '[0-9]+'
        
          def to_python(self, value):
              return int(value)
        
          def to_url(self, value):
              return str(value)
        
      • 改写 front/urls.py

        path('detail/<int:article_id>', views.detail, name='detail'),
        
      • 改写 front/views.py

        def detail(request, article_id):
        print(type(article_id))
        return HttpResponse('当前文章id: %s' % article_id)
        
      • 访问: http://localhost:8000/detail/1

      • 控制台输出 <class 'int'>

    • str 类型, 默认不指定类型,就是 str 类型

      • 原理:
        class StringConverter:
        regex = '[^/]+'
        
        def to_python(self, value):
            return value
        
        def to_url(self, value):
            return value
        
        
    • uuid 类型,通用唯一识别码

      • 原理:

        class UUIDConverter:
        regex = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
        
        def to_python(self, value):
            return uuid.UUID(value)
        
        def to_url(self, value):
            return str(value)
        
      • 生成一个uuid 如: b8f12562-7006-4e21-9aeb-c3426d9dcbd3

        python
        
        import uuid
        
        uuid.uuid4()
        
      • 改写 front/urls.py

        path('detail/<uuid:article_id>', views.detail, name='detail'),
        
      • 访问: http://localhost:8000/detail/b8f12562-7006-4e21-9aeb-c3426d9dcbd3

    • slug 类型

      • 原理:
          regex = '[-a-zA-Z0-9_]+'
        
    • path 类型

      • 原理:
          regex = '.+'
        

    九、自定义 path 转换器

    这里,我们实现一个规则为: python+django+flask 的 url 参数, python 代码接收到的是通过 + 拆分后的列表, 转换器接收的参数也必须是一个列表; 比较抽象,还是看代码吧!

    • 创建 front/converters.py

      from django.urls import register_converter
      
      
      class CateConverter:
          regex = r'\w+|(\w+\+\w+)+'
      
          def to_python(self, value):
              return value.split('+')
      
          def to_url(self, value):
              if isinstance(value, list):
                  return '+'.join(value)
              else:
                  raise RuntimeError('分类参数必须为 list 类型')
      
      
      # 注册 path 转换器
      register_converter(CateConverter, 'cate')
      
    • 修改 front/__init__.py

        # 运行我们自定义的转换器
        from . import converters
      
    • 修改 front/urls.py

        path('category/<cate:category>/', views.index_category, name='category'),
      
    • 修改 front/views.py

      def index_category(request, category):
        pathname = reverse('front:category', kwargs={'category': category})
        return HttpResponse('分类列表为: %s, url 的 pathname 部分为: %s' % (category, pathname))
      
    • 访问: http://localhost:8000/category/python+django/, 浏览器显示如下:

      分类列表为: ['python', 'django'], url 的 pathname 部分为: /category/python+django/

    十、重定向 与 url 命名反转

    通过模拟 cms 后台登录进行讲解

    • 修改 cms/urls.py

        path('login/', views.login, name='login'),
      
    • 修改 cms/views.py

      # from django.shortcuts import render
      from django.http import HttpResponse
      from django.shortcuts import redirect, reverse
      
      # Create your views here.
      
      
      def index(request):
          username = request.GET.get('username')
          if username:
              return HttpResponse('cms首页')
          else:
              # 重定向登录页面
              return redirect(reverse('cms:login'))  # url 命名反转
      
      
      def login(request):
          return HttpResponse('登录页面')
      
      
    • 访问: http://localhost:8000/cms/ 会自动跳转到登录页面

    • 访问: http://localhost:8000/cms/?username=zhb33 才能访问 cms 后台首页

    • url 命名反转时的参数传递

      如果反转时,url 需要接收参数, 可通过关键字参数传递, 如果传递的查询字符串, 需要手动进行拼接

      • 修改 cms/urls.py
      path('login/<location>', views.login, name='login'),
      
      • 修改 cms/views.py
      def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('cms首页')
        else:
            # 重定向登录页面
            login_url = reverse('cms:login', kwargs={'location': '深圳'})  # url传参
            login_url += '?next=/'  # 查询字符串
            return redirect(login_url)  # url 命名反转
      
      
      def login(request, location):
          return HttpResponse('登录页面, 登录地点是 %s' % location)
      
      • http://localhost:8000/cms/ 跳转到 http://localhost:8000/cms/login/深圳?next=/

    十一、 urls的 应用命名空间 与 实例命名空间

    • 应用命名空间

      • 可以在每个应用的 urls.py 通过 app_name 进行设置 (一般使用这种方式设置)

        app_name = 'cms'
        
      • 也可以在 ROOT_URLCONF 指定的 urls.py 中使用 include 时进行设置(不常用)

        # mysite/urls.py
        path('cms/', include(('cms.urls', 'cms'))),  # 引入 cms 模块的 urls.py 并设置应用命名空间 为 cms
        
      • 作用: 如上面的 url 命名反转时 reverse('cms:login'), 可以防止与其它应用的 url 命名冲突

    • 实例命名空间

      • 在通过 include 引用时,进行设置

        # 设置实例命名空间
        path('cms/', include('cms.urls', namespace='cms')),
        
        # 同时设置 应用命名空间 和 实例命名空间
        path('cms/', include(('cms.urls', 'cms'), namespace='cms')),
        
      • 作用: 当多个不同 url 指向同一个应用时, 防止 url 冲突

        不使用实例命名空间的情况

        • 修改mysite/urls.py

          path('cms1/', include('cms.urls')),  # 不同的 url 指向同一个 应用
          path('cms2/', include('cms.urls')),
          
        • 访问 http://localhost:8000/cms1/ 跳转到 http://localhost:8000/cms1/login/深圳?next=/

        • 访问 http://localhost:8000/cms2/ 也跳转到 http://localhost:8000/cms1/login/深圳?next=/

        冲突了吧!

        使用实例命名空间

        • 修改mysite/urls.py

          path('cms1/', include('cms.urls', namespace='cms1')),
          path('cms2/', include('cms.urls', namespace='cms2')),
          
        • 修改mysite/views.py

          def index(request):
          username = request.GET.get('username')
          if username:
              return HttpResponse('cms首页')
          else:
              # 重定向登录页面
              current_namespace = request.resolver_match.namespace
              login_url = reverse('%s:login' % current_namespace, kwargs={'location': '深圳'})  # url传参
              login_url += '?next=/'  # 查询字符串
              return redirect(login_url)  # url 命名反转
          
        • 访问 http://localhost:8000/cms1/ 跳转到 http://localhost:8000/cms1/login/深圳?next=/

        • 访问 http://localhost:8000/cms2/ 跳转到 http://localhost:8000/cms2/login/深圳?next=/

    十二、 re_path 函数

    通过正则进行匹配参数

    匹配生日

    • 修改 front/urls.py

      from django.urls import path, re_path
      from . import views
      
      app_name = 'front'
      
      urlpatterns = [
          path('', views.index, name='index'),
          # ?P<birthday> 表示参数为 birthday 匹配 \d{4}-\d{2}-\d{2}
          re_path(r'^birthday/(?P<birthday>\d{4}-\d{2}-\d{2})/$', views.index_birthday, name='birthday')
      ]
      
    • 修改 front/views.py

      def index_birthday(request, birthday):
        return HttpResponse('生日快乐 %s' % birthday)
      
    • 访问: http://localhost:8000/birthday/1992-12-28/

    • 能用 path 解决的问题, 尽量不要用 re_path 因为 re_path 可读性差

    十三、默认参数

    要实现默认参数,需要两条 url 的配合

    • 修改 front/urls.py

      from django.urls import path, re_path
      from . import views
      
      app_name = 'front'
      
      urlpatterns = [
          path('', views.index_list, name='index'),
          path('list/<int:category_id>', views.index_list, name='list'),
      ]
      
    • 修改 front/views.py

      from django.http import HttpResponse
      
      
      category = ['python', 'django', 'flask']
      
      
      def index_list(request, category_id=0):
          return HttpResponse(category[category_id])
      
      
    • 访问: http://localhost:8000, 显示:
      python

    • 访问: http://localhost:8000/list/2, 显示:
      flask

    相关文章

      网友评论

          本文标题:Django - urls与视图详解

          本文链接:https://www.haomeiwen.com/subject/xzpbcqtx.html