1.自定义管理器(Manager)

在语句Book.objects.all()中,objects是一个特殊的属性,通过它来查询数据库,它就是模型的一个Manager.
每个Django模型至少有一个manager,你可以创建自定义manager以定制数据库的访问.
这里有两个方法创建自定义manager:添加额外的manager;修改manager返回的初始Queryset.

添加额外的manager

增加额外的manager是为模块添加表级功能的首选办法.(至于行级功能,也就是只作用于模型实例对象的函数,则通过自定义模型方法实现).
例如,为Book模型添加一个title_count()的manger方法,它接收一个keyword,并返回标题中包含keyword的书的数量.

models.py

from django.db import models

# 自定义模型管理器类
class BookManager(models.Manager):
#自定义模型管理器中的方法
def title_count(self, keyword):
return self.filter(title_icountains=keyword).count() class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
...
objects = BookManager() def __str__(self):
return self.title

1.我们创建一个BookManager类,继承自django.db.models.Manager.它只有一个方法title_count(),来进行统计.注意,这个方法使用了self.filter(),这个self指manager本身.
2.将BookManager()赋值给模型的objects属性.它将取代模型的默认manager(objects).把它命名为objects是为了与默认的manager保持一致.
现在我们可以进行下面的操作:

>>> Books.objects.title_count('django')    #这是我们自定义的manager中的查询方法
2
>>> Books.objects.filter(title__icontains='django').count() # 默认的查询方法依然可用
2

这样我们可以将经常使用的查询进行封装,就不必重复写代码了.

修改初始Manager Queryset

manager的基础Queryset返回系统中的所有对象.例如,Book.objects.all()返回book数据库中的所有书籍.你而已通过覆盖Manager.get_queryset()方法来重写manager的基础Queryset.get_queryset()应该按照你的需求返回一个Queryset.
例如,下面的模型有两个manger--一个返回所有对象,另一个仅返回作者是Roald Dahl的书

from django.db import models

#首先,定义一个Manager的子类
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl') # 然后,将它显式地插入到Book模型中
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
...
objects = models.Manager() # 默认Manager
dahl_objects = DahlBookManager() # 自定义的特殊Manager

在这个示例模型中,Book.objects.all()将返回数据库中的所有书籍,而Book.dahl_objects.all()只返回作者是Roald Dahl的书籍.注意我们明确的将objects设置为默认Manger的一个实例,因为如果我们不这样做,那么dahl_objects将成为唯一一个可用的manager.
由于get_queryset()返回一个Queryset对象,所以你可以使用filter(),exclude()和其他所有的Queryset方法.

如果你使用自定义的Manager对象,请注意,Django遇到的第一个Manager(以它在模型中被定义的位置为准)会有一个特殊状态。 Django将会把第一个Manager 定义为默认Manager ,Django的许多部分(但是不包括admin应用)将会明确地为模型使用这个manager。 结论是,你应该小心地选择你的默认manager。因为覆盖get_queryset()了,你可能接受到一个无用的返回对像,你必须避免这种情况.

2.自定义模型方法

为了给你的对像添加一个行级功能,那就定义一个自定义方法.鉴于manager经常被用来用一些整表操作(table-wide).模型方法应该只对特殊模型实例起作用.

from django.db import models

class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField() def baby_boomer_status(self):
# Returns the person's baby_boomer status
import datetime
if self.birth_date < datetime.date(1945, 8, 1):
return 'Pre-boomer'
elif self.birth_date < datetime.date(1965, 1, 1):
return 'Baby boomer'
else:
return 'Post-boomer' def _get_full_name(self):
# Return the person's full name
return f'{self.first_name} {self.last_name}'
full_name = property(_get_full_name) # 将类方法包装为属性

这些方法的使用:

>>> p = Person.objects.get(first_name='Barack', last_name='Obama')
>>> p.birth_date
datetime.date(1961, 8, 4)
>>> p.baby_boomer_status()
'Baby boomer'
>>> p.full_name # 注意这不是一个方法 -- 它被视为一个属性
'Barack Obama'

3.重写预定义的模型方法

还有一组模型方法了封装了一些你可能想要自定义的数据库行为.特别是你可能想要修改save()delete()的工作方式.你可以自由的重写这些方法(以及其他的模型方法)来改变行为.重写内置方法的经典用例就是你想要在保存一个对象是做些其他的什么.例如:

from django.db import models

class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField() def save(self, *args, **kwargs):
do_something()
super(Blog, self).save(*args, **kwargs) #Call the "real" save() method.
do_something_else()

你也可以阻止保存行为:

from django.db import models

class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField() def save(self, *args, **kwargs):
if self.name == 'Yoko Ono's Blog':
return # Yoko shall never have her own blog!
else:
super(Blog, self).save(*args, **kwargs) #Call the "real" save() method

记住,继承超类的方法非常重要,即super(Blog, self).save(*args, **kwargs),它确保该对象仍被保存到数据库中.如果你忘记调用超类方法,那么默认的行为将不会发生,也不会发生数据库操作.
同样重要的是,您要传递可以传递给模型方法的参数——这就是*args, **kwargs所做的事情。Django将不时扩展内置模型方法的功能,并添加新的参数。如果您在方法定义中使用了*args, **kwargs,您将保证您的代码在添加时将自动支持这些参数。

Model.clean()

应用这个方法来提供自定义的模型验证,以及修改模型的属性.例如,你可以使用它来给一个字段自动提供值,或者用于多个字段需要一起验证的情形:

import detetime
from django.core.exceptions import ValidationError
from django.db import models class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date
if self.status == 'draft' and self.pub_date is not done:
raise ValidationEroor('Draft entries may not have a publication date')
#Set the pub_date for published items if it hasn't been set already
if self.status == 'published' and self.pub_date is None:
self.pub_date = datetime.date.today()

注意,调用模型的save()方法时,不会自动调用clean()方法,需要views手动调用.
上面的示例中,clean()引发的ValidationError异常通过一个字符串实例化,所以它将被保存在一个特殊的错误字典中,键为NON_FIELD_ERRORS.这个键用于整个模型出现的错误而不是一个特定字段穿线的错误:

from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
try:
article.full_clean()
except ValidationError as e:
non_field_errors = e.message_dict[NON_FIELD_ERRORS]

若要引发一个特定字段的异常,可以使用一个字典实例化ValidationError,其中字典的键为字段名.我们可以更新前面的例子,只引发pub_date字段上的异常:

class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError({'pub_date': 'Draft entries may not have a publication date.'})
...

Django中自定义模型管理器(Manager)及方法的更多相关文章

  1. Django 自定义模型管理器(Manager)及方法

    转载自:https://www.cnblogs.com/sui776265233/p/11571418.html 1.自定义管理器(Manager) 在语句Book.objects.all()中,ob ...

  2. Django 自定义模型管理器类2个应用场景

    class BookManager(models.Manager): # 改变查询集的结果集 def all(self): books = super().all() # QuerySet books ...

  3. 查询集 QuerySet和管理器Manager

    查询集 QuerySet 查询集,也称查询结果集.QuerySet,表示从数据库中获取的对象集合. 当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表): all():返回所有数据. ...

  4. 在中间层 .NET 应用程序中通过授权管理器使用基于角色的安全

    基于角色的安全是从 Windows NT 的第一个版本开始在 Windows 平台上发展而来的.使用角色,操作系统可以通过检查称为 BUILTIN\Administrators 的组的安全上下文做出一 ...

  5. JAVA中GridBagLayout布局管理器应用详解

    很多情况下,我们已经不需要通过编写代码来实现一个应用程序的图形界面,而是通过强大的IDE工具通过拖拽辅以简单的事件处理代码即可很轻松的完成.但是我们不得不面对这样操作存在的一些问题,有时候我们希望能够 ...

  6. (转)Python中的上下文管理器和Tornado对其的巧妙应用

    原文:https://www.binss.me/blog/the-context-manager-of-python-and-the-applications-in-tornado/ 上下文是什么? ...

  7. win2008以上的系统,在vmware esxi5.5里怎么使用自定义规范管理器?sysprep

    经过测试,原来08以上的系统自带了sysprep.exe,所以vcenter对08以上的系统直接使用自定义规范管理器即可,跟linux一样了.注意不要跟03一样写入了sn即可. vCenter可使用s ...

  8. Python中的上下文管理器(contextlib模块)

    上下文管理器的任务是:代码块执行前准备,代码块执行后收拾 1 如何使用上下文管理器: 打开一个文件,并写入"hello world" filename="my.txt&q ...

  9. 在django中进行后台管理时插入外键数据时不显示值的问题

    在django的后台管理站点插入数据时,发现需要添加外键时,下拉框中不显示值 按照显示内容中的object,考虑这里应该是调用的模型类的objects对象方法,那么去models.py中对模型类添加一 ...

随机推荐

  1. Sublime Text 3 使用手册

    Ctrl+Shift+P:打开命令面板 Ctrl+P:搜索项目中的文件 Ctrl+G:跳转到第几行 Ctrl+W:关闭当前打开文件 Ctrl+Shift+W:关闭所有打开文件 Ctrl+Shift+V ...

  2. ceph存储基础概念

    一.分布式文件系统: 是指文件系统管理的物理存储资源不一定直接是连接在本地节点上,而是通过计算机网络与节点相连. 分布式文件系统的设计基与C/S架构(客户端/服务器) 常见的分布式文件系统:Ceph. ...

  3. C#编写dll进行sql server数据库扩展储存过程

    一.编写C#函数文件 1.新建一个类库文件 备注:sqlserver 2008只能用.net3.5版本. 2.如有想加入强命名的话可如下步骤: 参考博文:https://blog.csdn.net/d ...

  4. Delphi - cxGrid内容xlsx、xls、csv格式导出

    .xls格式导出,uses中添加cxGridExportLink 代码如下: function SaveToExcel(gridMain: TcxGrid; FileName: string): st ...

  5. C#开发BIMFACE系列9 服务端API之获取应用支持的文件类型

    系列目录     [已更新最新开发文章,点击查看详细] BIMFACE最核心能力之一是工程文件格式转换.无需安装插件,支持数十种工程文件格式在云端转换,完整保留原始文件信息.开发者将告别原始文件解析烦 ...

  6. JavaScript 数据结构与算法之美 - 桶排序、计数排序、基数排序

    1. 前言 算法为王. 想学好前端,先练好内功,只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算 ...

  7. 在Azure云上实现postgres主备切换

    以下是工作上实现postgres主备切换功能所用到的代码和步骤,中间走了不少弯路,在此记录下.所用到的操作系统为centos 7.5,安装了两台服务器,hostname为VM7的为Master,VM8 ...

  8. txt 文件的归并和分割

    1.归并 import os # 1.获取需要整合的文件目录下的 filepath = "G:\\我的python\\尹成\\python基础\\day13\\详细分类\\详细地区" ...

  9. JIRA使用过程出现问题整理解答

    转自:http://www.51testing.com/html/44/n-2820444.html 发表于:2015-5-28 10:22  作者:知乎   来源:51Testing软件测试网采编 ...

  10. B-Quadratic equation_2019牛客暑期多校训练营(第九场)

    题意 解下列方程 \((x+y) \equiv b \ mod \ p\) \((x\ *\ y) \equiv c \ mod \ p\) 题解 \(y = b-x\) 带入二式 \(x * (b- ...