Python编程-后端开发之Django5应用请求处理与模板基础

news2024/12/23 8:09:46

Python编程-后端开发之Django5应用请求处理与模板基础

最近写项目,刚好用到了Django,现在差不多闲下来,个人觉得单体项目来讲django确实舒服,故写此总结
模板语法了解即可,用到了再看,毕竟分离已经是主流操作了,ORM与DRF加紧梳理中。。。。

Django程序简介

Django是一个用于构建Web应用程序的高级Python Web框架。它鼓励快速开发和干净、实用的设计。Django的主要目标是使开发复杂的、数据库驱动的网站变得简单,同时也适用于更小的项目。以下是一些Django框架的主要特点:

  1. MTV架构模式:Django采用了模型-模板-视图(Model-Template-View,MTV)的架构模式,将数据模型、用户界面和业务逻辑相分离,使得应用程序更易于维护和扩展。

  2. 强大的数据库支持:Django提供了内置的对象关系映射(Object-Relational Mapping,ORM)工具,支持多种数据库后端,包括MySQL、PostgreSQL、SQLite和Oracle等。

  3. 自动化的管理界面:Django自动生成管理界面,开发者无需编写额外的代码即可对数据库进行管理和操作,大大提高了开发效率。

  4. 安全性:Django内置了一系列安全功能,如防止SQL注入、跨站脚本攻击(XSS)和跨站请求伪造(CSRF)等,使得应用程序更加安全可靠。

  5. 灵活的URL路由:Django使用URLconf(URL配置)来将URL映射到视图函数,支持正则表达式和命名组,使URL配置更加灵活和可读性更高。

  6. 模板系统:Django提供了强大而灵活的模板系统,支持模板继承、自定义过滤器和标签等功能,使得页面设计更加简单和可维护。

  7. 多语言支持:Django提供了多语言支持功能,可以轻松地创建多语言网站,支持国际化和本地化。

  8. 易于扩展:Django提供了丰富的第三方应用程序和插件,可以轻松地扩展和定制功能,满足各种需求。

Django的MTV架构

在Django中,MVT(Model-View-Template)架构对应到了默认的目录层级,每个部分都有相应的位置和功能:

  1. 模型(Model):模型负责定义数据结构,通常对应数据库中的表。在Django中,模型位于应用程序的models.py文件中。每个应用程序都可以有自己的模型文件,用于描述该应用程序的数据模型。

  2. 视图(View):视图负责处理用户请求并返回相应的内容,可以是网页、JSON数据等。在Django中,视图通常位于应用程序的views.py文件中。视图函数接收请求,并根据需要从数据库中获取数据,然后渲染模板或返回JSON数据等。

  3. 模板(Template):模板负责生成最终呈现给用户的HTML页面。在Django中,模板通常位于应用程序的templates目录中(默认是不会创建的)。每个应用程序都可以有自己的模板目录,用于存放该应用程序的HTML模板文件。

除了上述三个部分外,Django还有一个项目级别的配置文件settings.py,用于配置整个Django项目的设置,如数据库设置、静态文件设置等。此外,还有一个项目级别的URL配置文件urls.py,用于定义项目中的URL路由。

Django的默认目录层级如下所示:

.
├── DjangoTestproject
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-310.pyc
│   │   └── settings.cpython-310.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── myfirstapp
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

每个子应用程序都有自己的目录,其中包含模型、视图、模板等文件。项目级别的文件包括项目的配置、URL路由等。

文件/目录功能描述
admin.py网站后台管理站点配置相关
apps.py配置当前子应用的相关信息
migrations存放数据库迁移历史文件
models.py保存数据库模型类
tests.py开发测试用例,编写单元测试
views.py编写Web应用视图

MVC架构与MVT架构区别

MTV(Model-Template-View)与MVC(Model-View-Controller)是两种常见的软件架构模式,用于构建Web应用程序。它们之间的区别如下:

  1. MVC 架构

    • Model(模型):负责处理应用程序的数据逻辑。它通常包含表示数据的类,以及与数据库交互的方法。
    • View(视图):负责将模型的数据呈现给用户。视图通常是用户界面的一部分,例如网页或移动应用的页面。
    • Controller(控制器):负责处理用户输入并更新模型和视图。控制器接收用户的请求,调用相应的模型逻辑来处理请求,然后更新视图以反映模型的变化。

    MVC 将应用程序分为三个部分,分别处理数据、用户界面和用户输入。这种分离使得代码更易于管理和维护,同时也使得不同部分的代码可以独立开发和测试。

  2. MTV 架构

    • Model(模型):与 MVC 中的模型类似,负责处理数据逻辑。
    • Template(模板):与 MVC 中的视图类似,负责将模型的数据呈现给用户。模板通常包含 HTML、CSS 和一些简单的逻辑代码。
    • View(视图):在 MTV 中,视图更多地指代控制器的功能。视图接收用户的请求,调用相应的模型逻辑来处理请求,然后将处理结果传递给模板进行渲染。

    MTV 与 MVC 的主要区别在于视图的角色。在 MVC 中,视图负责将模型的数据呈现给用户,而在 MTV 中,视图更像是控制器,负责处理用户的请求和更新模型。

Django默认配置解读

  • 指定django应用的根目录,因为django本身其实也是作为一个子应用嵌入进我们的web程序的
BASE_DIR = Path(__file__).resolve().parent.parent
  • 密钥(Secret Key)是用于加密会话数据、CSRF 令牌等重要信息的关键。密钥是一个随机生成的字符串,用于保护 Django 站点的安全性。
SECRET_KEY = 'django-insecure-%jo-z*+2)e8osx#vnpwtilvpq14c0+sx*!z##6chez68jwvsa%'
  • DEBUG调试模式开启状态,开启时访问页面将有详细输出与日志,并且可以直接访问静态资源
DEBUG = True
  • ALLOWED_HOSTS用于指定哪些主机名(或 IP 地址)可以被允许访问此Django网站, 可以是*表示允许所有主机访问,在DEBUG模式关闭状态下,必须进行设置
ALLOWED_HOSTS = []
  • 子应用注册列表,用于将指定应用用于构建Django应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
  • 中间件列表,以插件实现功能分离
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',
]

Web应用中间件是一种软件组件,它位于应用程序和底层操作系统之间,用于处理和管理在Web应用程序中发送和接收的网络请求和响应。中间件通常用于实现一些常见的功能,如路由请求、身份验证、日志记录、缓存、压缩和安全性。它们可以帮助开发人员简化应用程序的开发和维护,提高应用程序的性能和安全性,并允许开发人员集中精力处理应用程序的核心逻辑。

  • 项目级路由配置位置
ROOT_URLCONF = 'DjangoProjectExample.urls'
  • 模板文件配置项
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
  • WSGI程序入口点指定,这个我们一般不进行修改,一般是WSGI程序通过wsgi.application来与django访问
WSGI_APPLICATION = 'DjangoProjectExample.wsgi.application'

WSGI(Web Server Gateway Interface)是Python Web应用程序和Web服务器之间的标准接口,它定义了Web服务器如何与Python Web应用程序进行通信的规范。在Django中,WSGI扮演着非常重要的角色,它使得Django应用程序能够在符合WSGI标准的任何WSGI兼容的Web服务器上运行,如Gunicorn、uWSGI等。

WSGI服务器通常是一个独立的软件,可以单独部署和运行,也可以作为Web服务器的一部分。常见的WSGI服务器包括:

  1. uWSGI:uWSGI是一个功能强大的WSGI服务器,支持多种协议和语言,可以与Nginx等Web服务器配合使用,广泛用于部署Python Web应用程序。
  2. Gunicorn:Gunicorn是一个简单而稳定的WSGI服务器,易于使用和部署,是Django和Flask等Python Web框架的推荐服务器。
  3. mod_wsgi:mod_wsgi是一个用于Apache HTTP服务器的模块,可以让Apache直接运行WSGI应用程序,是在Apache上部署Python Web应用程序的常用方式。
  4. Waitress:Waitress是一个轻量级的WSGI服务器,易于配置和部署,适合用于开发和测试环境。

这些WSGI服务器都符合WSGI标准,可以与任何符合WSGI标准的Python Web应用程序(如Django、Flask等)配合使用,实现Web应用程序的部署和运行。

  • 数据库配置项,默认状态下为sqlite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

MySQL配置指令:

# settings.py
DATABASES = {
 'default': {
     'ENGINE': 'django.db.backends.mysql',
     'NAME': 'dbname',
     'USER': 'username',
     'PASSWORD': 'password',
     'HOST': '127.0.0.1',
     'POST': '3306',
 }
}

参考:https://docs.djangoproject.com/zh-hans/5.0/ref/databases/#mysql-notes

  • 定义密码验证器(Password Validators),用于验证用户设置的密码是否符合安全要求。
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

在上面的配置中,包含了四个密码验证器:

  1. UserAttributeSimilarityValidator:检查密码与用户的属性(如用户名、邮箱等)的相似度,防止用户设置过于简单的密码。
  2. MinimumLengthValidator:检查密码的最小长度,确保密码长度符合要求。
  3. CommonPasswordValidator:检查密码是否为常见密码(如123456、password等),以提高密码的安全性。
  4. NumericPasswordValidator:检查密码是否仅由数字组成,以提高密码的复杂性。
  • 指定了项目的默认语言
LANGUAGE_CODE = 'en-us'

'en-us’表示英语(美国)是项目的默认语言。Django会根据这个设置来选择适当的翻译文件,以便在需要时提供本地化的内容。

  • 指定项目的默认时区
TIME_ZONE = 'UTC'
  • 启用国际化功能状态,当这个设置为True时,Django会尝试根据LANGUAGE_CODE设置来翻译项目中的文本内容
USE_I18N = True
  • 启用时区功能,当这个设置为True时,Django会使用TIME_ZONE设置来处理日期和时间
USE_TZ = True
  • STATIC_URL指定了浏览器访问静态文件时的基础URL路径,相当于一条专属于静态资源的路由。
STATIC_URL = 'static/'
  • 指定数据库的自增字段类型
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

这段代码是Django 3.2及以上版本中新增的设置,用于指定模型的默认自增字段(AutoField)。在之前的Django版本中,默认使用的是AutoField,它会根据数据库类型选择适合的自增字段类型(如整数或大整数)。但是,在Django 3.2中引入了BigAutoField,它始终使用大整数类型来表示自增字段,以解决某些数据库(如PostgreSQL)中整数类型的自增字段可能不够大的问题。

Django的常见指令

  1. 安装 Django: 如果尚未安装 Django,请使用以下命令安装:

    pip install django
    
  2. 创建 Django 项目: 在命令行中运行以下命令来创建 Django 项目:

    django-admin startproject myproject
    

    这将在当前目录中创建一个名为 myproject 的新目录,其中包含 Django 项目的初始文件。

  3. 创建应用:使用 python manage.py startapp 命令创建一个新的子应用。

    python manage.py startapp myapp
    

    这将在项目中创建一个名为 myapp 的子应用。

  4. 初始化数据库: 在项目目录中运行以下命令来初始化数据库:

    python manage.py migrate
    

    这将创建默认的 SQLite 数据库文件,并为 Django 的内置应用程序创建必要的数据表。

  5. 运行开发服务器: 最后,运行以下命令启动 Django 的开发服务器:

    python manage.py runserver
    

    这将启动服务器,并在默认端口(通常为 8000)上提供 Django 应用程序。

注册使用子应用

这里的子应用我们可以看作是当前应用的一个模块,每个模块都符合我们的MTV架构,在上面我运行以下指令创建了一个子应用(注意,创建在了我们django应用的同级目录下,其实只要指定了正确的目录都可以,但是这样更符合我们的开发规范):

python3 manage.py startapp myfirstapp

然后我们在django创建项目时生成的目录内可以找到setting.py,我们在列表中加上我们需要注册的子应用的apps.py中默认生成的类即可:

# 子应用生成的类
class MyfirstappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myfirstapp'
# 修改后的setting中的应用数组

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myfirstapp.apps.MyfirstappConfig'
]

setting.py.INSTALLED_APPS中的默认字段:

  • django.contrib.admin:Django 管理后台,用于管理网站的后台管理界面。
  • django.contrib.auth:提供用户认证和授权的功能,包括用户登录、注册、密码管理等。
  • django.contrib.contenttypes:提供了用于跟踪模型(Model)之间关系的框架,可以用于实现通用关系、内容类型等功能。
  • django.contrib.sessions:提供了会话管理功能,用于在客户端和服务器端之间存储会话数据。
  • django.contrib.messages:用于在视图之间传递消息的框架,包括成功消息、错误消息等。
  • django.contrib.staticfiles:用于管理静态文件(如 CSS、JavaScript、图片等)的框架,可以方便地在模板中引用静态文件。

这些内置应用程序可以通过在 INSTALLED_APPS 设置中添加相应的应用名称来启用和使用。

视图创建使用

在 Django 中,视图(View)是处理用户请求并返回响应的函数或类。视图函数接收一个请求对象作为参数,然后根据请求的内容生成一个响应对象,通常这个响应对象是一个 HTML 页面。我们创建视图通常在子应用中的views.py中。

创建简单视图

from django.http import HttpResponse
from django.http import HttpRequest	


def say_hello_world(request: HttpRequest) -> HttpResponse:
    return HttpResponse("Hello World! This is MyFirstDjangoApp!")

Django请求对象

在 Django 中,要导入请求对象(HttpRequest),通常需要从 django.http 模块中导入。导入请求对象的方式如下:

from django.http import HttpRequest		# 如果需要写类型提示 则需要导入

但实际上,在编写 Django 视图时,通常不需要手动导入 HttpRequest。Django 会在调用视图函数时自动创建请求对象,并将其作为第一个参数传递给视图函数(所以视图函数的第一个传入参数必须定义,用于接收请求对象)。因此,可以直接在视图函数的参数列表中使用 HttpRequest,而不需要显式地导入它。

请求对象的主要属性和方法包括:

属性/方法描述
request.method请求的方法,如 GET、POST 等。
request.GET一个类似字典的对象,包含了所有的 GET 参数。
request.POST一个类似字典的对象,包含了所有的 POST 参数。
request.FILES一个类似字典的对象,包含了所有上传的文件。
request.COOKIES一个包含所有 cookie 的字典。
request.session一个代表当前会话的对象,用于存储和访问会话数据。
request.path请求的路径部分,不包括域名和查询参数。
request.get_host()获取请求的主机部分,包括域名和端口。
request.is_secure()如果请求是通过 HTTPS 发送的,则返回 True,否则返回 False。

Django响应对象

在 Django 中,响应对象(HttpResponse)代表了服务器返回给客户端的 HTTP 响应。它包含了要发送给客户端的内容以及其他相关的信息,如响应状态码、响应头等。当视图函数返回一个响应对象时,Django 将会把这个响应发送给客户端。

注意:在 Django 中,视图函数必须返回一个响应对象(HttpResponse 或其子类)。这是因为 Django 是一个基于请求和响应的 Web 框架,它需要将用户发来的请求映射到相应的视图函数,并将处理结果返回给客户端。如果视图函数没有返回响应对象,Django 将会抛出一个异常。因此,确保每个视图函数都正确返回一个响应对象是很重要的。如果视图函数不需要返回任何内容,可以返回一个空的响应对象

响应对象的主要方法和属性包括:

方法/属性描述
HttpResponse(content, content_type='text/html', status=200)构造一个响应对象,content 是要返回的内容,content_type 是内容的类型,默认为 text/htmlstatus 是响应的状态码,默认为 200。
HttpResponseRedirect(redirect_to)构造一个重定向响应,将客户端重定向到指定的 URL。
JsonResponse(data, **kwargs)构造一个 JSON 格式的响应,data 是要返回的 JSON 数据。
response.content响应的内容,以字节形式表示。
response.status_code响应的状态码。
response['header']获取指定的响应头。

视图路由管理

在 Django 中,路由(URLconf)用于将 URL 映射到视图函数,从而确定如何处理客户端发来的请求。Django 的路由系统基于 URL 模式(URL patterns)。路由模式通常使用正则表达式来匹配 URL。在路由配置中,我们可以使用 path() 函数或 re_path() 函数来定义 URL 模式。Django 的路由配置主要包括两个部分:

  1. 项目级别的路由配置:位于项目的 urls.py 文件中,用于指定项目级别的 URL 模式。这个文件通常位于项目的根目录下,例如 myproject/urls.py
  2. 应用级别的路由配置:位于应用程序的 urls.py 文件中,用于指定应用程序级别的 URL 模式。每个应用程序都可以有自己的 urls.py 文件,用于定义应用程序内部的 URL 映射关系。这个文件通常位于应用程序目录下,例如 myapp/urls.py

项目级视图配置

在创建项目时生成的django子应用中的urls.py文件中修改urlpatterns列表:

from django.contrib import admin
from django.urls import path
from myfirstapp.views import say_hello_world

urlpatterns = [
    path('admin/', admin.site.urls),
    # 第一参数是路由路径 第二参数是视图函数 
    # 还有个name参数是模板和重定向相关 暂时不表
    path('hello_world/', say_hello_world),
]

path('admin/', admin.site.urls)这个默认配置是将 /admin/ 路径映射到 Django 管理后台的 URL。当访问 admin/ 路径时,Django 会自动调用管理后台的视图函数,显示管理后台的登录页面(如果用户未登录),或者显示管理后台的主界面(如果用户已登录)。

使用python3 manage.py runserver启动项目进行访问:

r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/hello_world/'
Hello World! This is MyFirstDjangoApp!

需要注意的是,django对于路由的管理默认是严格的,即访问hello_world/hello_world是不一样的,但是一旦我们在视图路径后加上/,django将会在用户访问hello_world时重定向到hello_world/路由。为了确保加载正常,建议每个路由的路径都添加/,这点同时也是其他web应用的约定。

应用级视图配置

对于项目级路由来讲,维护是及其不便的,所以我们有另一种方式来管理我们的视图路由,我们可以在子应用下建立一个新的urls.py文件:

# myfirstapp/urls.py
from . import views
from django.urls import path

urlpatterns = [
    path('hello_world', views.say_hello_world),
]

然后在项目级的urls.py中使用include函数包含子应用中的urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myfirstapp/', include('myfirstapp.urls'))
]

启动项目进行访问:

r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/hello_world'
Hello World! This is MyFirstDjangoApp

路由解析顺序

urlpatterns = [
    re_path(r'^get', myfirstapp.views.get_index),
    re_path(r'^get_', myfirstapp.views.get_content)
]

需要注意的是,django的路由解析顺序是自上而下的顺序,如上述路由表,即使我们访问get_content

视图,我们也只会收到服务端get_index的视图内容,因为正则匹配的路由在第一条中优先解析了我们的请求,造成了第二条路由被屏蔽了访问

路由属性NAME

name 属性在 Django 中用于给 URL 模式命名,使得我们可以在代码的其他地方引用这个 URL。这样做的好处是,当我们需要在模板中生成链接或在视图函数中重定向到某个 URL 时,可以直接使用这个 URL 的名称,而不必硬编码 URL 地址。

例如,在 urls.py 中定义了一个 URL 模式:

path('about/', views.about, name='about')
  • 模板生成路由链接

我们可以在模板中这样使用这个命名的 URL(模板使用详见后文):

<a href="{% url 'about' %}">About Us</a>

这里的 {% url 'about' %} 将会被解析为 /about/,这样就可以生成一个指向 “About Us” 页面的链接。如果后续需要修改 URL 地址,只需在 urls.py 中修改一处即可,而不必在模板中每处引用都修改。

  • reverse() 函数反向解析 URL

同样地,在视图函数中可以使用 reverse() 函数来反向解析 URL:

from django.urls import reverse
from django.http import HttpResponseRedirect, HttpResponse

def my_redirect_view(request) -> HttpResponse:
    # 重定向到 'about' 页面
    return HttpResponseRedirect(reverse('about'))
  • redirect()函数中使用name属性:

redirect()函数可以直接接受URL的name属性作为参数,用于重定向到特定的URL。

pythonCopy codefrom django.shortcuts import redirect
from django.http import HttpResponse

def my_redirect_view(request) -> HttpResponse:
    # 重定向到名为'about_page'的URL
    return redirect('about_page')

静态资源管理

在Django中,静态资源通常包括CSS样式表、JavaScript文件、图像文件等,这些文件需要被服务器直接提供给客户端,而不需要经过Django的处理。

静态资源目录列表

在项目的settings.py文件中,定义静态文件目录的位置。可以使用STATICFILES_DIRS设置静态文件目录列表,通常为了便于项目维护,我们会使用BASE_DIR配合指定静态资源目录路径

# 在settings.py增加以下内容

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

这样设置后,在开启DEBUG模式下,我们可以直接在请求路径中使用static路由,例如:

http://127.0.0.1:8000/static/example.png

静态资源搜集路径

可以使用STATIC_ROOT设置收集静态文件的目录。不过,在部署应用程序之前,需要收集静态文件到STATIC_ROOT目录中。可以使用collectstatic管理命令来完成此操作。

# 在settings.py增加以下内容

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    os.path.join(BASE_DIR, "file"),
]

# 在setting.py 设置静态文件收集目录
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

在部署项目时运行以下指令将会把所有的静态资源文件复制一份到STATIC_ROOT路径中:

python manage.py collectstatic

在开发过程中,可以使用django.contrib.staticfiles中的staticfiles_urlpatterns来提供静态文件的URL模式。

# urls.py

from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()

说白了上述代码就是在路由表里增加了我们的静态资源路由规则,之所以选择复制一份到一个统一的目录下,原因是在在生产环境中,通常使用Web服务器(如Nginx或Apache)来提供静态文件,而不是由Django来处理。这样可以提高静态文件的访问速度和性能。

客户端请求处理

URL路径参数处理

在Django中,我们处理路径中的请求参数是依靠正则表达式的捕获分组来实现的,其处理方式也分为两种,一种是分组位置传递,一种是分组名传递,例如我们有个博客网站,其定位文章的路径通常是:

http://blog.example.com/userhash/article/123456

那我们就可以捕获路径中的/article/123456来进行定位,我们在这里使用正则匹配,然后我去除了最后的/,保证可以一次获取到请求的内容,而非重定向的响应:

urlpatterns = [
    re_path(r'^userhash/([a-z]+)/(\d{8})$', views.get_path_arguments),
]

得到结果:

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/userhash/artclie/23333333'
Status: OK<br/>FirstArg: artclie<br/>SecondArg: 23333333<br/>

另一种方式则是借助正则的分组命名精确指定参数,修改路由规则:

urlpatterns = [
    re_path(r'^userhash/(?P<second_arg>[a-z]+)/(?P<first_arg>\d{8})$', 
            views.get_path_arguments),
]

再次请求发现参数顺序发生改变:

 r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/userhash/artclie/23333333'
Status: OK<br/>FirstArg: 23333333<br/>SecondArg: artclie<br/

GET请求参数处理

对于get请求参数的处理,我们则是依靠request的GET属性来进行获取,使用get方法获取单个参数内容,使用getlist获取列表内容(处理多选框等一键多值的情况),并且在未获取到对应参数时将返回None或空列表

urlpatterns = [
    path('getargs', views.get_request_arguments),
]

对应的方法:

def get_request_arguments(request: HttpRequest) -> HttpResponse:
    arg1: str = request.GET.get('arg1')
    arg2: list[str] = request.GET.getlist('arg2')
    return HttpResponse(f"The Arg1: {arg1}<br/>"
                        f"The Arg2: {arg2}<br/>")

我们依次测试访问:

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getargs?arg1=2333&arg2=233&arg2=2333333333'
The Arg1: 2333<br/>The Arg2: ['233', '2333333333']<br/>

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getargs?arg1=2333&arg2=233'
The Arg1: 2333<br/>The Arg2: ['233']<br/>

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getargs?arg1=&arg2=233'
The Arg1: <br/>The Arg2: ['233']<br/>

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getargs?arg2=233'
The Arg1: None<br/>The Arg2: ['233']<br/>

POST请求参数处理

处理POST请求的方式与GET请求的方式是类似的,只不过我们获取的参数是POST的内容,但是我们在测试环境中测试时,需要关闭django的CRSF安全中间件,否则将会被拦截

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

直接修改上面处理GET的视图函数来测试:

def get_request_arguments(request: HttpRequest) -> HttpResponse:
    arg1: str = request.POST.get('arg1')
    arg2: list[str] = request.POST.getlist('arg2')
    return HttpResponse(f"The Arg1: {arg1}<br/>"
                        f"The Arg2: {arg2}<br/>")

与上面一致,我们直接进行测试即可(这里只展示一种):

(.venv) r123@localhost:~/DjamgoTestProject$ curl -X POST http://127.0.0.1:8000/myfirstapp/getargs -d "arg1=value1&arg2=value2"
The Arg1: value1<br/>The Arg2: ['value2']<br/>

JSON请求体处理

要处理JSON请求体,我们可以使用request的body内容来获取:

def get_request_body(request: HttpRequest) -> HttpResponse:
    json_data: bytes = request.body
    return HttpResponse(f"DataType: {type(json_data)}<br/>"
                        f"DataContent: {json_data}<br/>")

测试结果如下:

(.venv) r123@localhost:~/DjamgoTestProject$ curl -X POST http://127.0.0.1:8000/myfirstapp/getbody -H "Content-Type: application/json" -d '{"key1": "value1", "key2": "value2"}'
DataType: <class 'bytes'><br/>DataContent: b'{"key1": "value1", "key2": "value2"}'<br/>

在使用json中的数据时需要先将请求体中的数据先解码后加载:

import json
...

# 解码请求体中的JSON数据
json_data = request.body.decode('utf-8')
# 将JSON字符串转换为Python对象
data = json.loads(json_data)

Headers请求头处理

在Django中request维护一个字典属性META用于保存请求头内容,常用的属性标识如下:

变量名描述
CONTENT_LENGTH请求正文的长度(作为字符串)。
CONTENT_TYPE请求正文的 MIME 类型。
HTTP_ACCEPT响应可接受的内容类型。
HTTP_ACCEPT_ENCODING响应可接受的编码方式。
HTTP_ACCEPT_LANGUAGE响应可接受的语言。
HTTP_HOST客户端发送的 HTTP 主机头。
HTTP_REFERER引用页面(如果有)。
HTTP_USER_AGENT客户端的用户代理字符串。
QUERY_STRING查询字符串,作为单个(未解析的)字符串。
REMOTE_ADDR客户端的 IP 地址。
REMOTE_HOST客户端的主机名。
REMOTE_USERWeb 服务器验证的用户(如果有)。
REQUEST_METHOD字符串,如“GET”或“POST”。
SERVER_NAME服务器的主机名。
SERVER_PORT服务器的端口(作为字符串)。
def get_request_header(request: HttpRequest) -> HttpResponse:
    return HttpResponse(str(request.META))

服务端响应处理

响应头处理

我们还可以自定义响应头部发送给客户端:

def get_request_header(request: HttpRequest) -> HttpResponse:
    response: HttpResponse = HttpResponse("Please check the response headers")
    response["MySelfDefineHeader"] = "MySelfDefineHeaderData"
    return response

通过这样类似字典的方式,我们就可以实现自定义响应头部字段:

HTTP/1.1 200 OK
Date: Mon, 06 May 2024 06:52:16 GMT
Server: WSGIServer/0.2 CPython/3.10.12
Content-Type: text/html; charset=utf-8
MySelfDefineHeader: MySelfDefineHeaderData
X-Frame-Options: DENY
Content-Length: 33
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin

Please check the response headers

修改响应头的内容,则可以通过面向对象的方式来进行修改:

def get_request_header(request: HttpRequest) -> HttpResponse:
    response: HttpResponse = HttpResponse("Please check the response headers")
    response.status_code = 233
    return response

输出响应头,发现修改成功:

HTTP/1.1 233 Unknown Status Code
Date: Mon, 06 May 2024 06:55:32 GMT
Server: WSGIServer/0.2 CPython/3.10.12
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Content-Length: 33
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin

Please check the response headers

页面重定向

我们还可以返回一个HttpResponseRedirect对象来对客户端进行页面重定向操作,同时也有redirect方法可直接返回此对象

from django.shortcuts import redirect
from django.http import HttpResponseRedirect

def set_redirect_page(request: HttpRequest) -> HttpResponseRedirect:
    return redirect("http://www.baidu.com")

这个redirect函数的实现并不复杂:

def redirect(to, *args, permanent=False, **kwargs):
 redirect_class = (
     HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
 )
 return redirect_class(resolve_url(to, *args, **kwargs))

其本质上追踪到最后的HttpResponseRedirectBase类,实质上就是指定了我们的响应头Location

class HttpResponseRedirectBase(HttpResponse):
 allowed_schemes = ["http", "https", "ftp"]

 def __init__(self, redirect_to, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self["Location"] = iri_to_uri(redirect_to)
		...

值得注意的是,我们还可以指定我们的urls.py中的路由进行重定向,这样的重定向具有三个使用形态,并且相互独立:

  • 直接使用路由的name信息进行定位页面
urlpatterns = [
    path('getpage', views.set_redirect_page),
    path('hello', views.say_hello_world, name='hello'),
]

def set_redirect_page(request: HttpRequest) -> HttpResponseRedirect:
    return redirect("hello")
  • 使用相对路径重定向页面
urlpatterns = [
    path('getpage', views.set_redirect_page),
    path('hello/', views.say_hello_world),
]

def set_redirect_page(request: HttpRequest) -> HttpResponseRedirect:
    return redirect("hello/")
  • 使用绝对路径定向页面
urlpatterns = [
    path('getpage', views.set_redirect_page),
    path('hello/', views.say_hello_world, name='hello'),
]

def set_redirect_page(request: HttpRequest) -> HttpResponseRedirect:
    # 在开发环境中此时重定向的页面是http://127.0.0.1:8000/hello/
    return redirect("/hello/")

JSON响应

JsonResponse是Django框架中用于返回JSON数据的类。它允许以JSON格式构建响应,并将其发送回客户端。

def get_request_json(request: HttpRequest) -> JsonResponse:
    data: dict = {"key1": "value1", "key2": "value2", "key3": "value3"}
    return JsonResponse(data=data)

得到响应:

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getjson'
{"key1": "value1", "key2": "value2", "key3": "value3"}

我们还可以传递其他参数来自定义响应的行为,例如设置响应的状态代码、内容类型或字符编码:

def my_view(request: HttpRequest) -> JsonResponse:
    data = {'key': 'value'}
    return JsonResponse(data, status=200, content_type='application/json', charset='utf-8')

此外,JsonResponse还具有safe参数,用于处理非字典类型的数据。当safe=True时,JsonResponse将尝试将数据转换为可序列化的内容。默认情况下,safeTrue,但可以显式设置为False以禁用此行为:

def my_view(request: HttpRequest) -> JsonResponse:
    data = ['item1', 'item2', 'item3']
    return JsonResponse(data, safe=False)

状态交互之COOKIES

Cookie:有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型的应用就是记住用户名。

Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息,如密码等,因为电脑上的浏览器可能被其它人使用。

Cookie的特点

  1. Cookie以键值对的格式进行信息的存储。

  2. Cookie基于域名安全,不同域名的Cookie是不能互相访问

  3. 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。

设置Cookies

可以通过HttpResponse对象中的set_cookie方法来设置cookies

def set_cookie(
    self, key, value="", max_age=None, expires=None, path="/", domain=None,
    secure=False, httponly=False, samesite=None,
)...

可以将这些属性整理成表格形式如下:

属性含义默认值
keycookie 的名称
valuecookie 的值“”
max_agecookie 的最大存活时间(秒)None
expirescookie 的过期时间None
pathcookie 的有效路径“/”
domaincookie 的有效域名None
securecookie 是否只能通过 HTTPS 连接传输False
httponlycookie 是否只能通过 HTTP(S) 协议访问False
samesitecookie 的 SameSite 属性,控制跨站点请求时是否发送 cookieNone

max_age 单位为秒,如果是临时cookie,可将max_age设置为None。

def get_site_cookies(request: HttpRequest) -> HttpResponse:
    response: HttpResponse = HttpResponse("set cookies")
    response.set_cookie(key="cookie1", value="value1")
    response.set_cookie(key="cookie2", value="value2", max_age=600)
    return response

读取Cookies

读取cookies可以使用响应的元数据字典,并且在 Django 中,request.COOKIES.get() 方法不会因为未找到指定的 cookie 而报错。如果指定的 cookie 不存在,get() 方法会返回 None,这样可以避免抛出异常。

def get_client_cookies(request: HttpRequest) -> HttpResponse:
    cookie1 = request.COOKIES.get("cookie1")
    cookie2 = request.COOKIES.get("cookie2")
    return HttpResponse(f"{request.COOKIES} , {cookie1}, {cookie2}")

利用curl单次访问输出,为空内容:

(.venv) r123@localhost:~/DjamgoTestProject$ curl 'http://127.0.0.1:8000/myfirstapp/getcookies'
{}

删除Cookies

删除客户端的cookies可以通过delete_cookie方法,不过它的删除是基于键的,需要我们提供对应cookie字段的键,执行此方法会将对应cookie的值的部分置为空

def delete_cookie(self, key, path="/", domain=None, samesite=None)...

示例:

def reset_cookies_status(request: HttpRequest) -> HttpResponse:
    response: HttpResponse = HttpResponse()
    # 删除指定cookie
    response.delete_cookie(key="cookie1")
    # 循环清除所有cookie
    for i in request.COOKIES:
        response.delete_cookie(i)
    return response

状态交互之SESSION

Session在取得客户端的凭据后进行鉴权生成。在HTTP报文中,Session可以通过两种方式出现:

  • Cookie中:最常见的方式是通过Cookie将Session ID发送到服务器。服务器在响应中设置一个名为"Set-Cookie"的头部,其中包含Session ID,浏览器会将这个Cookie保存下来,并在后续的请求中将其发送到服务器,以维持会话。

  • URL参数中:在某些情况下,Session ID也可以通过URL参数传递。这种方式比较少见(CTF遇到过,现实中没见过),因为URL参数可能会被记录在浏览器的历史记录、日志文件等中,存在一定的安全风险。但在某些情况下,比如浏览器禁用了Cookie时,这种方式可能会被使用。

SESSION存储

在Django中session默认是以中间件的形式加载进Web应用程序的:

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    ...
]

这也就意味着我们也必须将session模块注册进应用中,Django默认也是自动加载的:

INSTALLED_APPS = [
    ...
    'django.contrib.sessions',
	...
]

Django提供了几种不同的方式来存储会话(session)数据,具体取决于应用程序需求和环境。主要有以下配置方式,我们可以在settings.py文件中进行配置:

数据库存储:Django可以将会话数据存储在关系型数据库中,如SQLite、MySQL、PostgreSQL等。可以通过在settings.py中设置SESSION_ENGINE来选择使用的数据库引擎(这也是默认的存储方式,其在数据库中只保存键,值,过期时间):

SESSION_ENGINE = 'django.contrib.sessions.backends.db'

缓存存储:Django支持使用缓存系统存储会话数据,这样可以提高性能并减轻数据库负担。可以在settings.py中配置使用的缓存后端,例如:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

文件系统存储:还可以将会话数据存储在文件系统中。这种方法适用于单个服务器环境,但在负载较高或多服务器部署时可能会遇到性能问题。可以在settings.py中配置文件系统路径:

SESSION_ENGINE = 'django.contrib.sessions.backends.file'
SESSION_FILE_PATH = '/path/to/session/files/'

缓存数据库存储:结合缓存和数据库的优点,可以将会话数据存储在缓存中,并在需要时同步到数据库中。这种方法可以在一定程度上提高性能并保证数据的持久性。配置方式如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

在加载缓存服务器时,我们可以指定SESSION_CACHE_ALIAS配置加载多个不同缓存服务器来执行不同的功能

SESSION_CACHE_ALIAS 是 Django 中用于配置会话(session)存储时所使用的缓存别名的配置项。它允许指定一个缓存别名,该别名对应于在 CACHES 设置中定义的缓存配置。

CACHES = {
 'default': {
     'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
     'LOCATION': '127.0.0.1:11211',
 },
 'session_cache': {
     'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
     'LOCATION': '/var/tmp/django_cache',
 }
}

SESSION_CACHE_ALIAS = 'session_cache'

在这个例子中,会话数据将会使用名为 session_cache 的缓存配置来进行存储。

SESSION操作

在Django中我们通过HttpRequest对象的session属性进行会话的读写操作,建立session后将会在客户端cookies中建立session_id字段:

def set_session(request: HttpRequest) -> HttpResponse:
    request.session["key"] = "value"
    request.session.set_expiry(60)
    return HttpResponse("set sesssion ok")

常见操作如下:

操作示例
设置session键值对request.session["key"] = "value"
读取请求中的session信息request.session.get("key", "default_value")
清除所有sessionrequest.session.clear()
清除session数据request.session.flush()
删除指定键及值del request.session["key"]
设置有效期60srequest.session.set_expiry(60)

request.session.set_expiry接收值value

  • 如果value是一个整数,session将在value秒没有活动后过期。
  • 如果value0,那么用户sessionCookie将在用户的浏览器关闭时过期。
  • 如果valueNone,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。

注意:与COOKIES的获取一致,在 Django 中,如果使用 request.session.get('key') 方法获取会话(session)值时,如果键 'key' 不存在,不会抛出异常。相反,它将返回 None

我们可以抓个包来看看:

HTTP/1.1 200 OK
Date: Tue, 14 May 2024 08:51:41 GMT
Server: WSGIServer/0.2 CPython/3.10.12
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Content-Length: 12
Vary: Cookie
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Set-Cookie:  sessionid=8qwysr46bcgpfw8djsgvf0pr71wna8jn; expires=Tue, 14 May 2024 08:52:41 GMT; HttpOnly; Max-Age=60; Path=/; SameSite=Lax

set sesssion ok

类视图请求交互

在Django中,类视图(Class-Based Views)是一种处理HTTP请求的方式,使用基于类的视图可以让你的代码更加简洁和可重用。类视图基于Python类的概念,每个类视图处理一个特定类型的请求(如GET、POST等),并根据请求执行相应的操作,下面来编写一个类视图处理请求:

# 在路由时需要使用视图类的as_view方法
from . import views
from django.urls import path


urlpatterns = [
    path("classview", views.MyFirstClassView.as_view())
]

as_view 方法是 Django 类视图(class-based views)中一个重要的方法,其作用是将类视图转换为函数视图,以便它们可以在URL配置中使用。类视图通过 as_view 方法提供了一种便捷的方式来处理不同的HTTP请求方法(如GET、POST等)

class MyFirstClassView(View):
    def get(self, request: HttpRequest) -> HttpResponse:
        return HttpResponse("The Method is GET") 
    
    def post(self, request: HttpRequest) -> HttpResponse:
        return HttpResponse("The Method is POST") 

访问视图得到以下内容:

(.venv) r123@localhost:~/DjamgoTestProject$ curl -X GET "http://127.0.0.1:8000/myfirstapp/classview"
The Method is GET
(.venv) r123@localhost:~/DjamgoTestProject$ curl -X POST "http://127.0.0.1:8000/myfirstapp/classview"
The Method is POST

而在源码层面,Django使用了反射来动态处理类视图请求处理的方法:

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = [
        "get",
        "post",
        "put",
        "patch",
        "delete",
        "head",
        "options",
        "trace",
    ]
    ...
        def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(
                self, request.method.lower(), self.http_method_not_allowed
            )
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
    ...

自定义简易中间件

在Django中所谓的中间件实质上是一个又一个子应用,在收到请求时优先对请求进行预处理,由于篇幅,讨论一个完整的中间件包是不太合适的,我们可以定义一个闭包来实现我们的中间件功能:

from typing import Callable
from django.http import HttpRequest, HttpResponse

def custom_middleware(get_response: Callable[[HttpRequest], HttpResponse]) -> (
        Callable[[HttpRequest], HttpResponse]):
    
    print("自动调用中间件请求处理前逻辑")
    
    def middleware(request: HttpRequest) -> HttpResponse:
        print("中间件处理请求前的逻辑")
        response = get_response(request) # 处理请求的视图调用
        print("中间件处理响应后的逻辑")
        return response
    
    return middleware

然后注册到中间件中,就实现了一个简单的中间件:

MIDDLEWARE = [
	...
    'myfirstapp.middleware.custom_middleware',
    ...
]

在这里插入图片描述

同样的,我们也可以使用__call__方法来定义一个简易的类中间件:

from typing import Callable
from django.http import HttpRequest, HttpResponse

class CustomMiddleware:
    def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None:
        self.get_response = get_response

    def __call__(self, request: HttpRequest) -> HttpResponse:
        # 中间件处理请求前的逻辑
        response = self.get_response(request)
        # 中间件处理响应后的逻辑
        return response

模板渲染系统使用

Django模板是Django框架中的一种用于生成HTML的系统。它使用模板语言(Django Template Language, DTL)来动态生成网页。Django模板的核心理念是分离业务逻辑和展示逻辑,使开发者可以更方便地管理和维护代码。首先在setting中配置模板路径:

TEMPLATES = [
    {
		...
        'DIRS': [os.path.join(BASE_DIR, "templates")],
       	...
    },
]

视图上下文传递

模板从视图中传递上下文(context),上下文是一个字典,包含需要在模板中使用的数据

  • 借助Template类进行模板渲染
from django.template import Template, loader

def get_template(request: HttpRequest) -> HttpResponse:
    template: Template = loader.get_template("index.html")
    data: dict = {
        'user1': {
            'name': 'A',
            'age': 28
        },

        'user2': {
            'name': 'B',
            'age': 23
        },
        
        'list_data': [233, 2333, 23333]
    }
    return HttpResponse(template.render(context=data))

  • 直接进行模板渲染
from django.shortcuts import render

def get_template(request: HttpRequest) -> HttpResponse:
    data: dict = {
        'user1_name': 'A',

        'user2': {
            'name': 'B',
            'age': 23
        },
        
        'list_data': [233, 2333, 23333]
    }
    return render(request=request, template_name="index.html", context=data)

模板语法-变量渲染

在django中有两种模板语法,第一种是直接输出数据,类似于变量的方式。当字典中元素的值部分为单独常量时,可直接在模板中填入该元素的键,而值为可迭代类型时,我们则需要使用.来访问对应的索引或键名:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    user1_name: {{ user1_name }}<br/>
    user2_age: {{ user2.age }}<br/>
    list_element0: {{ list_data.0 }}<br/>
    list_element1: {{ list_data.1 }}<br/>
</body>
</html>

我们将会在前端得到渲染后的源代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    user1_name: A<br/>
    user2_age: 23<br/>
    list_element0: 233<br/>
    list_element1: 2333<br/>
</body>
</html>

django的模板语法也支持注释:

{# content #}

模板语法-结构渲染

条件控制结构
  • 基本条件判断

    {% if condition %}
        <!-- 条件为真时显示的内容 -->
    {% endif %}
    
  • else语句

    {% if condition %}
        <!-- 条件为真时显示的内容 -->
    {% else %}
        <!-- 条件为假时显示的内容 -->
    {% endif %}
    
  • elif语句

    {% if condition1 %}
        <!-- 条件1为真时显示的内容 -->
    {% elif condition2 %}
        <!-- 条件2为真时显示的内容 -->
    {% else %}
        <!-- 条件都为假时显示的内容 -->
    {% endif %}
    
循环控制结构

循环语句用于在模板中遍历列表或字典等可迭代对象。Django模板语言提供了{% for %}标签来实现循环。

  • 基本循环

    {% for item in item_list %}
        <!-- 对每个item进行操作 -->
    {% endfor %}
    
  • 循环控制

    • forloop.counter:循环计数,从1开始
    • forloop.counter0:循环计数,从0开始
    • forloop.revcounter:从1开始的倒计数
    • forloop.revcounter0:从0开始的倒计数
    • forloop.first:是否是第一个元素
    • forloop.last:是否是最后一个元素
  • 遍历列表

    <ul>
    {% for item in item_list %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
    
  • 遍历字典

    <ul>
    {% for key, value in my_dict.items %}
        <li>{{ key }}: {{ value }}</li>
    {% endfor %}
    </ul>
    
  • 使用循环控制变量

    <ul>
    {% for item in item_list %}
        <li>{{ forloop.counter }}: {{ item }}</li>
    {% endfor %}
    </ul>
    

模板语法-内容过滤器

Django模板系统提供了许多内置的过滤器,可以让我们在模板中对变量进行简单的操作和格式化。以下是一些常见的过滤器:

  1. date: 格式化日期。

    {{ some_date|date:"Y-m-d" }}
    
  2. time: 格式化时间。

    {{ some_time|time:"H:i" }}
    
  3. default: 如果变量值为空,使用默认值。

    {{ some_variable|default:"默认值" }}
    
  4. length: 返回列表或字符串的长度。

    {{ some_list|length }}
    
  5. lower: 将字符串转换为小写。

    {{ some_string|lower }}
    
  6. upper: 将字符串转换为大写。

    {{ some_string|upper }}
    
  7. join: 将列表连接成字符串,用指定的字符分隔。

    {{ some_list|join:", " }}
    
  8. slice: 对列表或字符串进行切片。

    {{ some_list|slice:":3" }}
    
  9. first: 返回列表或字符串的第一个元素。

    {{ some_list|first }}
    
  10. last: 返回列表或字符串的最后一个元素。

    {{ some_list|last }}
    
  11. striptags: 去除字符串中的HTML标签。

    {{ some_html_string|striptags }}
    
  12. escape: 对字符串进行HTML转义。

    {{ some_string|escape }}
    
  13. linebreaks: 将换行符转换为<p><br>标签。

    {{ some_text|linebreaks }}
    
  14. urlencode: 对字符串进行URL编码。

    {{ some_string|urlencode }}
    
  15. capfirst: 将字符串的首字母大写。

    {{ some_string|capfirst }}
    
  16. wordcount: 计算字符串中的单词数。

    {{ some_string|wordcount }}
    
  17. pluralize: 根据变量的值决定单复数形式。

    {{ some_number|pluralize:"项,项" }}
    
  18. add: 将数字相加。

    {{ some_number|add:5 }}
    
  19. default_if_none: 如果变量值为None,使用默认值。

    {{ some_variable|default_if_none:"默认值" }}
    
  20. empty:用于判断一个变量是否为空。

    {% if some_variable|empty %}
        <p>变量为空</p>
    {% else %}
        <p>变量不为空</p>
    {% endif %}
    

    empty常用于与for循环联动

    <ul>
     {% for item in item_list %}
         <li>{{ item }}</li>
     {% empty %}
         <li>没有内容</li>
     {% endfor %}
    </ul>
    
  21. safe:用于标记字符串为安全的HTML,防止自动转义

    <p>{{ html_content|safe }}</p>
    

模板语法-模板继承

Django的模板继承是一种强大的机制,可以在构建网页时复用HTML代码。模板继承允许创建一个基础模板,然后在此基础上创建更具体的模板,从而减少重复代码,提高代码的可维护性和可读性。模板继承通过{% block %}标签和{% extends %}标签来实现:

  • {% block %}:定义一个可被子模板重载的可扩展区域。
  • {% extends %}:指示该模板继承自另一个模板。
创建基础模板

首先,我们需要创建一个基础模板,通常包含网站的通用结构,比如头部、导航栏和页脚。示例代码如下:

<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}我的网站{% endblock %}</title>
</head>
<body>
    <header>
        <h1>我的网站</h1>
    </header>
    <nav>
        <!-- 导航栏内容 -->
    </nav>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>
        <p>版权所有 &copy; 2024</p>
    </footer>
</body>
</html>

在这个基础模板中,定义了两个可扩展的块:titlecontent

创建子模板

接下来,创建一个子模板,它将继承基础模板,并提供具体的内容:

<!-- home.html -->
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
    <h2>欢迎来到我的网站</h2>
    <p>这是首页的内容。</p>
{% endblock %}

在这个子模板中,通过{% extends "base.html" %}指示继承自base.html。然后,使用{% block %}标签重载基础模板中的titlecontent块。

块的灵活重载

我们可以在基础模板中定义多个块,然后在子模板中选择性地重载这些块。示例如下:

<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}我的网站{% endblock %}</title>
    {% block extra_head %}{% endblock %}
</head>
<body>
    <header>
        <h1>我的网站</h1>
    </header>
    <nav>
        <!-- 导航栏内容 -->
    </nav>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>
        <p>版权所有 &copy; 2024</p>
    </footer>
    {% block extra_foot %}{% endblock %}
</body>
</html>
<!-- about.html -->
{% extends "base.html" %}

{% block title %}关于我们 - 我的网站{% endblock %}

{% block content %}
    <h2>关于我们</h2>
    <p>这是关于我们的页面内容。</p>
{% endblock %}

{% block extra_foot %}
    <script src="path/to/extra/script.js"></script>
{% endblock %}

在这个例子中,基础模板中定义了extra_headextra_foot块,子模板可以选择性地重载这些块以添加额外的头部或脚部内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

幼儿园管理系统-收退费管理原型模版

幼儿园管理系统是专为幼儿园打造&#xff0c;涵盖学校儿童、职工人事、收费财务、后勤管理、办公教务、膳食分析、体检保健、文档管理等各方面内部管理的幼儿园专家系统。 本次分享给大家的是雅居乐教育集团幼儿园园务管理系统中“收退费管理”模块的设计文档。收退费管理是幼儿…

报错:c2665 ”loadimage“没有重载函数可以转换所有参数类型

解决方法: 右键项目选择属性-》高级-》字符集-》使用多字节字符集-》确定

IO多路复用模型原理

在linux没有实现epoll事件驱动机制之前,常规的手段是选择select和poll等IO多路复用的方法来实现并发服务程序。但是在大数据、高并发、集群情况下,select和poll的性能瓶颈就出现了,于是epoll就诞生了 Select select函数监视的文件描述符分三类:writefds、readfds和exceptf…

国内首个智能体生态大会!2024百度万象大会定档5月30日

最近&#xff0c;百度悄悄「上新」了几个AI神器。 百度搜索上线「互动」功能&#xff0c;可以实时问答&#xff0c;查询信息就像聊天一样简单&#xff0c;还可以艾特相关智能体&#xff0c;更细致精确地满足个性化需求&#xff0c;比如去新加坡旅游&#xff0c;可以让新加坡旅…

【源码】2024心悦搜剧源码百万级网盘资源

1、一键转存他人链接&#xff1a;就是将别人的分享链接转为你自己的 2、转存心悦搜剧资源&#xff1a;就是将心悦搜剧平台上的所有资源都转成你自己的 3、每日自动更新&#xff1a;自动转存每天的资源并入库 前端uin-app&#xff0c;后端PHP&#xff0c;兼容微信小程序

必看!企业数字化转型的组织架构与人员配置方案!

数字化浪潮汹涌而来&#xff0c;企业如何在这波大潮中破浪前行&#xff1f;关键在于构建合理的组织架构和配备合适的人员&#xff01;今天&#xff0c;我们就为大家带来蚓链实践经验总结的方案&#xff0c;让你的企业数字化转型之路更加顺畅&#xff01; 组织架构&#xff1a; …

【数学建模】碎纸片的拼接复原

2013高教社杯全国大学生数学建模竞赛B题 问题一模型一模型二条件设立思路 问题求解 问题一 已知 d i d_i di​为第 i i i张图片图片的像素矩阵 已知 d i d_i di​都是 n ∗ m n*m n∗m二维矩阵 假设有 N N N张图片 模型一 我们认为对应位置像素匹配为 d i [ j ] [ 1 ] d k…

引入安全生产培训云平台,实现“人人讲安全、个个会应急”

引入安全生产培训云平台&#xff0c;旨在全面提升企业及员工的安全意识与应急处理能力&#xff0c;通过数字化手段实现“人人讲安全、个个会应急”的目标。这一平台的构建和应用&#xff0c;不仅促进了安全知识的普及&#xff0c;还极大提高了培训的效率与效果。以下是该平台几…

【赠书第24期】Java项目开发实战(微视频版)

文章目录 前言 1 项目选择与需求分析 1.1 项目选择 1.2 需求分析 2 系统设计 2.1 系统架构设计 2.2 数据库设计 2.3 接口设计 3 编码实现 3.1 环境搭建 3.2 编码规范 3.3 编码实现 4 测试与部署 4.1 单元测试 4.2 系统测试 4.3 部署与上线 5 总结与展望 6 推…

挖矿宝藏之系统日志

什么是日志&#xff1f; 日志是指系统或应用程序在运行过程中产生的记录文件&#xff0c;这些文件记录了系统或应用程序的运行情况、错误信息、用户操作等。 日志的主要作用 记录信息&#xff1a;日志可以记录系统或应用程序的启动、运行、停止等状态信息&#xff0c;以及用户的…

262 基于matlab的一级倒立摆仿真

基于matlab的一级倒立摆仿真&#xff0c;在对一级倒立摆进行数学建模的基础上&#xff0c;对模型进行线性化&#xff0c;得到其状态空间模型&#xff0c;利用二次型最优控制方法得出控制率。输出角度和位置优化曲线。程序已调通&#xff0c;可直接运行。 262 一级倒立摆仿真 状…

adb环境搭建

1.安装jdk adb正常使用的前提条件&#xff1a;安装jdk&#xff0c;网上很多可以找找&#xff0c;或者翻翻之前记录的。 2.安装adb 2.1.下载Android_sdk 通过网盘下载&#xff0c;网盘链接&#xff1a;https://pan.baidu.com/s/1r4Y_2-nkKs2a2h9mdrueWg&#xff0c;e5wv。下载成…

关系代数、函数依赖、Armstrong公理及软考试题解析

注&#xff1a;本文面向于软考高级—系统架构设计师&#xff0c;具体来说是数据库部分&#xff0c;知识点偏零碎化。想要系统学习数据库原理的&#xff0c;可考虑去看《数据库原理》&#xff0c;清华大学出版社或其他出版社皆可。 概述 概念 关系&#xff0c;就是二维表。特…

2024年上半年软件设计师试题及答案(回忆版)

目录 基础知识选择题案例题1.缺陷识别的数据流图2.球队、球员、比赛记录的数据库题3.用户、老师、学生、课程用例图4.算法题5.程序设计题 基础知识选择题 树的节点&#xff0c;度为4的有4个&#xff0c;度为3的有8个&#xff0c;度为2个有6个&#xff0c;度为1的有10个&#x…

spring boot整合j2cache 配置项目全局键标识 帮助定位是哪个项目产生的缓存

我们利用 j2cache 存进 redis的缓存 key 可以加个全局标识 这样 到时看缓存 方便别人看是哪个项目存进去的 例如 这里 我们存入的 book 我们 keys * 查看 就知道是个book 但不知道具体来自那套系统 我们在 j2cache.properties 中加上 redis.namespace 项目全局键标识 我们…

【方法】ZIP压缩文件的密码如何设置和取消?

ZIP是一种常见的压缩文件格式&#xff0c;今天来分享一下&#xff0c;ZIP压缩文件如何设置密码保护&#xff0c;以及如何取消密码&#xff0c;不清楚的小伙伴一起来看看吧&#xff01; 设置ZIP文件密码&#xff1a; 想要给ZIP压缩包设置密码&#xff0c;需要用到支持ZIP格式的…

移动云主机ECS搭建Kubernetes集群:详细步骤与指南

目录 云主机 ECS&#xff1a;云计算的强大引擎什么是云主机ECS&#xff1f;为何选择云主机ECS&#xff1f; 使用移动云ECS进行Kubernetes集群搭建1. 环境准备2. 安装步骤2.1 在每一个节点上执行的操作2.1.1 系统准备2.1.2 安装Docker2.1.3 安装Kubernetes的安装组件 2.2 在Mast…

一篇文章讲透排序算法之堆排序

1.前言 在学习这篇文章之前&#xff0c;请大家先学习堆这一数据结构中堆的概念&#xff0c;向下调整算法&#xff0c;向下调整建堆。 有关堆的实现方式请参考&#xff1a;堆的实现 堆排序就是利用堆里面学习过的知识点进行排序&#xff0c;如何进行排序呢&#xff1f; 2.堆…

linux centos nginx配置浏览器访问后端(tomcat日志)

1、配置nginx访问tomcat日志路径 vim /usr/local/nginx/conf/nginx,conflocation ^~ /logs {autoindex on;autoindex_exact_size on;autoindex_localtime on;alias /home/tomcat/apache-tomcat-9.0.89-1/logs;}###配置讲解### 1、location ^~ /logs { … }: location&#xf…

抖音IP地址频繁变动:背后的原因与解读

在抖音这个短视频平台的日常使用中&#xff0c;不少用户可能注意到了自己的IP地址有时会频繁变动。这种现象不仅引起了用户的好奇&#xff0c;也引发了关于个人隐私、账号安全以及平台政策的一系列讨论。那么&#xff0c;抖音IP地址换来换去什么意思&#xff1f;这背后又隐藏着…