目录
粗浅来看,在django中为模型添加的自定义功能包括表级功能与行级功能,两者的区别即作用对象不同,对于行级功能其作用对象是面向模型的实例对象,也就是行数据。其中表级功能的实现通过自定义管理器的方法实现,行级功能的实现通过自定义模型类方法实现。
自定义管理器
在django内对于数据库的操作是通过manager实现的。例如,task=Task.objects.get(id=task_id)中,objects是Task模型类的一个特别的类属性,其特别之处就在于其指向的是模型管理器,也就是manager,是django自动创建的。通过自定义模型管理器就可以定制数据库的更加简洁的操作方法。实现的方法有两种:一种是通过创建新的manager,另一种是在本身的manager上进行修改,重构返回的QuerySet。
- 创建新的管理器
# 引用教程:https://www.w3cschool.cn/django4/django4-ptid3m0s.html
from django.db import models
from django.db.models.functions import Coalesce
# 创建PollManager类
class PollManager(models.Manager):
# 创建分组统计方法
def with_counts(self):
return self.annotate(num_responses=Coalesce(models.Count("response"), 0))
class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
# 将PollManager()赋值给OpinionPoll的objects类属性,相当于代替其本身的objects
objects = PollManager()
# 自定义管理器的查询方法
OpinionPoll.objects.with_counts()
- 修改管理器的QuerySet()
class TaskQuerySet(models.QuerySet):
"""自定义QuerySet类"""
def with_label_summary(self):
return self.prefetch_related(
'label_set',
'label_set__parent',
'project__label_set',
'project__label_set__parent',
).annotate(
task_labels_count=models.Count('label',
filter=models.Q(label__parent__isnull=True),
distinct=True
),
proj_labels_count=models.Count('project__label',
filter=models.Q(project__label__parent__isnull=True),
distinct=True
),)
class Task(models.Model):
# 这里用了相对高级的写法,将TaskQuerySet作为默认的查询管理器
objects = TaskQuerySet.as_manager()
# 自定义管理器的查询方法
Task.objects.with_label_summary()
自定义模型类方法
举例说明自定义模型类方法,以下文get_labels(),get_dirname()为例:
# 创建方法
class Task(models.Model):
objects = TaskQuerySet.as_manager()
project = models.ForeignKey(Project, on_delete=models.CASCADE,
null=True, blank=True, related_name="tasks",
related_query_name="task")
name = SafeCharField(max_length=256)
mode = models.CharField(max_length=32)
owner = models.ForeignKey(User, null=True, blank=True,
on_delete=models.SET_NULL, related_name="owners")
assignee = models.ForeignKey(User, null=True, blank=True,
on_delete=models.SET_NULL, related_name="assignees")
bug_tracker = models.CharField(max_length=2000, blank=True, default="")
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
overlap = models.PositiveIntegerField(null=True)
# Zero means that there are no limits (default)
# Note that the files can be split into jobs in a custom way in this case
segment_size = models.PositiveIntegerField(default=0)
status = models.CharField(max_length=32, choices=StatusChoice.choices(), default=StatusChoice.ANNOTATION)
data = models.ForeignKey(Data, on_delete=models.CASCADE, null=True, related_name="tasks")
dimension = models.CharField(max_length=2, choices=DimensionType.choices(), default=DimensionType.DIM_2D)
subset = models.CharField(max_length=64, blank=True, default="")
organization = models.ForeignKey(Organization, null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name="tasks")
source_storage = models.ForeignKey('Storage', null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name='+')
target_storage = models.ForeignKey('Storage', null=True, default=None,
blank=True, on_delete=models.SET_NULL, related_name='+')
# Extend default permission model
class Meta:
default_permissions = ()
def get_labels(self):
project = self.project
return project.get_labels() if project else self.label_set.filter(parent__isnull=True)
def get_dirname(self):
return os.path.join(settings.TASKS_ROOT, str(self.id))
# 使用方法
# 自定义模型类方法针对的是模型实例对象,因此先生成对象实例
task = Task.objects.get(name='')
# 实例的类方法
task.get_dirname()
task.get_label()
重写预定义模型方法
暂时占位,后续补充