自定义字段属性

2018-10-17  本文已影响0人  叶田的学习笔记

官方文档: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

上一篇 下一篇

猜你喜欢

热点阅读