官方文档:https://docs.djangoproject.com/en/2.1/howto/custom-model-fields/
在数据模型中自定义一个OrderField字段。
models.py
class Lesson(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,related_name='lesson_user')
course = models.ForeignKey(Course,on_delete=models.CASCADE,related_name='lesson')
title = models.CharField(max_length=200)
order = OrderField(blank=True,for_fields=['course']) # order序号从0开始
class Meta:
ordering = ['order']
def __str__(self):
return '{}.{}'.format(self.order,self.title)
新建 fields.py
自定义的字段属性在本质上就是一个类。
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
class OrderField(models.PositiveIntegerField): # PositiveIntegerField,正整数字段,包含0,最大2147483647
"""
自定义字段属性,对同一课程标题下的课程内容排序
实现在数据库中保存该课程内容在相应课程标题下的序号
"""
def __init__(self,for_fields=None,*args,**kwargs): # 自定义初始化方法
self.for_fields = for_fields
super(OrderField,self).__init__(*args,**kwargs)
def pre_save(self, model_instance, add):
"""
在保存之前对数值进行处理。在具体的某个字段属性中,因特殊需要,常常将Field类中的pre_save()方法重写
model_instance 引用的是实例,add 为该实例是否第一次被保存
"""
if getattr(model_instance,self.attname) is None: # getattr(),python内建函数,返回对象属性的值
try:
qs = self.model.objects.all() # 得到当前实例的所有实例
if self.for_fields:
query = {field: getattr(model_instance,field) for field in self.for_fields} # 得到字段列表中的属性名称(字段名称)字典形式
qs = qs.filter(**query)
last_item = qs.latest(self.attname) # 得到经筛选之后的记录中的最后一条
value = last_item.order+1 # 注意这里的order!!!!
except ObjectDoesNotExist:
value = 0
setattr(model_instance,self.attname,value) # 在相应的字段上记录本实例的序号,返回该序号值并通过pre_save()自动保存
return value
else:
return super(OrderField,self).pre_save(model_instance,add)
代码分析:
因为OrderField是要得到对象排序的序号,其值为整数,所以继承了models.PositivaIntegerField。
在Django的字段属性中都继承了Field类,pre_save()就是Field类的一个方法。
if getattr(model_instance,self.attname) is None
判断当前对象(实例)是否有某个属性(字段),如果有,就执行else分支,调用父类的pre_save()方法,但不会在数据库中增加记录;否则,就执行try...except...语句,在try中,计算新增一条数据后的序号。
getattr() 返回对象属性值
语法:getattr(object, name[, default])
object -- 对象。
name -- 字符串,对象属性。
default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
setattr() 用于设置属性值,该属性必须存在
setattr(object, name, value)
object -- 对象。
name -- 字符串,对象属性。
value -- 属性值。
filter(**kwargs) 得到的是列表。
**kwargs 参数:两个星表示接受键值对的动态参数,数量任意。调用的时候会将实际参数打包成字典。
两个星号能将字典内部的键值对逐一传入**kwargs。
def func(**kwargs):
for kwg in kwargs:
print(kwg, kwargs[kwg])
dic = {
'k1': 'v1',
'k2': 'v2'
}
func(**dic)
运行结果:
k2 v2
k1 v1
网友评论