django自定义非主键自增字段类型详解(auto increment field)
1.django自定义字段类型,实现非主键字段的自增
#-*-encoding:utf-8-*-
fromdjango.db.models.fieldsimportField,IntegerField
fromdjango.coreimportchecks,exceptions
fromdjango.utils.translationimportugettext_lazyas_
classAutoIncreField(Field):
description=_("Integer")
empty_strings_allowed=False
default_error_messages={
'invalid':_("'%(value)s'valuemustbeaninteger."),
}
def__init__(self,*args,**kwargs):
kwargs['blank']=True
super(AutoIncreField,self).__init__(*args,**kwargs)
defcheck(self,**kwargs):
errors=super(AutoIncreField,self).check(**kwargs)
#每张表只能设置一个字段为自增长字段,这个字段可以是主键,也可以不是主键,如果不是主键,则必须设置为一种“键(key)”
#(primarykey)也是键(key)的一种,key还包括外键(foreignkey)、唯一键(uniquekey)
errors.extend(self._check_key())
returnerrors
def_check_key(self):
ifnotself.unique:
return[
checks.Error(
'AutoIncreFieldsmustsetkey(unique=True).',
obj=self,
id='fields.E100',
),
]
else:
return[]
defdeconstruct(self):
name,path,args,kwargs=super(AutoIncreField,self).deconstruct()
delkwargs['blank']
kwargs['unique']=True
returnname,path,args,kwargs
defget_internal_type(self):
return"AutoIncreField"
defto_python(self,value):
ifvalueisNone:
returnvalue
try:
returnint(value)
except(TypeError,ValueError):
raiseexceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={'value':value},
)
defdb_type(self,connection):
return'bigintAUTO_INCREMENT'
defrel_db_type(self,connection):
returnIntegerField().db_type(connection=connection)
defvalidate(self,value,model_instance):
pass
defget_db_prep_value(self,value,connection,prepared=False):
ifnotprepared:
value=self.get_prep_value(value)
value=connection.ops.validate_autopk_value(value)
returnvalue
defget_prep_value(self,value):
value=super(AutoIncreField,self).get_prep_value(value)
ifvalueisNone:
returnNone
returnint(value)
defcontribute_to_class(self,cls,name,**kwargs):
assertnotcls._meta.auto_field,"Amodelcan'thavemorethanoneAutoIncreField."
super(AutoIncreField,self).contribute_to_class(cls,name,**kwargs)
cls._meta.auto_field=self
defformfield(self,**kwargs):
returnNone
2.使用
classTest(models.Model): id=models.UUIDField(primary_key=True,default=uuid4) numbering=AutoIncreField(_(u'numbering'),unique=True) name=models.CharField(_(u'name'),max_length=32,blank=True,null=True)
3.bug
当save()后并不能刷新instance,及save后numbering会为空值,需要重写get一次.
如果您修复了这个问题请留言回复下,谢谢
4.bug修复
以一种非常不优雅的方法进行了简单修复,重写了模型的save方法,在save后从新get
classAutoIncreFieldFixMinxin(object): defsave(self,*args,**kwargs): super(AutoIncreFieldFixMinxin,self).save(*args,**kwargs) auto_field=self._meta.auto_field.name new_obj=self.__class__.objects.get(pk=self.pk) setattr(self,auto_field,int(getattr(new_obj,auto_field))) classTest(AutoIncreFieldFixMinxin,models.Model): id=models.UUIDField(primary_key=True,default=uuid4) sequence=AutoIncreField(_(u'sequence'),unique=True) name=models.CharField(_(u'name'),max_length=100)
补充知识:Djangomodel表与表的关系
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
ForeignKey(ForeignObject)#ForeignObject(RelatedField)
to,#要进行关联的表名
to_field=None,#要关联的表中的字段名称
on_delete=None,#当删除关联表中的数据时,当前表与其关联的行的行为
-models.CASCADE,删除关联数据,与之关联也删除
-models.DO_NOTHING,删除关联数据,引发错误IntegrityError
-models.PROTECT,删除关联数据,引发错误ProtectedError
-models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
-models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
-models.SET,删除关联数据,
a.与之关联的值设置为指定值,设置:models.SET(值)
b.与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
deffunc():
return10
classMyModel(models.Model):
user=models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None,#反向操作时,使用的字段名,用于代替【表名_set】如:obj.表名_set.all()
related_query_name=None,#反向操作时,使用的连接前缀,用于替换【表名】如:models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None,#在Admin或ModelForm中显示关联数据时,提供的条件:
#如:
-limit_choices_to={'nid__gt':5}
-limit_choices_to=lambda:{'nid__gt':5}
fromdjango.db.modelsimportQ
-limit_choices_to=Q(nid__gt=10)
-limit_choices_to=Q(nid=8)|Q(nid__gt=10)
-limit_choices_to=lambda:Q(Q(nid=8)|Q(nid__gt=10))&Q(caption='root')
db_constraint=True#是否在数据库中创建外键约束
parent_link=False#在Admin中是否显示关联数据
OneToOneField(ForeignKey)
to,#要进行关联的表名
to_field=None#要关联的表中的字段名称
on_delete=None,#当删除关联表中的数据时,当前表与其关联的行的行为
######对于一对一######
#1.一对一其实就是一对多+唯一索引
#2.当两个类之间有继承关系时,默认会创建一个一对一字段
#如下会在A表中额外增加一个c_ptr_id列且唯一:
classC(models.Model):
nid=models.AutoField(primary_key=True)
part=models.CharField(max_length=12)
classA(C):
id=models.AutoField(primary_key=True)
code=models.CharField(max_length=1)
ManyToManyField(RelatedField)
to,#要进行关联的表名
related_name=None,#反向操作时,使用的字段名,用于代替【表名_set】如:obj.表名_set.all()
related_query_name=None,#反向操作时,使用的连接前缀,用于替换【表名】如:models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None,#在Admin或ModelForm中显示关联数据时,提供的条件:
#如:
-limit_choices_to={'nid__gt':5}
-limit_choices_to=lambda:{'nid__gt':5}
fromdjango.db.modelsimportQ
-limit_choices_to=Q(nid__gt=10)
-limit_choices_to=Q(nid=8)|Q(nid__gt=10)
-limit_choices_to=lambda:Q(Q(nid=8)|Q(nid__gt=10))&Q(caption='root')
symmetrical=None,#仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
#做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
#可选字段有:code,id,m1
classBB(models.Model):
code=models.CharField(max_length=12)
m1=models.ManyToManyField('self',symmetrical=True)
#可选字段有:bb,code,id,m1
classBB(models.Model):
code=models.CharField(max_length=12)
m1=models.ManyToManyField('self',symmetrical=False)
through=None,#自定义第三张表时,使用字段用于指定关系表
through_fields=None,#自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
fromdjango.dbimportmodels
classPerson(models.Model):
name=models.CharField(max_length=50)
classGroup(models.Model):
name=models.CharField(max_length=128)
members=models.ManyToManyField(
Person,
through='Membership',
through_fields=('group','person'),
)
classMembership(models.Model):
group=models.ForeignKey(Group,on_delete=models.CASCADE)
person=models.ForeignKey(Person,on_delete=models.CASCADE)
inviter=models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason=models.CharField(max_length=64)
db_constraint=True,#是否在数据库中创建外键约束
db_table=None,#默认创建第三张表时,数据库中表的名称
ForeignKey外键(跨表操作):
跨表操作1
v=models.Host.objects.filter(nid__gt=0)
v[0].b.caption#通过.进行跨表操作,在对象中去做跨表操作用.
跨表操作2
v=models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')#使用values()取值时可以用双下划线做跨表操作
forrowinv:
print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])
前端:
{{row.b__caption}} #用双下划线做跨表操作
以上这篇django自定义非主键自增字段类型详解(autoincrementfield)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。