【Django入门】——模型管理器对象、模型管理器类和模型类

在文章【Django入门】——Django中通过模型类实现数据表基本操作中,我们知道通过模型类操作数据表时,一般的语法为模型类.objects.方法名(如:all()get()filter()等)。你是否想过objects到底是什么?

一、模型管理器对象

实际上,objects是所谓的模型管理器对象,Django为每一个模型类都生成了一个objects对象作为其类属性,用于操作模型类对应的数据表。

为了演示方便,我们还以文章【Django入门】——通过模型类查询MySQL数据库基本操作中的项目做案例来演示:

$ python manage.py shell
>>> from booktest.models import BookInfo, HeroInfo
>>> type(BookInfo.objects)
<class 'django.db.models.manager.Manager'>
>>> type(HeroInfo.objects)
<class 'django.db.models.manager.Manager'>

由上述代码运行可知,不管是模型类BookInfo还是HeroInfo,其objects对象都是django.db.models.manager.Manager类的一个对象。

1. 自定义模型管理器对象

既然objects只不过是作为模型类的类属性,且是Manager类的一个对象,那么开发者必然可以自定义模型管理器对象,如下列代码所示:

from django.db import models


# Create your models here.
class BookInfo(models.Model):
    """图书模型类"""
    book_title = models.CharField(max_length=20)  # 图书名称
    book_pub_date = models.DateField()  # 出版日期
    book_read = models.IntegerField(default=0)  # 阅读量,默认为0
    book_comment = models.IntegerField(default=0)  # 评论量,默认为0
    is_delete = models.BooleanField(default=False)  # 软删除标记,默认不删除
    books = models.manager.Manager()  # 自定义一个管理器对象

如下列代码所示,当开发者为模型类自定义一个管理器对象时,此时用于操作数据表的管理器对象就发生了改变:

$ python manage.py shell
>>> from booktest.models import BookInfo
>>> BookInfo.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: type object 'BookInfo' has no attribute 'objects'
>>> BookInfo.books.all()
<QuerySet [<BookInfo: BookInfo object (1)>, <BookInfo: BookInfo object (2)>, <BookInfo: BookInfo object (3)>, <BookInfo: BookInfo object (4)>]>

2. 自定义模型管理器类

实际上,在模型类中通过models.manager.Manager类来自定义模型管理器对象的意义不大,更加有意义的是自定义模型管理器类,在类中进行个性化操作,然后利用该自定义模型管理器类在模型类中创建对象,便可以达到一些想要的效果(如:重写框架的方式、添加自定义方法等):

from django.db import models


class BookInfoManager(models.manager.Manager):  # 1.自定义图书模型管理器类
    """图书模型管理器类"""
    pass


# Create your models here.
class BookInfo(models.Model):
    """图书模型类"""
    book_title = models.CharField(max_length=20)  # 图书名称
    book_pub_date = models.DateField()  # 出版日期
    book_read = models.IntegerField(default=0)  # 阅读量,默认为0
    book_comment = models.IntegerField(default=0)  # 评论量,默认为0
    is_delete = models.BooleanField(default=False)  # 软删除标记,默认不删除
    objects = BookInfoManager()  # 2.自定义一个BookInfoManager类的对象

下列代码显示,此时BookInfoobjects属性即创建于自定义的模型管理器类:

$ python manage.py shell
>>> from booktest.models import BookInfo
>>> type(BookInfo.objects)
<class 'booktest.models.BookInfoManager'>

3. 自定义模型管理器类应用

那么,自定义模型管理器类究竟可以实现什么功能呢?下面是其可以实现的两大主要功能:

3.1 重写框架的方法

假设现在有这样一个需求:要求通过BookInfo.objects.all()查询出来的记录中,剔除is_delete字段为True即为1的记录。为了演示方便,下面先将BookInfo对应的数据表中id为4的记录的is_delete字段置为1:

mysql> use db4_test3;
Database changed
mysql> select * from booktest_bookinfo;
+----+-----------------+---------------+-----------+--------------+-----------+
| id | book_title      | book_pub_date | book_read | book_comment | is_delete |
+----+-----------------+---------------+-----------+--------------+-----------+
|  1 | 射雕英雄传      | 1980-05-01    |        12 |           34 |         0 |
......
|  4 | 雪山飞狐        | 1987-11-11    |        58 |           24 |         0 |
+----+-----------------+---------------+-----------+--------------+-----------+
4 rows in set (0.00 sec)

mysql> update booktest_bookinfo set is_delete=1 where id=4;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from booktest_bookinfo;
+----+-----------------+---------------+-----------+--------------+-----------+
| id | book_title      | book_pub_date | book_read | book_comment | is_delete |
+----+-----------------+---------------+-----------+--------------+-----------+
......
|  4 | 雪山飞狐        | 1987-11-11    |        58 |           24 |         1 |
+----+-----------------+---------------+-----------+--------------+-----------+
4 rows in set (0.00 sec)

那么,实现上述需求的方法可以是:在继承了models.manager.Manager类的自定义模型管理器类中重写all()方法:

from django.db import models


class BookInfoManager(models.manager.Manager):
    """图书模型管理器类"""
    # 1.改变查询的结果集
    def all(self):
        # 1.1 调用父类的all(),获取所有数据集
        books = super().all()
        # 1.2 对数据进行过滤
        books = books.filter(is_delete=False)
        # 1.3 返回过滤结果
        return books

由下述代码可知,通过BookInfo.objects.all()进行查询时,的确剔除了字段is_delete取值为1的记录:

$ python manage.py shell
>>> from booktest.models import BookInfo
>>> type(BookInfo.objects)
<class 'booktest.models.BookInfoManager'>
>>> books = BookInfo.objects.all()
>>> for book in books:
...     print(book.id)
... 
1
2
3

3.2 封装自定义方法

在文章【Django入门】——Django中通过模型类实现数据表基本操作中,我们知道:每次通过模型类向其对应数据表中插入数据要经过以下几步:

  • 创建模型类对象;
  • 通过模型类对象.类型=字段值的方式为每一个字段赋值;
  • 调用save()方法将数据插入数据表。

事实上,可以如下所示在自定义模型管理器中封装自定义create_book()方法来实现:

from django.db import models


class BookInfoManager(models.manager.Manager):  # 1.自定义图书模型管理器类
    """图书模型管理器类"""

    # 1.重写框架的方法
	# ......

    # 2.封装自定义方法:直接操作模型类对应的数据表(增删改查)
    def create_book(self, book_title, book_pub_date):
        # 2.1 创建一个图书对象
        book = BookInfo()
        book.book_title = book_title
        book.book_pub_date = book_pub_date
        # 2.2 保存数据进数据库
        book.save()
        # 2.3 返回book对象
        return book

通过下列代码可使用上述自定义的create_book()方法向数据表中插入记录:

>>> from booktest.models import BookInfo
>>> book = BookInfo.objects.create_book('鹿鼎记', '1972-9-1')
>>> book.book_title
'鹿鼎记'
>>> book.book_pub_date
'1972-9-1'

查询数据表可知,记录的确被插入了表中:

mysql> select * from booktest_bookinfo;
+----+-----------------+---------------+-----------+--------------+-----------+
| id | book_title      | book_pub_date | book_read | book_comment | is_delete |
+----+-----------------+---------------+-----------+--------------+-----------+
......
|  5 | 鹿鼎记          | 1972-09-01    |         0 |            0 |         0 |
+----+-----------------+---------------+-----------+--------------+-----------+
5 rows in set (0.00 sec)

实际上,通过模型类对数据表的增删改查的操作都可以像上面一样封装成方法使用。

需要指出的是,models.manager.Manager中封装了一个create()方法,其实现的功能和上述create_book()方法基本一致:

>>> book = BookInfo.objects.create(book_title='白马啸西风', book_pub_date='1961-11-1')
>>> book
<BookInfo: BookInfo object (6)>

只是需要说明的是,调用create()方法传参时必须使用关键字参数传参方式。

mysql> select * from booktest_bookinfo;
+----+-----------------+---------------+-----------+--------------+-----------+
| id | book_title      | book_pub_date | book_read | book_comment | is_delete |
+----+-----------------+---------------+-----------+--------------+-----------+
......
|  6 | 白马啸西风      | 1961-11-01    |         0 |            0 |         0 |
+----+-----------------+---------------+-----------+--------------+-----------+
6 rows in set (0.00 sec)

4. 模型管理器对象的model属性

上述代码的create_book()方法中显式使用模型类BookInfo创建了对象,假如修改了模型类的名字,则需要在这里同步进行修改,十分不方便。

实际上,模型管理器对象都有一个名为model的属性,该属性即代表了模型管理器对象当前所在的模型类。

即下列代码中的book = self.model()等价于book = BookInfo()

class BookInfoManager(models.manager.Manager):
    """图书模型管理器类"""

    # 1.重写框架的方法
	......

    # 2.封装自定义方法
    def create_book(self, book_title, book_pub_date):
        # 2.1 创建一个图书对象
        book = self.model()
        book.book_title = book_title
        book.book_pub_date = book_pub_date
        # 2.2 保存数据进数据库
        book.save()
        # 2.3 返回book对象
        return book

二、模型类和模型管理类

模型类、模型管理器、模型管理器对象的关系如下图所示:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_37780776/article/details/107647259