Django Web框架学习日记

——始于2.10

Django总体流程框架图

(图片出处: Django框架全面讲解 – 小丑进场 – 博客园

Django本身同样也是MVC架构。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),称为 MTV模式。

M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务——如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。

    T 代表模板(Template),即表现层。 该层处理与表现相关的决定—— 如何在页面或其他类型文档中进行显示。

    V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑——可以看作为模型与模板之间的桥梁。

下图为django基本框架:


Django 配置和基础命令

1. 创建一个新的 Django 项目

在当前目录下创建一个名为 project_name 的 Django 项目,使用以下命令:

django-admin startproject project_name

执行完毕后,会生成一个包含以下结构的项目:

project_name/
    manage.py          # 项目管理脚本,用于执行 Django 的各种命令
    project_name/      # 项目目录,包含项目的设置、URL 配置等
        __init__.py    # 一个空文件,标识这是一个 Python 包
        settings.py    # 项目的配置文件
        urls.py        # URL 路由配置
        asgi.py        # ASGI 配置文件(用于异步服务器)
        wsgi.py        # WSGI 配置文件(用于部署)

2. 启动本地开发服务器

进入项目的根目录后,运行以下命令来启动服务器:

python manage.py runserver

默认情况下,Django 服务器会运行在 http://127.0.0.1:8000/ 上。

如果需要指定 IP 和端口,可以这样运行:

python manage.py runserver 0.0.0.0:8080

上述命令会将服务器绑定到所有网络接口(0.0.0.0)并使用端口 8080

3. 创建新的 App 应用

在项目下创建一个名为 app_name 的新的 App 应用:

python manage.py startapp app_name

Django 中的 App 是项目的一个功能模块,例如博客、用户管理等。运行该命令后,会在项目目录中生成以下结构的 App:

app_name/
    migrations/       # 用于存放数据库迁移文件
        __init__.py
    __init__.py       # 标识当前目录为 Python 包
    admin.py          # 用于在 Django 管理后台中注册模型
    apps.py           # App 的配置文件
    models.py         # 定义数据库模型
    tests.py          # 编写测试用例
    views.py          # 处理业务逻辑的视图函数

需要在项目的 settings.py 文件中注册 App,比如添加以下内容:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app_name',  # 添加你的 App
]

4. 数据库操作命令

(1) 同步数据库

在 Django 1.7 及以上版本中,数据库同步分为两步操作:

  1. 创建迁移文件
    每当修改模型文件(models.py)后,需要运行以下命令来生成迁移文件:
   python manage.py makemigrations

该命令会显示并记录所有模型的改动,例如新增字段或表。

  1. 迁移数据库
    使用以下命令将迁移文件的更改应用到数据库中:
   python manage.py migrate
(2) 创建超级管理员

运行以下命令创建管理后台的超级用户:

python manage.py createsuperuser

按照提示输入用户名、电子邮件和密码即可完成创建。

(3) 数据库交互

通过以下命令进入数据库的交互命令行(通常用于调试):

python manage.py dbshell

在此模式下,你可以直接运行 SQL 查询。

数据库连接配置

Django 默认使用 SQLite 数据库,但你也可以配置其他类型的数据库,比如 MySQL、PostgreSQL 或 Oracle。

1. SQLite 默认配置

settings.py 中默认的 SQLite 数据库配置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',  # 使用 SQLite 数据库
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),  # 数据库文件的路径
    }
}

SQLite 是 Django 内部的默认数据库,适合开发阶段使用,无需额外安装数据库服务。

2. MySQL 配置

如果需要使用 MySQL 数据库,首先确保已安装 MySQL 和 pymysql

pip install pymysql

然后在 settings.py 中设置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # 使用 MySQL 数据库引擎
        'NAME': 'dbname',  # 数据库名称(确保数据库使用 UTF-8 编码)
        'USER': 'your_username',  # 数据库用户名
        'PASSWORD': 'your_password',  # 数据库用户密码
        'HOST': '127.0.0.1',  # 数据库主机(本地则为 '127.0.0.1' 或留空)
        'PORT': '3306',  # 数据库端口(MySQL 默认端口为 3306)
    }
}

此外,由于 Django 使用的是 MySQLdb 模块,而在 Python 3 中没有官方支持的 MySQLdb,所以需要使用 pymysql 代替。
在项目的 __init__.py 文件中添加如下代码:

import pymysql
pymysql.install_as_MySQLdb()

3. PostgreSQL 配置

安装 PostgreSQL 和相关驱动:

pip install psycopg2

然后在 settings.py 中设置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',  # 使用 PostgreSQL 数据库引擎
        'NAME': 'app_data',  # 数据库名称
        'USER': 'your_username',  # 数据库用户名
        'PASSWORD': 'your_password',  # 数据库用户密码
        'HOST': '127.0.0.1',  # 数据库主机地址
        'PORT': '5432',  # 数据库端口(PostgreSQL 默认端口为 5432)
    }
}

4. Oracle 配置

如果需要使用 Oracle 数据库,首先安装 Oracle 驱动包 cx_Oracle

pip install cx_Oracle

然后在 settings.py 中设置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',  # 使用 Oracle 数据库引擎
        'NAME': 'xe',  # 数据库名称或服务名
        'USER': 'a_user',  # 数据库用户名
        'PASSWORD': 'a_password',  # 数据库用户密码
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': '1521',  # 数据库端口(Oracle 默认端口为 1521)
    }
}

静态文件配置

1. 静态文件的概念

静态文件指的是前端页面中使用的 CSS、JavaScript 文件、图片等资源。为了方便管理这些文件,可以在项目中设置一个 static 文件夹。

2. 配置方法

在项目根目录下创建一个 static 文件夹,然后在 settings.py 中添加以下配置:

STATIC_URL = '/static/'  # 访问静态文件的 URL 前缀
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),  # 告诉 Django 静态文件所在的目录
)

3. 在模板中使用静态文件

在 HTML 模板中引入静态文件时,需要使用 {% static %} 标签。例如:

{% load static %}
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    <script src="{% static 'js/jquery-1.12.4.js' %}"></script>
</head>
<body>
    <h1>Welcome to Django!</h1>
</body>
</html>

上述代码假设你的 static 目录下有 css/style.cssjs/jquery-1.12.4.js 文件。

Django 路由系统

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的加载是从配置文件中开始。下图为urls.py:

一个正则表达式路由例子:

一个更为常见的路由例子:

Django 二级路由

为什么需要二级路由?

随着项目功能的逐步扩展,urls.py 文件中的 URL 路由规则会变得越来越多。如果所有路由都写在主项目的 urls.py 文件中,不仅难以管理,还会显得冗杂和繁琐。为了解决这一问题,Django 提供了 include 函数,用于拆分路由配置,将不同模块的路由分配到其对应的 App 中,从而形成二级路由结构。

代码示例

一级路由配置(项目根 urls.py)
from django.urls import path, include  # 导入path和include函数

urlpatterns = [
    # 将所有以 "blog/" 开头的 URL 请求交由 blog 应用的二级路由处理
    path('blog/', include('blog.urls')),
]
二级路由配置(App 内 urls.py,例如 blog/urls.py)
from django.urls import path  # 导入path函数
from . import views           # 导入当前 app 的 views 模块

urlpatterns = [
    # 访问 "blog/" 时调用 views.blog_home
    path('', views.blog_home, name='blog_home'),

    # 访问 "blog/post/<post_id>/" 时调用 views.blog_post,并传递 post_id
    path('post/<int:post_id>/', views.blog_post, name='blog_post'),

    # 访问 "blog/author/<author_name>/" 时调用 views.blog_author,并传递 author_name
    path('author/<str:author_name>/', views.blog_author, name='blog_author'),
]
视图函数(App 内 views.py,例如 blog/views.py)
from django.http import HttpResponse  # 导入HttpResponse函数,用于返回响应

# 处理 "blog/" 的视图函数
def blog_home(request):
    return HttpResponse("Welcome to the Blog Home Page!")

# 处理 "blog/post/<post_id>/" 的视图函数
def blog_post(request, post_id):
    return HttpResponse(f"Viewing Post {post_id}")

# 处理 "blog/author/<author_name>/" 的视图函数
def blog_author(request, author_name):
    return HttpResponse(f"Author: {author_name}")

运行逻辑

  1. 当访问 http://127.0.0.1:8000/blog/ 时,匹配到主项目的 urls.py 中的 path('blog/', include('blog.urls')),然后进入 blog 应用的路由规则。
  2. 如果访问的是 http://127.0.0.1:8000/blog/post/1/post/1/ 会匹配到二级路由中的 path('post/<int:post_id>/'),并调用 views.blog_post
  3. 如果访问的是 http://127.0.0.1:8000/blog/author/john/,会匹配到 path('author/<str:author_name>/'),并调用 views.blog_author

Django Views(视图函数)

在 Django 中,视图函数是处理客户端请求的核心逻辑。每个视图函数都会接收一个 HttpRequest 对象,并返回一个 HttpResponse 对象。

1. HttpRequest 对象

HttpRequest 是 Django 自动生成的请求对象,包含所有与 HTTP 请求相关的数据。

常见属性:
  1. path
    请求的 URL 路径,不包括域名部分。
    示例:访问 http://127.0.0.1:8000/blog/post/1/req.path 的值为 /blog/post/1/
  2. method
    请求的 HTTP 方法(如 GETPOST)。可通过 if req.method == "POST": 判断类型。
  3. GET
    包含 URL 中的所有查询参数的类字典对象。
    示例:访问 http://127.0.0.1:8000/search?q=djangoreq.GET['q'] 的值为 django
  4. POST
    包含表单提交的所有数据。只能用于接收请求体中的表单数据。
  5. FILES
    包含上传文件的数据。每个文件以 <input type="file" name="...">name 属性为键。
  6. COOKIES
    以字典形式存储请求中的所有 Cookie。
  7. user
    当前登录的用户对象。如果用户未登录,默认为 AnonymousUser 对象。
    示例:req.user.is_authenticated 可判断用户是否已登录。
  8. META
    包含所有可用的 HTTP 头信息。常见键值:
  • REMOTE_ADDR: 客户端 IP 地址
  • HTTP_USER_AGENT: 用户代理字符串(浏览器信息)
  • HTTP_REFERER: 来源页面的 URL

2. HttpResponse 对象

HttpResponse 是 Django 自动生成的响应对象,用于将处理结果返回给客户端。

视图函数示例:
from django.http import HttpResponse
from django.shortcuts import render, redirect

def index(request):
    # 示例 1: 返回简单的字符串
    return HttpResponse("Hello, Django!")

    # 示例 2: 渲染模板
    # return render(request, "index.html", {"title": "Welcome to Django!"})

    # 示例 3: 重定向到外部页面
    # return redirect("http://www.baidu.com")

3. render() 方法

render 是 Django 提供的快捷方法,用于将请求对象、模板和上下文结合,生成响应页面返回给用户。

示例:

假设 views.py 中定义了以下视图函数:

from django.shortcuts import render

def my_view(request):
    context = {
        'title': 'My Django App',
        'description': 'This is an example page rendered using Django.',
    }
    return render(request, 'myapp/index.html', context)

对应的模板文件 myapp/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
</body>
</html>

访问对应 URL 时,页面会显示如下内容:

<h1>My Django App</h1>
<p>This is an example page rendered using Django.</p>

小知识点:

  • 字典取值方式
    在 Django 模板语言中,字典的取值是通过点操作符,而不是方括号([])。
    例如:context['title'] 在模板中使用时应写为 {{ title }}

通过这些内容,您可以更清楚地理解 Django 的二级路由、视图函数以及模板渲染的核心概念。这种结构化的拆分也能帮助开发者更高效地组织代码。

Django 模型 (Models)

什么是模型?

在 Django 中,模型就是数据库表的抽象表示。每个模型类对应一张数据库表,模型的字段(类属性)对应数据库表中的列。通过模型类,开发者能够以面向对象的方式操作数据库,而无需直接编写 SQL 语句。

模型的基本定义

以下是一个 UserInfo 模型的定义示例:

代码:模型定义

# 导入 Django 的模型模块
from django.db import models

class UserInfo(models.Model):
    """
    UserInfo 模型类,用于表示用户信息。
    """
    # 用户名字段
    name = models.CharField(max_length=30, verbose_name="姓名")
    # 最大长度为 30 字符的字符串字段

    # 用户邮箱字段
    email = models.EmailField(verbose_name="邮箱")
    # EmailField 会验证邮箱格式,且默认最大长度为 254 字符

    # 用户备注字段
    memo = models.TextField(verbose_name="备注")
    # TextField 不限制长度,适合存储大段文本

    def __str__(self):
        """
        定义模型对象的字符串表示(对象转字符串时会调用)。
        """
        return self.name

    class Meta:
        """
        模型的元数据,提供控制模型行为的选项。
        """
        db_table = "userinfo"  # 自定义表名为 "userinfo"
        verbose_name = "用户信息"  # 模型单数名称(后台显示)
        verbose_name_plural = "用户信息列表"  # 模型复数名称
        ordering = ['name']  # 按姓名升序排列

模型对应的数据库表

上述模型会自动生成如下数据库表(使用 SQLite 时为例):

CREATE TABLE userinfo (
    id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自动生成的主键
    name VARCHAR(30) NOT NULL,            -- 用户名字段
    email VARCHAR(254) NOT NULL,          -- 用户邮箱字段
    memo TEXT                             -- 用户备注字段
);
  • id:默认的主键字段,Django 自动生成。
  • nameemailmemo:对应模型中定义的字段。

模型的基本使用

创建数据

from myapp.models import UserInfo

# 方法 1:直接创建并保存
user = UserInfo(name="John", email="[email protected]", memo="Test user")
user.save()

# 方法 2:通过 create 方法
user = UserInfo.objects.create(name="Jane", email="[email protected]", memo="Another user")

查询数据

# 查询单条数据
user = UserInfo.objects.get(id=1)  # 根据主键查询

# 查询所有数据
users = UserInfo.objects.all()

# 筛选数据
users = UserInfo.objects.filter(name="John")  # 查询 name 为 "John" 的用户

# 排序
users = UserInfo.objects.all().order_by('name')  # 按 name 升序

更新数据

# 方法 1:单行更新
user = UserInfo.objects.get(id=1)
user.name = "Updated Name"
user.save()

# 方法 2:批量更新
UserInfo.objects.filter(name="John").update(email="[email protected]")

删除数据

# 删除单条数据
user = UserInfo.objects.get(id=1)
user.delete()

# 删除多条数据
UserInfo.objects.filter(name="John").delete()

字段参数详解

  1. null=True
    数据库字段允许为空(对应数据库中的 NULL 值)。
    示例:email = models.CharField(max_length=100, null=True)
  2. blank=True
    后台表单允许此字段为空。
    示例:email = models.CharField(max_length=100, null=True, blank=True)
  3. primary_key=True
    将该字段设置为主键。默认情况下,Django 会自动生成一个名为 id 的主键。
  4. auto_nowauto_now_add
  • auto_now=True:每次保存时,自动更新为当前时间。
  • auto_now_add=True:只在首次创建时,设置为当前时间。
    示例:created_at = models.DateTimeField(auto_now_add=True)
  1. choices
    限制字段值的选项范围(类似枚举)。
    示例:
   GENDER_CHOICES = (
       ('M', 'Male'),
       ('F', 'Female'),
   )
   gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
  1. default
    设置字段的默认值。
    示例:status = models.CharField(max_length=10, default='active')
  2. unique=True
    确保字段值的唯一性。
    示例:email = models.EmailField(unique=True)
  3. db_index=True
    为字段创建数据库索引以提高查询性能。
  4. verbose_name
    设置字段在管理后台中的显示名称。
  5. help_text
    在后台管理表单中,提供帮助提示信息。

常用字段类型

  • CharField:字符串字段,需要设置 max_length 参数。
  • TextField:长文本字段,无需设置 max_length
  • IntegerField:整数字段。
  • BooleanField:布尔值字段,默认值为 True/False
  • EmailField:邮箱字段,自动验证邮箱格式。
  • DateFieldDateTimeField:日期和日期时间字段。
  • ImageField:用于上传图片,需设置 upload_to 参数指定上传路径。
  • ForeignKey:定义一对多关系。
  • ManyToManyField:定义多对多关系。
  • OneToOneField:定义一对一关系。

连表关系

一对多

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    # `on_delete=models.CASCADE` 表示当关联的 Author 删除时,相关联的 Book 也会被删除。

多对多

class Student(models.Model):
    name = models.CharField(max_length=100)

class Course(models.Model):
    title = models.CharField(max_length=100)
    students = models.ManyToManyField(Student)

一对一

class User(models.Model):
    username = models.CharField(max_length=100)

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField()

增删改查示例

添加数据

Author.objects.create(name="John Doe")
Book.objects.create(title="Book 1", author_id=1)

查询数据

# 获取作者的所有书籍
author = Author.objects.get(id=1)
books = author.book_set.all()

# 获取书籍的作者
book = Book.objects.get(id=1)
author = book.author

删除数据

Author.objects.filter(name="John Doe").delete()

更新数据

Author.objects.filter(name="John Doe").update(name="Jane Doe")

复杂查询

  1. 条件查询:
Book.objects.filter(title__contains="Django")
  1. 范围查询:
Book.objects.filter(id__range=(1, 5))
  1. 排序:
Book.objects.all().order_by('-title')  # 按 title 降序
  1. 聚合:
from django.db.models import Count
Book.objects.values('author').annotate(book_count=Count('id'))

————————————— 2.12 分割线 ——————————————————

Django 文件上传及自定义上传实现

文件上传是 Django 开发中常见的功能场景,以下是自定义文件上传的详细实现及不同形式的实例(普通表单上传和 Ajax 上传)。

自定义文件上传实现(后端)

视图代码

from django.shortcuts import render
from django.http import HttpResponse

def upload_file(request):
    """
    自定义处理文件上传。
    """
    if request.method == "POST":  # 确保只有 POST 请求时执行上传
        # 获取上传的文件对象
        obj = request.FILES.get('fafafa')  # 'fafafa' 是前端表单中 <input type="file" name="fafafa"> 的 name 属性
        if obj:
            # 打开文件并以二进制写入模式保存
            with open(obj.name, 'wb') as f:  
                # 分块读取文件内容,避免一次性读取大文件造成内存溢出
                for chunk in obj.chunks():
                    f.write(chunk)
            return HttpResponse(f"File {obj.name} uploaded successfully!")  # 返回成功消息
        else:
            return HttpResponse("No file selected!")

    return render(request, 'file.html')  # 渲染上传页面

文件上传页面(HTML 表单)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
    <h1>Upload File</h1>
    <form method="post" action="/upload/" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="file" name="fafafa" id="fileInput">
        <button type="submit">Upload</button>
    </form>
</body>
</html>

基于 Django Form 的文件上传

后端代码

Form 定义

使用 Django 的 forms.Form 提供的 FileField,可以更方便地进行文件上传的表单验证。

from django import forms

class FileForm(forms.Form):
    ExcelFile = forms.FileField(label="上传文件")
模型定义

如果需要将上传的文件存储到数据库中,可以通过模型的 FileField 指定存储路径。

from django.db import models

class UploadFile(models.Model):
    userid = models.CharField(max_length=30)  # 用户 ID
    file = models.FileField(upload_to='./upload/')  # 文件存储路径(相对于 MEDIA_ROOT)
    date = models.DateTimeField(auto_now_add=True)  # 文件上传时间
视图定义

在视图中处理文件上传和表单验证:

from django.shortcuts import render
from .forms import FileForm
from .models import UploadFile

def upload_file_form(request):
    """
    基于 Django Form 的文件上传视图。
    """
    if request.method == "POST":
        # 创建表单实例并绑定 POST 数据和文件
        uf = FileForm(request.POST, request.FILES)
        if uf.is_valid():
            # 保存到模型
            upload = UploadFile()
            upload.userid = 1  # 示例用户 ID
            upload.file = uf.cleaned_data['ExcelFile']  # 表单验证后的文件对象
            upload.save()

            # 返回上传文件的路径
            return HttpResponse(f"File uploaded: {upload.file}")

    else:
        uf = FileForm()  # 初始化空表单

    return render(request, 'upload_form.html', {'form': uf})

上传页面(HTML 表单)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
    <h1>Upload File</h1>
    <form method="post" action="/upload_form/" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Upload</button>
    </form>
</body>
</html>

基于 Ajax 的文件上传

后端代码

视图可以重用 upload_file_form 中的逻辑,只需确保返回 JSON 响应。

from django.http import JsonResponse

def upload_file_ajax(request):
    """
    Ajax 文件上传视图。
    """
    if request.method == "POST":
        # 获取上传的文件对象
        obj = request.FILES.get('ExcelFile')
        if obj:
            # 模拟保存文件
            with open(obj.name, 'wb') as f:
                for chunk in obj.chunks():
                    f.write(chunk)
            return JsonResponse({'status': 'success', 'message': f"File {obj.name} uploaded successfully!"})
        else:
            return JsonResponse({'status': 'error', 'message': 'No file selected!'})

    return JsonResponse({'status': 'error', 'message': 'Invalid request method!'})

Ajax 上传页面(HTML 和 JavaScript)

HTML 页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax File Upload</title>
</head>
<body>
    <h1>Ajax File Upload</h1>
    <input type="file" id="fileInput">
    <button id="submitButton">Upload</button>

    <div id="response"></div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="/static/js/upload.js"></script>
</body>
</html>
JavaScript 文件(upload.js
$(document).ready(function () {
    $('#submitButton').on('click', function () {
        // 获取文件对象
        var file = $('#fileInput')[0].files[0];
        if (!file) {
            $('#response').text('No file selected!');
            return;
        }

        // 创建 FormData 对象并附加文件
        var formData = new FormData();
        formData.append('ExcelFile', file);

        // Ajax 请求
        $.ajax({
            url: '/upload_ajax/',  // 后端处理 URL
            type: 'POST',
            data: formData,
            processData: false,  // 不处理文件数据
            contentType: false,  // 不设置默认 Content-Type
            headers: {
                'X-CSRFToken': getCookie('csrftoken')  // Django 的 CSRF 保护
            },
            success: function (response) {
                $('#response').html('<p>' + response.message + '</p>');
            },
            error: function () {
                $('#response').text('Error occurred while uploading!');
            }
        });
    });
});

// 获取 CSRF Token
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

对比

普通表单上传

  • 适合简单的文件上传。
  • 上传后刷新整个页面,用户体验稍差。

基于 Django Form 的上传

  • 能够使用 Django 提供的表单验证功能,更安全、更方便扩展。
  • 结合模型可以直接将文件保存到数据库。

基于 Ajax 的上传

  • 无需刷新页面,用户体验更佳。
  • 适合需要实时响应和多文件上传的场景。

Django 中间件

在django中,中间件其实就是一个类,在请求到来/结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE ( _CLASSES ) 变量,其中每一个元素就是一个中间件。

中间件运行流程示意图:

(图片出处:Django框架全面讲解 – 小丑进场 – 博客园

自定义中间类

Form

Django Form 的作用

  1. 生成 HTML 表单
  • 自动生成表单标签,减少手动编写 HTML 的工作量。
  1. 验证用户输入
  • 提供字段验证功能,确保用户输入符合预期(如数字、邮箱格式等)。
  • 支持自定义验证规则。

Form 示例

代码实现:

# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError

# 自定义字段验证函数
def mobile_validate(value):
    """
    验证手机号码格式
    """
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

# 表单类定义
class PublishForm(forms.Form):
    """
    发布表单类,定义用户输入的字段及验证方式。
    """
    user_type_choice = (
        (0, '普通用户'),
        (1, '高级用户'),
    )

    user_type = forms.IntegerField(
        widget=forms.widgets.Select(choices=user_type_choice, attrs={'class': "form-control"})
    )

    title = forms.CharField(
        max_length=20,
        min_length=5,
        error_messages={
            'required': '标题不能为空',
            'min_length': '标题最少为5个字符',
            'max_length': '标题最多为20个字符'
        },
        widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': '标题5-20个字符'})
    )

    memo = forms.CharField(
        required=False,
        max_length=256,
        widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': '详细描述', 'rows': 3})
    )

    phone = forms.CharField(
        validators=[mobile_validate],
        error_messages={'required': '手机不能为空'},
        widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': '手机号码'})
    )

    email = forms.EmailField(
        required=False,
        error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'},
        widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': '邮箱'})
    )

处理用户提交的表单

视图实现:

import json
from django.http import HttpResponse
from .forms import PublishForm

def publish(request):
    """
    处理用户发布表单的视图
    """
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)  # 绑定用户提交的数据
        if request_form.is_valid():
            # 表单验证通过
            request_dict = request_form.cleaned_data  # 获取清洗后的数据
            print(request_dict)
            ret['status'] = True
        else:
            # 表单验证失败
            error_msg = request_form.errors.as_json()  # 获取错误信息
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))

自动生成 HTML 表单

Django Form 可以自动生成 HTML 表单,同时支持添加样式和验证规则。

表单类:

from django import forms
from app01 import models

class Form1(forms.Form):
    user = forms.CharField(
        widget=forms.TextInput(attrs={'class': 'c1'}),  # 添加 HTML 属性
        error_messages={'required': '用户名不能为空'},  # 自定义错误提示
    )
    pwd = forms.CharField(max_length=4, min_length=2)
    email = forms.EmailField(error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})
    memo = forms.CharField(widget=forms.Textarea())
    user_type_choice = models.BookType.objects.values_list("id", "caption")
    book_type = forms.CharField(widget=forms.widgets.Select(choices=user_type_choice))  # 动态选项

动态联动数据库选项(解决实时更新问题):

def __init__(self, *args, **kwargs):
    super(Form1, self).__init__(*args, **kwargs)
    self.fields['book_type'] = forms.CharField(
        widget=forms.widgets.Select(choices=models.BookType.objects.values_list("id", "caption"))
    )

ModelForm

ModelForm 是 Django 提供的扩展,可以直接从数据库模型自动生成表单,减少重复字段的定义。

示例:

from django import forms
from app01.models import Admin

class AdminModelForm(forms.ModelForm):
    """
    ModelForm 示例
    """
    class Meta:
        model = Admin  # 绑定的模型
        fields = ['username', 'email']  # 指定生成表单的字段
        widgets = {
            'email': forms.PasswordInput(attrs={'class': "form-control"}),  # 自定义字段样式
        }

认证系统(auth)

Django 提供了内置的认证系统(auth 模块),用于管理用户认证、用户权限、用户组和会话。它与 Django 管理后台(admin)集成得很好,可以快速实现用户管理功能。

1. 启用 auth 模块

auth 模块默认启用,无需手动添加。如果没有启用,请确保 INSTALLED_APPS 中包含以下内容:

INSTALLED_APPS = [
    'django.contrib.auth',  # 认证系统
    'django.contrib.contenttypes',  # 依赖组件
    ...
]

2. User 模型

Django 内置了一个用户模型 User,其在数据库中的表名为 auth_user。常用字段和功能包括:

字段名描述
username用户名,必须唯一
password密码(存储的是加密后的 Hash 值)
email电子邮箱
is_active用户是否有效(软删除标志)
is_staff是否有后台管理权限
is_superuser是否是超级管理员
last_login最后一次登录时间
date_joined用户创建时间

3. 新建用户

Django 提供了方便的 API 来创建用户:

from django.contrib.auth.models import User

# 创建新用户
user = User.objects.create_user(username="john", email="[email protected]", password="password123")
user.save()

注意:

  • 密码不会以明文存储在数据库中,而是存储为 Hash 值。

4. 用户认证

可以通过 authenticate 函数验证用户的身份:

from django.contrib.auth import authenticate

user = authenticate(username="john", password="password123")

if user is not None:
    print("认证成功,用户对象为:", user)
else:
    print("认证失败,用户名或密码错误")

注意:

  • authenticate 方法只验证用户名和密码是否正确,不检查 is_active 标志位。

5. 修改密码

用户可以通过以下方式修改密码:

user.set_password("new_password")
user.save()

示例:只有认证后的用户才可以修改密码:

from django.contrib.auth import authenticate

user = authenticate(username="john", password="old_password")
if user is not None:
    user.set_password("new_password")
    user.save()

6. 登录

登录会在 Session 中设置用户的状态:

from django.contrib.auth import login

user = authenticate(username="john", password="password123")
if user is not None:
    if user.is_active:  # 检查用户是否有效
        login(request, user)  # 将用户登录到当前请求
        print("用户已登录")

7. 退出登录

退出登录会清除 Session 中的用户信息:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    return HttpResponse("您已退出登录")

8. 限制访问未登录用户

通过 @login_required 装饰器,可以强制要求用户登录后才能访问某个视图。

from django.contrib.auth.decorators import login_required

@login_required(login_url="/accounts/login/")  # 未登录用户被重定向到此路径
def userinfo(request):
    return HttpResponse("这是用户信息页面")

settings.py 中可以设置默认登录 URL:

LOGIN_URL = "/accounts/login/"  # 全局的未登录重定向路径

跨站请求伪造(CSRF)

CSRF(Cross-Site Request Forgery)是一种攻击方式,通过伪造用户身份发送恶意请求。Django 默认启用了 CSRF 防护,通过中间件实现。

1. 全局启用 CSRF

确保 MIDDLEWARE 中包含以下内容:

MIDDLEWARE = [
    ...,
    'django.middleware.csrf.CsrfViewMiddleware',  # 启用 CSRF 中间件
    ...
]

2. 局部设置 CSRF

  • 强制启用 CSRF: 使用 @csrf_protect 装饰器强制启用 CSRF 防护,即使全局 CSRF 防护未启用。
  from django.views.decorators.csrf import csrf_protect

  @csrf_protect
  def my_view(request):
      ...
  • 禁用 CSRF: 使用 @csrf_exempt 装饰器禁用单个视图的 CSRF 防护。
  from django.views.decorators.csrf import csrf_exempt

  @csrf_exempt
  def my_view(request):
      ...

3. 在模板中使用 CSRF Token

在 HTML 表单中添加 {% csrf_token %}

<form method="post" action="/submit/">
    {% csrf_token %}
    <input type="text" name="name">
    <button type="submit">提交</button>
</form>

4. Ajax 请求中的 CSRF

对于 Ajax 请求,需要手动添加 CSRF Token 到请求头中。

var csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;

function csrfSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

// 示例 Ajax 请求
$.ajax({
    url: "/app01/test/",
    type: "POST",
    data: {id: 1},
    success: function(data) {
        console.log(data);
    }
});

分页

分页是一个常见的功能,Django 提供了内置的分页类,也支持自定义分页逻辑。

1. 内置分页类

视图文件:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

items = list(range(1, 101))  # 示例数据

def index(request):
    page_number = request.GET.get('page', 1)  # 获取当前页码,默认第一页
    paginator = Paginator(items, 10)  # 每页显示 10 条数据

    try:
        page = paginator.page(page_number)
    except PageNotAnInteger:
        page = paginator.page(1)  # 如果页码不是整数,显示第一页
    except EmptyPage:
        page = paginator.page(paginator.num_pages)  # 如果超出页码范围,显示最后一页

    return render(request, "index.html", {"page": page})

模板文件:

<ul>
    {% for item in page %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
    {% if page.has_previous %}
        <a href="?page={{ page.previous_page_number }}">上一页</a>
    {% endif %}
    <span>第 {{ page.number }} 页,共 {{ page.paginator.num_pages }} 页</span>
    {% if page.has_next %}
        <a href="?page={{ page.next_page_number }}">下一页</a>
    {% endif %}
</div>

2. 自定义分页

自定义分页可以通过计算当前页码和数据范围实现。

核心逻辑:

  1. 计算数据的起始索引和结束索引。
  2. 生成分页控件的 HTML。

示例代码已较详细,这里不重复。

Cookie

Django 支持操作客户端 Cookie,用于存储小型会话数据。

1. 获取 Cookie

# 获取 Cookie
value = request.COOKIES.get("key", "默认值")

2. 设置 Cookie

response = HttpResponse("设置 Cookie 示例")
response.set_cookie("key", "value", max_age=3600)  # 设置有效期为 1 小时
return response

加密 Cookie:

response.set_signed_cookie("key", "value", salt="加密盐")

Session

Django 默认支持 Session 功能,用于在请求之间存储用户的会话数据。Django 内置 5 种类型的 Session 存储方式,开发者可以根据需求选择合适的存储方式。

1. 数据库 Session (默认存储)

Django 默认通过数据库 (表 django_session) 存储 Session 数据。

a. 配置
settings.py 中进行如下配置:

# 默认设置,无需修改即可使用
SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # Session 引擎,存储到数据库

SESSION_COOKIE_NAME = "sessionid"          # 浏览器中保存 Session Cookie 的名称,默认是 "sessionid"
SESSION_COOKIE_PATH = "/"                  # Session Cookie 的保存路径,默认是根路径
SESSION_COOKIE_DOMAIN = None               # Session Cookie 的域名,默认是 None(即当前域名)
SESSION_COOKIE_SECURE = False              # 如果为 True,则通过 HTTPS 传输 Cookie
SESSION_COOKIE_HTTPONLY = True             # 如果为 True,则客户端 JavaScript 无法访问 Cookie
SESSION_COOKIE_AGE = 1209600               # Cookie 的过期时间(单位:秒),默认是两周(14 天)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False    # 如果为 True,则关闭浏览器时 Session 过期
SESSION_SAVE_EVERY_REQUEST = False         # 如果为 True,每次请求都会保存 Session

b. 使用
在视图函数中操作 Session:

def index(request):
    # 设置 Session 数据
    request.session['key'] = 'value'  # 设置键值对
    request.session.setdefault('key', 'default_value')  # 如果键不存在,则设置默认值

    # 获取 Session 数据
    value = request.session.get('key', None)  # 获取键的值,若不存在返回 None

    # 删除 Session 数据
    del request.session['key']  # 删除指定 Session 数据
    request.session.flush()  # 清空当前用户的所有 Session 数据

    # 遍历 Session 数据
    keys = request.session.keys()  # 获取所有键
    values = request.session.values()  # 获取所有值
    items = request.session.items()  # 获取键值对

    # 获取当前用户的 session_key
    key = request.session.session_key

    # 检查指定 session_key 是否存在
    exists = request.session.exists('session_key')

    return HttpResponse("Session 操作完成")

2. 缓存 Session

Session 数据存储在缓存中,性能比数据库存储更高。

a. 配置
settings.py 中进行如下配置:

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 使用缓存存储 Session
SESSION_CACHE_ALIAS = 'default'                            # 指定缓存别名

其他配置项与数据库 Session 相同。

b. 使用
与数据库 Session 操作完全相同。

3. 文件 Session

Session 数据存储在文件中。

a. 配置
settings.py 中进行如下配置:

SESSION_ENGINE = 'django.contrib.sessions.backends.file'  # 使用文件存储 Session
SESSION_FILE_PATH = None  # 文件存储路径,默认使用 `tempfile.gettempdir()` 获取临时文件目录

b. 使用
与其他 Session 操作完全相同。

4. 缓存 + 数据库 Session

结合缓存和数据库,缓存用于加速访问,数据库用于数据持久化。

a. 配置
settings.py 中进行如下配置:

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'  # 缓存 + 数据库存储 Session

b. 使用
与其他 Session 操作完全相同。

5. 加密 Cookie Session

Session 数据存储在加密的 Cookie 中。此方式避免了服务器端存储,但性能上可能稍差。

a. 配置
settings.py 中进行如下配置:

SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'  # 使用加密 Cookie 存储 Session

b. 使用
与其他 Session 操作完全相同。

缓存

缓存用于提高动态网站的性能,避免频繁查询数据库。当访问量较大时,缓存可以显著提升响应速度。

Django 提供了 6 种缓存方式:开发调试用缓存、内存缓存、文件缓存、数据库缓存、Memcached (python-memcached) 和 Memcached (pylibmc)。

1. 配置缓存

以下是每种缓存方式的配置:

a. 开发调试用缓存
不实际存储任何缓存数据,适用于调试阶段。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',  # 不存储缓存
    }
}

b. 内存缓存
缓存数据存储在进程内存中,性能高,但数据无法跨进程共享。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',  # 内存缓存的标识
    }
}

c. 文件缓存
缓存数据存储在文件中。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',  # 文件存储路径
    }
}

d. 数据库缓存
缓存数据存储在数据库中。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',  # 数据库表名
    }
}

创建缓存表:

python manage.py createcachetable

e. Memcached(python-memcached 模块)

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',  # Memcached 地址
    }
}

f. Memcached(pylibmc 模块)

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

2. 使用缓存

a. 全局缓存

通过中间件实现全局缓存:

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',  # 请求后更新缓存
    # 其他中间件
    'django.middleware.cache.FetchFromCacheMiddleware',  # 请求前检查缓存
]

CACHE_MIDDLEWARE_SECONDS = 600  # 缓存有效期(秒)
CACHE_MIDDLEWARE_KEY_PREFIX = ''  # 缓存键的前缀

b. 单独视图缓存

为单个视图函数添加缓存:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)  # 缓存 15 分钟
def my_view(request):
    return HttpResponse("这是缓存的内容")

或者在路由中指定:

from django.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/', cache_page(60 * 15)(my_view)),
]

c. 模板部分缓存

在模板中缓存部分内容:

{% load cache %}

{% cache 600 "my_cache_key" %}
    <p>这是缓存的内容。</p>
{% endcache %}

序列化

Django 提供了工具将数据库数据序列化为 JSON、XML 等格式,常用于与客户端的 Ajax 通信。

1. 使用 serializers

from django.core import serializers
from myapp.models import BookType

data = serializers.serialize('json', BookType.objects.all())  # 序列化为 JSON

2. 使用 json.dumps

import json
from myapp.models import BookType

data = list(BookType.objects.all().values('caption'))  # 转换为 QuerySet
json_data = json.dumps(data)  # 序列化为 JSON

处理日期时间字段:

import json
from datetime import datetime, date

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime, date)):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        return super().default(obj)

data = json.dumps(data, cls=CustomJSONEncoder)  # 使用自定义编码器

信号 (Signals)

Django 提供了 “信号调度器” 来解耦框架操作中的事件和处理逻辑。信号允许发送者在某些事件发生时通知接收者 (信号处理函数)。它可以用来在系统的特定时刻执行一些额外的操作。


1. Django 内置信号

Django 提供了丰富的内置信号,以下是常见的信号分类及其触发时机。

a. Model Signals (模型信号)

信号名称触发时机
pre_init模型实例化之前触发
post_init模型实例化之后触发
pre_save模型保存之前触发(save() 方法之前)
post_save模型保存之后触发
pre_delete模型删除之前触发(delete() 方法之前)
post_delete模型删除之后触发
m2m_changed操作多对多字段时触发(addremoveclear
class_preparedDjango 启动时,检测到注册的模型类时触发

b. Management Signals (管理信号)

信号名称触发时机
pre_migrate执行 migrate 命令之前触发
post_migrate执行 migrate 命令之后触发

c. Request/Response Signals (请求/响应信号)

信号名称触发时机
request_started请求到达之前触发
request_finished请求完成之后触发
got_request_exception请求发生异常时触发

d. Test Signals (测试信号)

信号名称触发时机
setting_changed使用测试框架运行时,设置文件发生修改时触发
template_rendered使用测试框架渲染模板时触发

e. Database Wrappers (数据库连接信号)

信号名称触发时机
connection_created创建数据库连接时触发

2. 注册和使用信号

Django 的信号使用步骤如下:

a. 注册信号

使用 Django 内置信号时,需要先定义回调函数 (处理逻辑),然后将其与信号绑定。

示例:

from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
from myapp.models import MyModel

# 定义信号处理函数
@receiver(pre_save, sender=MyModel)
def my_callback(sender, instance, **kwargs):
    print(f"即将保存模型对象: {instance}")

@receiver(post_save, sender=MyModel)
def my_callback_after_save(sender, instance, created, **kwargs):
    if created:
        print(f"新对象已创建: {instance}")
    else:
        print(f"对象已更新: {instance}")

在这个例子中,当 MyModel 的实例被保存时,pre_savepost_save 信号会分别调用回调函数 my_callbackmy_callback_after_save

b. 使用信号

不需要显式触发内置信号,它们会在 Django 执行相应操作时自动调用。

3. 自定义信号

有时你需要定义自己的信号并触发它。

a. 定义信号
使用 django.dispatch.Signal 定义一个信号:

from django.dispatch import Signal

# 自定义信号,定义时可以指定传递的参数
pizza_done = Signal(providing_args=["toppings", "size"])

b. 注册信号

将回调函数与自定义信号绑定:

def handle_pizza_done(sender, **kwargs):
    print("Pizza is done!")
    print(f"Sender: {sender}, Arguments: {kwargs}")

pizza_done.connect(handle_pizza_done)

c. 触发信号

在任意位置触发信号:

# 触发信号
pizza_done.send(sender="Chef", toppings=["pepperoni", "cheese"], size="large")

输出示例:

Pizza is done!
Sender: Chef, Arguments: {'toppings': ['pepperoni', 'cheese'], 'size': 'large'}

Admin 管理后台

Django 提供了一个强大的后台管理页面 (Django Admin),可以快速地对模型数据进行增删改查。以下是使用 Django Admin 的详细步骤和增强技巧。

1. 创建超级用户

超级用户可以登录后台并管理所有内容。

运行以下命令创建超级用户:

python manage.py createsuperuser

输入用户名、邮箱和密码后,超级用户会被创建。

2. URL 配置

默认情况下,Django Admin 的 URL 已配置好。如果没有,请在 urls.py 文件中添加如下代码:

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

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

3. 注册模型到 Admin

admin.py 文件中,通过 admin.site.register 将模型注册到后台管理页面。

from django.contrib import admin
from myapp.models import MyModel

# 注册模型
admin.site.register(MyModel)

注册后,你可以在浏览器中访问 /admin/ 查看和管理该模型的数据。

4. 配置 Admin 显示

Django Admin 提供了多种增强模型展示和管理功能的方法。

a. 修改模型名称显示

在模型的 Meta 类中定义 verbose_nameverbose_name_plural

class MyModel(models.Model):
    name = models.CharField(max_length=50)

    class Meta:
        verbose_name = "我的模型"  # 单数名称
        verbose_name_plural = "我的模型列表"  # 复数名称

b. 自定义列表显示字段
在 Admin 中,默认仅显示模型的 __str__ 方法的返回值。要自定义显示的字段,可在 admin.ModelAdmin 中设置 list_display

class MyModelAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'created_at')  # 指定需要显示的字段

admin.site.register(MyModel, MyModelAdmin)

c. 添加搜索框

为模型添加搜索功能:

class MyModelAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'created_at')
    search_fields = ('name',)  # 在这些字段中搜索

admin.site.register(MyModel, MyModelAdmin)

d. 添加过滤功能

为模型列表添加侧边栏过滤器:

class MyModelAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'created_at')
    list_filter = ('created_at',)  # 按日期过滤

admin.site.register(MyModel, MyModelAdmin)

e. 自定义保存逻辑

重写 save_model 方法可以自定义对象的保存逻辑:

class MyModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        # 在保存前执行一些操作
        print(f"保存的对象: {obj}")
        super().save_model(request, obj, form, change)

f. 自定义操作 (Actions)

可以为模型列表添加批量操作:

class MyModelAdmin(admin.ModelAdmin):
    actions = ['mark_as_published']  # 注册操作

    # 自定义操作
    def mark_as_published(self, request, queryset):
        queryset.update(status='published')
        self.message_user(request, "选中的对象已标记为已发布!")

    mark_as_published.short_description = "标记为已发布"

admin.site.register(MyModel, MyModelAdmin)

5. 美化后台

安装 django-grappellidjango-suit 等第三方库,可以显著提升后台界面的视觉效果和易用性。

pip install django-grappelli

settings.pyINSTALLED_APPS 中添加:

INSTALLED_APPS = [
    'grappelli',
    'django.contrib.admin',
    ...
]

将 URL 配置指向 Grappelli:

urlpatterns = [
    path('grappelli/', include('grappelli.urls')),  # Grappelli 管理页面
    path('admin/', admin.site.urls),
]

访问 /grappelli/ 即可查看美化后的界面。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇