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)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。