[实验] Django 自定义查询 (通过自定义 manager 管理器实现)

注意:

文中的 python 系统名、mysite 项目、user 应用和 Student 类只是站主在本次操作中随意取的名称,读者可以根据自己的喜好换成任意别的名称

正文:

步骤一:系统环境要求

(1)服务器的系统需要是 openSUSE 15.2 版本
(2)服务器要关闭防火墙
(3)服务器系统要配置好可用的软件源(最好是软件数量最多的官方版本)
(4)服务器要能够连接外网

步骤二:安装 Django

2.1 安装 Python3

[root@python ~]# zypper -n install python3

2.2 创建并进入 Django 项目的目录

[root@python ~]# mkdir project
[root@python ~]# cd project

2.3 将 Django 项目的目录指定为 Django 环境

[root@python project]# python3 -m venv django_env

2.4 进入 Django 环境

[root@python project]# source django_env/bin/activate
(django_env) [root@python project]# pip install django

(补充:在此次操作发生时,最新的 Django 版本是 3.2)

步骤三:创建 mysite 项目

3.1 创建 mysite 项目

(django_env) [root@python project]# django-admin startproject mysite

3.2 mysite 项目的目录

3.2.1 安装 tree 目录显示软件
(django_env) [root@python project]# zypper -n install tree
3.2.2 显示 mysite 项目的目录
(django_env) [root@python project]# cd mysite
(django_env) [root@python mysite]# tree
.
├── manage.py
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 5 files
3.2.3 Django 项目目录介绍

(1)mysite 此 Django 项目的容器
(2)manage.py 命令行工具,与 Django 项目进行交互
(3)mysite/__init__.py 空文件,通知 Python 此项目是 1 个 Python 包
(4)mysite/settings.py 此 Django 项目的配置文件
(5)mysite/urls.py 此 Django 项目的 URL 声明和 Django 的网站“目录”
(6)mysite/wsgi.py WSGI 兼容 Web 服务器的入口

步骤四:创建 test 应用

4.1 创建 test 应用

(django_env) [root@python mysite]# django-admin startapp test

4.2 test 应用的目录

4.2.1 显示 test 应用的目录
(django_env) [root@python mysite]# tree
.
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── test
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

3 directories, 13 files
4.2.2 Django 应用目录介绍

(1)test/app.py 此 Django 应用的容器
(2)test/__init__.py 空文件,通知 Python 此项目是 1 个 Python 包
(3)test/admin.py 此 Django 应用自带的后台管理相关的类
(4)test/app.py 此 Django 应用指定应用名的文件
(5)test/migrations.py 此 Django 应用通过 python 代码生成数据库表时里面会产生一些迁移文件
(6)test/models.py 可以在里面创建一些 Python 对象并通过这些对象在数据库里创建对应的表
(7)test/test.py 此 Django 应用的测试文档
(8)test/views.py 此 Django 应用的视图,接收前端数据,把数据传递给后端,响应相关页面

4.3 在 mysite 应用中导入 test 应用

在 mysite/mysite/settings.py 中添加以下内容:

......
INSTALLED_APPS = [
......
    'test',
]
......

步骤五:实现连接 MariaDB 数据库

5.1 安装 MairaDB 数据库和客户端

(django_env) [root@python mysite]# zypper -n install mariadb mariadb-devel mariadb-server mariadb-client

5.2 创建用于 Django 的 MairaDB 的库和用户

5.2.1 进入 MairaDB 数据库
(django_env) [root@python mysite]# mysql -h 127.0.0.1 -p
5.2.2 创建用于 Django 的库
MariaDB [(none)]> create database user;

(补充:这里以创建 user 库为例)

5.2.3 创建用于 Django 的用户
MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

(补充:这里以创建 root 用户,密码是 password 为例)

5.2.4 刷新权限
MariaDB [(none)]> flush privileges;

5.3 退出 MariaDB 数据库

MariaDB [(none)]> exit

5.4 重启 MariaDB

(django_env) [root@python mysite]# systemctl restart mariadb

步骤六:搭建用于 Django 的 MariaDB 数据库环境

6.1 安装 Django 连接 MariaDB 的模块

(django_env) [root@python mysite]# pip3 install hexdump
(django_env) [root@python mysite]# pip3 install pymysql

6.2 在 mysite 应用中添加 Django 连接 MariaDB 的模块

在 mysite/mysite/__init__.py 中添加以下内容:

import pymysql
pymysql.install_as_MySQLdb()

6.3 在 test 应用数据库模板中添加 Student 类

在 mysite/test/models.py 中添加以下内容:

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

(补充:这里以创建包含 sname 字段和 isdelete 字段的 Student 类为例)

6.4 在 mysite 应用中设置连接到 MariaDB 数据库

将 mysite/mysite/settings.py 中的以下内容:

......
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
......

修改为:

......
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'password',
    }
}
......


补充:这里以
(1)使用的库是 test
(2)使用的服务器是 127.0.0.1
(3)使用的端口是 3306
(4)使用的用户是 root
(5)使用的密码是 password
为例

6.5 生成牵引文件

(django_env) [root@python mysite]# python3 manage.py makemigrations
Migrations for 'user':
  user/migrations/0001_initial.py
    - Create model Student

6.6 将牵引文件导入 MariaDB 数据库

(django_env) [root@python mysite]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, user
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
  Applying user.0001_initial... OK

步骤七:插入测试数据

7.1 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *

7.2 插入测试数据

>>> Student.objects.create(sname='zhangsan')
<Student: Student object (1)>

>>> Student.objects.create(sname='lisi',isdelete=True)
<Student: Student object (2)>

>>> Student.objects.create(sname='wangwu',isdelete=True)
<Student: Student object (3)>

(补充:这里以往 Student 类任意插入三条测试数据为例)

7.3 退出相应的 Django 环境

>>> quit();

步骤八:正常查询数据

8.1 进入相应的 Django 环境

(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *

8.2 正常查询数据

>>> Student.objects.all()
<QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>]>

(补充:此时会一次性查询出 Student 类里所有的数据)

8.3 退出相应的 Django 环境

>>> quit();

步骤九:通过自定义 manager 管理器查询数据

9.1 自定义 manager 管理器(通过重写父类的 all 实现)

9.1.1 自定义 1 个查询 isdelete=True 数据的 manager 管理器
9.1.1.1 创建 1 个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)
......

修改为:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......


补充:
(1)self 在 python 中代表当前对象,在其他语言中,会用 this 来代表当前对象
(2)这里以将父类的 all 重写成只选择 isdelete=True 数据的 CustomManager(Manager) 类并在 Student 类中使用 objects 调用为例

9.1.1.2 进入相应的 Django 环境
(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *
9.1.1.3 通过自定义 manager 管理器查询数据
>>> Student.objects.all()
<QuerySet [<Student: student:True>, <Student: student:True>]>

(补充:这里只查出了 isdelete=True 的数据)

9.1.1.4 退出相应的 Django 环境
>>> quit();
9.1.2 自定义 1 个查询 isdelete=False 数据的 manager 管理器
9.1.2.1 创建 1 个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

修改为:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)

class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

(补充:这里以添加一个将父类的 all 重写成只选择 isdelete=False 数据的 NotDeletedManager(Manager) 对象并在 Student 类中使用 show 调用为例)

9.1.2.2 进入相应的 Django 环境
(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *
9.1.2.3 通过自定义 manager 管理器查询数据
>>> Student.show.all()
<QuerySet [<Student: student:False>]>

(补充:这里只查出了 isdelete=False 的数据)

9.1.2.4 退出相应的 Django 环境
>>> quit();

9.2 自定义 manager 管理器(通过重写继承的子类 get_queryset 实现)

9.2.1 创建 1 个自定义 manager 管理器的类

将 mysite/test/models.py 中的以下内容:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)
   
class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

修改为:

......
from django.db.models.manager import Manager

class CustomManager(Manager):
    #def all(self):
    #    return Manager.all(self).filter(isdelete=True)

    def get_queryset(self):
        return Manager.get_queryset(self).filter(isdelete=True)

class NotDeletedManager(Manager):
    def all(self):
        return Manager.all(self).filter(isdelete=False)
   
class Student(models.Model):
    sname = models.CharField(max_length=30)
    isdelete = models.BooleanField(default=False)

    objects = CustomManager()

    show = NotDeletedManager()

    def __str__(self):
        return u'student:%s'%self.isdelete
......

(补充:这里以添加一个将子类的 get_queryset 重写成只选择 isdelete=True 数据的 CustomManager(Manager) 对象并在 Student 类中使用 objects 调用为例)

9.2.2 进入相应的 Django 环境
(django_env) [root@python mysite]# python3
>>> import os,django
>>> os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
'mysite.settings'
>>> django.setup()
>>> from test.models import *
9.2.3 通过自定义 manager 管理器查询数据
>>> Student.objects.all()
<QuerySet [<Student: student:True>, <Student: student:True>]>

(补充:这里只查出了 isdelete=True 的数据)

9.2.4 退出相应的 Django 环境
>>> quit();