linRichielinRichie
前端
Python
Linux
ChatGPT
  • B 站
  • 500px
前端
Python
Linux
ChatGPT
  • B 站
  • 500px
    • Python学习指南
  • 快速开始

    • Python: 输入与输出 (I/O)
    • Python: 异常处理 try-except
    • Python: List深入概述
    • Python: 面向对象编程(OOP)
  • Python 语法库函数

    • 语法库目录
    • 库

      • library目录
      • argparse:解析命令行参数
      • difflib:比较序列并生成差异信息
      • dnspython: DNS处理库
      • IPy:IP地址处理库
      • logging:记录和管理日志信息
      • os:访问和操作操作系统
      • psutil:系统性能信息库
      • re:正则表达式库
      • smtplib:邮件发送库
    • 函数

      • function目录
      • any() 函数
      • input 函数
      • lambda 和 map 函数
      • reversed()函数
      • zip()函数
    • 语句

      • statement目录
      • import 语句
      • Try/Exception 异常
    • 概念

      • concept目录
      • 深拷贝与浅拷贝
      • 列表、字典与元组
      • 文件读写
      • IO: 输入与输出
      • 逻辑判断与条件语句
      • OOP 面向对象:class
      • OOP: 面向对象编程
  • SQLAlchemy

    • 获取insert或者update的id
  • Pandas

    • Pandas目录
    • Pandas:基础操作
    • Pandas:数据处理与转换
    • Pandas: 数据写入 excel 表格
  • Python前端框架

    • Flask

      • 1. Flask简介
      • 2. Flask程序基本结构
      • 3. Flask请求-响应循环
      • 4. flask案例: 框架网页查询IP
      • Python: Flask中的GitHub OAuth
    • Django

      • chapter-01:Django框架认识

        • 1.1 Django的产生背景
        • 1.2 MTV设计模式
        • 1.3 Django 主要功能模块
      • chapter-02:开发环境配置

        • 2.1 Python的安装与配置
        • 2.2 虚拟环境安装与配置
        • 2.3 Django安装与配置
        • 2.4 MySQL安装配置
      • chapter-03:项目框架搭建

        • 3.1 Django管理工具-创建项目骨架
        • 3.2 修改项目的默认配置
        • 3.3 初始化项目环境
      • chapter-04:ORM应用与原理剖析

        • 4.1 构建POST应用需要的数据集
        • 4.2 Model相关的概念和使用方法
        • 4.3 Model的查询操作API
        • 4.4 ORM实现原理
      • chapter-05:Django管理后台

        • 5.1 将Model注册到管理后台
        • 5.2 管理后台实现原理
      • chapter-06:视图

        • 6.1 视图基础
        • 6.2 视图的高级特性和快捷方法
        • 6.3 基于类的通用视图
      • chapter-07:模板系统

        • 7.1 模板系统基础
        • 7.2 模板语言
      • chapter-08:表单系统

        • 8.2 使用表单系统实现表单: ModelForm
      • chapter-09:用户认证系统

        • 9.1 用户与身份认证
        • 9.2 权限管理
        • 9.3 用户认证系统应用
      • chapter-10:Django路由系统

        • 10.1 路由系统基础
      • chapter-11:Django中间件

        • 11.1 中间件基础
  • Python例子

    • Python: Linux的Shell命令
    • Python: PEP8自动格式化代码
    • Python: pip操作
    • Python: 业务服务监控
    • Python: 从文件逐行读取数据
    • 将链表转换为字符串
    • Python: 检查URL是否能正常访问
    • Python: 爬取网易云音乐
    • Python: 读取目录下的所有内容
    • 案例研究:文本统计
  • Python爬虫

    • 数据解析工具:Xpath
  • 算法题

    • 02:两数相加
    • 09:回文数
    • 13:罗马数值转换为整数
    • 14:最长公共前缀

6.1 视图基础

  • 6.1 视图基础
    • 6.1.1 理解url.py文件的注释
      • 总结
    • 6.1.2 视图的请求与相应对象
      • HttpRequest
      • HttpResponse
    • 6.1.3 基于类的视图
      • 简单的类视图定义
        • 具体代码
      • 设置类属性
      • 利用Mixin实现代码复用
        • 总结
    • 6.1.4 动态路由
      • 使用path配置动态路由
      • 自定义转换器
      • 带默认参数的视图
      • 正则表达式
    • 6.1.5 给post应用添加视图
      • 实现Topic列表视图
      • 实现Topic实例对象信息视图
      • 给Topic实例对象添加评论的视图

  • 一般视图都会放在view.py文件中
  • 简单的例子
from django.http import HttpResponse
def hello_django_bbs(request):
    html = '<h1>hello django</h1>'
    return HttpResponse(html)
- 引用HttpResponse,作为视图的返回类型
- 视图函数声明,当前的函数名为hello_django_bbs,仅仅描述自身的用途
- 视图函数的第一个参数:是HttpRequest类型的对象,通常定义为request,Django没有要求,约定俗成
- 函数内部定义业务处理逻辑
- 视图最后返回一个HttpResponse对象,标记一次Web请求的结束

在管理后台进行映射(my_bbs/my_bbs/urls.py)文件中配置URL到视图的映射

from django.contrib import admin
from django.urls import path
from post import views   # 导入post的views视图函数

urlpatterns = [
    path('admin/', admin.site.urls),
    path('post/hello/',views.hello_django_bbs) # 注册post应用的视图函数
]   

hello_django_bbs

6.1.1 理解url.py文件的注释

my_bbs URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views  # 针对基于函数的视图
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views  # 针对基于类的视图
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf  # 针对项目中存在多APP的场景
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
  • 针对基于函数的视图

    • 需要先将视图定义文件引入:import
    • 利用path定义URL和视图的关系
      • path函数传递两个参数,第一个参数定义URL的匹配规则,第二个参数定义映射的视图函数,都是必填项
  • 针对基于类的视图

    • 需要现将类对象引入
    • 使用类似方法配置URL和视图类的关系
    from other_app.views import Home
    path('',Home.as_view(), name='home')
    
  • 针对项目中存在多App的场景

    • 利用include实现App与项目的解耦
    • include将App的URL配置文件导入,就可以实现根据不同的App来分发请求,以实现每个App自己管理自己的视图与URL映射
    from django.urls import include, path
    path('blog/', include('blog.urls'))
    
  • 上面的URL映射就可以改为

    # my_bbs/post/urls.py
    from django.urls import path
    from post import views
    
    urlpatterns = [
        path('hello/',views.hello_django_bbs) # 注册post应用的视图函数
    ]   
    
    # my_bbs/my_bbs/urls.py
    """my_bbs URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/4.0/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import include, path
    
    urlpatterns = [
        path('post/',include('post.urls'))
    ]
    

得到的结果 hello_django_bbs

总结

在多应用App的项目中,在每个App下面创建urls.py文件,然后通过include注册到整个项目中,方便管理,而且结构清晰,便于维护

6.1.2 视图的请求与相应对象

  • 请求与返回涉及两个对象
    • HttpRequest:请求对象
    • HttpResponse:相应对象

HttpRequest

  • 此对象定义域:django/http/request.py文件中
  • 请求的时候,Django会创建一个携带有请求元数据的HttpRequest对象,传递给视图函数的第一个参数
  • 视图函数的处理逻辑:根据携带的元数据作出相应的动作
  • 定义的属性
    • method:字符串类型的值,标识请求所使用的HTTP方法,如GET,POST,PUT等
      • 对于同一个URL,不管使用的是GET还是POST都会路由到同一个视图函数去处理
      • 装饰器:@csrf_exempt:POST方法和GET方法会获取相同的响应
      • 指定请求方法需要使用:@require_http_methods装饰器指定视图可以接受的方法
      • 简化:提供了几个简单的装饰器指定可以接受的请求方法
        • require_GET或require_POST等
    • scheme:被@property装饰的方法,返回字符串类型的值
      • 可以被当做属性直接调用:request.scheme。标识请求的协议类型(http/https)
    • path:字符串类型,返回当前请求页面的路径,但不包括协议类型或域名
    • GET:类字典对象,包括GET请求的所有参数,GET属性中的键和值都是字符串类型
      • 获取参数的方法有两种
        • request.GET['a']
        • request.GET.get('b',0)
      • GET的属性不是Python的字典类型,实际上是一个QuerySet(django.http.QueryDict)类型的实例,且是只读的,修改此数据,需要通过copy方法获取副本并在副本上进行修改
    • POST:与GET类型

      在POST方法上传文件时,文件相关的信息不会保存在POST中,而是保存在FILES属性中

    • FILES
    • META
    • user

具体介绍查看文档:https://weread.qq.com/web/reader/6e4329007193f1e66e43129k341323f021e34173cb3824c

HttpResponse

具体介绍查看文档:https://weread.qq.com/web/reader/6e4329007193f1e66e43129k341323f021e34173cb3824c

  • 常用的HttpResponse子类对象
    • JsonResponse
    • HttpResponseRedirect
    • HttpResponseNotFound

6.1.3 基于类的视图

  • 类视图的特点:可以利用不同的实例方法相应不同的HTTP请求方法(GET,POST)
  • 可以利用面向对象的技术将代码分解为可重用的组件

简单的类视图定义

from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

class FirstView(View):
    html = '(%s) Hello Django BBS'
    
    def get(self, request):
        return HttpResponse(self.html % 'GET')
    def post(self, request):
        return HttpResponse(self.html % 'POST')
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(FirstView, self).dispatch(request, *args, **kwargs)
  • FirstView 继承自 View,它是所有基于类视图的基类(View)

  • FirstView 定义了get和post方法

  • 并且重写了父类的dispatch方法,dispatch根据HTTP类型实现请求分发:

    • 如果是GET请求,分发给get
    • 如果是POST请求,分发给post
  • 如果View中没有实现对应请求类型的方法,则会返回 HttpResponseNotAllowed

  • 类对象中定义的方法与普通的函数并不相同,所以,应用于函数的装饰器不能直接应用到类方法上,需要将它转换为类方法的装饰器。

    • 在dispatch方法上添加了@method_decorator
    • 此装饰器可以将函数装饰器转换为类方法装饰器, csrf_exempt装饰器可以被用在类方法上
  • 基于类的视图,在urls.py中定义路由和视图的时候,需要用到View提供的as_view()方法完成URL的定义

具体代码

# my_bbs/post/views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

class FirstView(View):
    html = '(%s) Hello Django BBS'
    
    def get(self, request):
        return HttpResponse(self.html % 'GET')
    def post(self, request):
        return HttpResponse(self.html % 'POST')
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(FirstView, self).dispatch(request, *args, **kwargs)
# my_bbs/post/urls.py

from django.urls import path
from post.views import FirstView

urlpatterns = [
    path('hello/',FirstView.as_view()) # 注册post应用的视图函数
]   
# my_bbs/my_bbs/urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/',admin.site.urls),
    path('post/',include('post.urls'))   # 基于不同APP的urls
]  

结果基于类的视图-简单案例

设置类属性

  • FirstView中定义了一个类属性:html
    • 常用的设计:将公用的部分放在类属性中,所有的方法都能看到

要修改类的属性由两种办法

  • 使用Python语言的特性,实现子类并覆盖父类中的属性
class SecondsView(FirstView):
  html = "Seconds ...."
  • 直接在配置URL的时候在as_view方法中指定类属性,简单直接
    • as_view中设置的类属性只在URL第一次导入时设置
path('second_hello_class/', FirstView.as_view(html="Seconds: (%s) Hello Django Seconds"))

利用Mixin实现代码复用

  • Mixin就是一个Python对象,但这个类不一定需要明确的语义,主要目的:实现代码的复用
  • 一个视图类可以继承多个Mixin,但只能继承一个View,写法上通常会把Mixin写在View的前面
  • 例子:将FirstView中重写的dispatch方法放到Mixin里,并加入计时装饰器
# post/views.py
import time
def exec_time(func):
  def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        print('%ss elapsed for %s' %(time.time() - start, func.__name__))
        return res
    return wrapper

class ExecTimeMixin(object):
  @method_decorator(csrf_exempt)
  @method_decorator(exec_time)

  def dispatch(self, request, *args, **kwargs):
    return super(ExecTimeMixin, self).dispatch(request, *args, **kwargs)

class FirstView(ExecTimeMixin, View):
  html = '(%s) Hello Django BBS'
  def get(self, request):
      return HttpResponse(self.html % 'GET')
  def post(self, request):
      return HttpResponse(self.html % 'POST')
  • 使用了ExecTimeMixin重写dispatch之后,在FirstView中不需要在进行重写dispatch
  • Django默认定义了一些Mixin简化开发:
    • LoginRequiredMixin验证当前请求必须是登录用户,否则禁止访问或重定向到登录页

Mixin实现代码复用

总结

  • 基于函数的视图:FBV
  • 基于类的视图:CBV

6.1.4 动态路由

  • 视图函数也是普通的Python函数,所以可以定义额外的参数
  • 对于视图函数中的额其他参数,如何传值
  • 需要引入动态路由的概念(URL不是固定的,URL中包含了传递给视图的参数变量)
  • 之前定义的视图映射的URL都可以被称作静态路由,即URL是固定的。
  • 配置动态路由需要用到path函数,区别在于:URL配置的语法上

使用path配置动态路由

  • 简单接受其他参数的视图示例
def dynamic_hello(request, year, month, day):
  html = '<h1>(%s) Hello</h1>'
  return HttpResponse(html % ('%s-%s-%s' % (year, month, day)))
  • 为这些参数有具体的含义,所以,它们也应该有具体的类型
# urls.py
path('dynamic/<int:year>/<int:month>/<int:day>/', views.dynamic_hello)

简单接收参数的视图

  • 之所以需要定义转换器,有两个原因:

    • 第一是可以将捕获到的字符值转换为对应的类型
    • 第二是对URL中传值的一种限制,避免视图处理出错
  • Django还提供了其他的转换器:str, slug, uuid, path 具体文档信息:https://weread.qq.com/web/reader/6e4329007193f1e66e43129k341323f021e34173cb3824c

自定义转换器

  • 内置的转换器都定义于:django/urls/converters.py

  • 它包含三个部分,也是每一个转换器都需要实现的三要素。

    • (1)regex:字符串类型的类属性,根据属性名可以猜测,这是一个正则表达式,用于匹配URL对应位置的参数值。
    • (2)to_python:参数value是从URL中匹配到的参数值,通过强转成对应的类型传递给视图函数。需要注意,这里可能因为强转抛出ValueError。
    • (3)to_url:将一个Python类型的对象转换为字符串,to_python的反向操作
  • 之前的例子:dynamic_hello存在的不足,月份的区间参数

  • 自定义一个转换器捕获一个正确的月份

from django.urls.converters import IntConverter
class MonthConverter(InConverter):
  regex = '0?[1-9]|1[0-2]'
  • 定义好转换器之后还需要注册才能使用, 在post应用的urls.py文件中注册
# urls.py
from django.urls import register_converter
from post.views import MonthConverter
register_converter(MonthConverter,'mth')
# 将转换器的类型名设定为mth,之后需要重新定义dynamic_hello视图的urls
path('dymmmic/<int:year>/<mth:month>/<int:day>/', views.dynamic_hello)

dymmmic_mth_404dymmmic_mth_200

带默认参数的视图

# views.py
def dynamic_hello(request, year, month, day=15):
  html = '<h1>(%s) Hello</h1>'
  return HttpResponse(html % ('%s-%s-%s' % (year, month, day)))
# urls.py
path('dymmmic/<int:year>/<mth:month>/', views.dynamic_hello),
path('dymmmic/<int:year>/<mth:month>/<int:day>/', views.dynamic_hello)

带默认参数

正则表达式

  • 正则表达式命名分组的语法:(?P<name>pattern)
    • name:分组名
    • pattern:匹配模式
    • 引用分组可以使用分组名,也可以使用分组编号
import re
r = re.compile('(?P<year>[0-9]{4})')
s = r.search('2022')
print(s.group('year'))
print(s.group(1))

# 2022
# 2022
  • path:定义于 django/urls/conf.py文件中
  • 基于此,就可以通过re_path,使用命名分组来定义URL
  • 使用re_path的理由是path方法和转换器都不能满足需求。其使用方法与path类似
  • 例子: 将dynamic_hello的URL模式使用re_path重新定义
# urls.py
from django.urls import re_path
re_path('re_dynamic/(?P<year>[0-9]{4})/(?P<month>0[1-9]|1[0-2])/(?P<day>[0-9]{2})', views.dynamic_hello)

注意:当使用re_path的时候,在实际应用中,path自定义选择器无法使用的问题

6.1.5 给post应用添加视图

  • 查看当前站点中所有的Topic列表信息
  • 查看单个Topic的详细信息
  • 给某一个Topic添加评论等

实现Topic列表视图

  • 这里不涉及渲染,而是直接返回json格式的数据(JsonResponse)
  1. 创建存储业务处理逻辑的文件post/post_service.py,并实现构造Topic实例对象基本信息的业务逻辑

    # post/post_service.py
    def build_topic_base_info(topic):
        """
        构造Topic基本信息
        :param topic
        :return 
        """
        return {
            'id':topic.id,
            'title': topic.title,
            'user': topic.user.username,
            'created_time': topic.created_time.strftime('%y-%m-%d %H:%M:%S')
        }
    
  2. 在post/views.py文件中定义Topic列表信息的视图函数

    # post/views.py
    def topic_list_view(request):
        """
        话题列表
        :param: request:
        :return:
        """
        topic_qs = Topic.objects.all()
        result = {
            "count": topic_qs.count(),
            "info": [build_topic_base_info(topic) for topic in topic_qs]
        }
        return JsonResponse(result)
    
  3. 添加视图路由

    # post/urls.py
    
    from django.urls import path, register_converter
    from post.views import FirstView, MonthConverter
    from post import views
    from django.urls import re_path
    urlpatterns = [
        # path('hello/',FirstView.as_view()), # 注册post应用的视图函数
        # path('dynamic/<int:year>/<int:month>/<int:day>/', views.dynamic_hello),
        # path('dymmmic/<int:year>/<mth:month>/', views.dynamic_hello),
        # path('dymmmic/<int:year>/<mth:month>/<int:day>/', views.dynamic_hello),
        # re_path('re_dynamic/(?P<year>[0-9]{4})/(?P<month>0[1-9]|1[0-2])/(?P<day>[0-9]{2})/', views.dynamic_hello),
        path('topiclist/', views.topic_list_view)
    ]   
    

实现Topic实例对象信息视图

  • 有了Topic的列表信息,根据列表信息中提供的id(Topic主键字段)查看每一个Topic的详细信息
  • 思考思路
    • 每一个Topic都有可能会有多个Comment,展示一个Topic的详细信息,应该吧Comment也展示出来,所需需要构造一个Comment信息的方法
# post/post_service.py
def build_comment_info(comment):
    """
    构造Comment信息
    :param comment:
    :return:
    """
    
    return {
        'id': comment.id,
        'content': comment.content,
        'up': comment.up,
        'down': comment.down,
        'created_time': comment.created_time.strftime('%y-%m-%d %H:%M:%S'),
        'last_modified': comment.last_modified.strftime('%y-%m-%d %H:%M:%S'),
    }
from post.models import Comment
def build_topic_detail_info(topic):
    """
    构造Topic详细信息
    :oaram topic:
    :return:
    """
    comment_qs = Comment.objects.filter(topic=topic)
    return {
        "id": topic.id,
        "title": topic.title,
        "content": topic.content,
        "user": topic.user.username,
        "create_time": topic.created_time.strftime('%y-%m-%d %H:%M:%S'),
        'last_modified': topic.last_modified.strftime('%y-%m-%d %H:%M:%S'),
        'comments': [build_comment_info(comment) for comment in comment_qs]
    }
# post/views.py
# comment详细信息
def topic_detail_view(reqeust, topic_id):
    """
    话题详细信息

    :param request:
    :param topic_id:
    :return:
    """
    result = {}
    try:
        result = build_topic_detail_info(Topic.objects.get(pk=topic_id))
    except Topic.DoesNotExist:
        pass
    return JsonResponse(result)
# post/urls.py
urlpatterns = [
  path('topic/<int:topic_id>/',views.topic_detail_view)
]

给Topic实例对象添加评论的视图

  • 先写添加评论的业务逻辑
# post/post_service.py

def add_comment_to_topic(topic,content):
    """
    给话题添加评论

    :param topic:
    :param content:
    :return:
    """
    # 这里简单地根据传递的Topic实例对象和评论内容(content)创建了Comment实例对象。注意,up和down可以使用默认值,不需要指定
    return Comment.objects.create(topic=topic, content=content)
  • 视图函数
from post.post_service import add_comment_to_topic
def add_comment_to_topic_view(request):
    """
    给话题添加评论

    :param request:
    :return:
    """
    topic_id = int(request.POST.get('id',0))
    content = request.POST.get('content','')
    topic = None
    try:
        topic = Topic.objects.get(pk=topic_id)
    except Topic.DoesNotExist:
        pass
    
    if topic and content:
        return JsonResponse({'id':add_comment_to_topic(topic,content)})
    return JsonResponse({})
  • 路由函数
urlpatterns = [
    path('topic_comment/', views.add_comment_to_topic_view)
]
最近更新时间:
Next
6.2 视图的高级特性和快捷方法