1.django自定义字段类型,实现非主键字段的自增
# -*- encoding: utf-8 -*-
from django.db.models.fields import field, integerfield
from django.core import checks, exceptions
from django.utils.translation import ugettext_lazy as _
class autoincrefield(field):
description = _("integer")
empty_strings_allowed = false
default_error_messages = {
'invalid': _("'%(value)s' value must be an integer."),
}
def __init__(self, *args, **kwargs):
kwargs['blank'] = true
super(autoincrefield, self).__init__(*args, **kwargs)
def check(self, **kwargs):
errors = super(autoincrefield, self).check(**kwargs)
# 每张表只能设置一个字段为自增长字段,这个字段可以是主键,也可以不是主键,如果不是主键,则必须设置为一种“键(key)”
# (primary key)也是键(key)的一种,key还包括外键(foreign key)、唯一键(unique key)
errors.extend(self._check_key())
return errors
def _check_key(self):
if not self.unique:
return [
checks.error(
'autoincrefields must set key(unique=true).',
obj=self,
id='fields.e100',
),
]
else:
return []
def deconstruct(self):
name, path, args, kwargs = super(autoincrefield, self).deconstruct()
del kwargs['blank']
kwargs['unique'] = true
return name, path, args, kwargs
def get_internal_type(self):
return "autoincrefield"
def to_python(self, value):
if value is none:
return value
try:
return int(value)
except (typeerror, valueerror):
raise exceptions.validationerror(
self.error_messages['invalid'],
code='invalid',
params={'value': value},
)
def db_type(self, connection):
return 'bigint auto_increment'
def rel_db_type(self, connection):
return integerfield().db_type(connection=connection)
def validate(self, value, model_instance):
pass
def get_db_prep_value(self, value, connection, prepared=false):
if not prepared:
value = self.get_prep_value(value)
value = connection.ops.validate_autopk_value(value)
return value
def get_prep_value(self, value):
value = super(autoincrefield, self).get_prep_value(value)
if value is none:
return none
return int(value)
def contribute_to_class(self, cls, name, **kwargs):
assert not cls._meta.auto_field, "a model can't have more than one autoincrefield."
super(autoincrefield, self).contribute_to_class(cls, name, **kwargs)
cls._meta.auto_field = self
def formfield(self, **kwargs):
return none
2.使用
class test(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
class autoincrefieldfixminxin(object): def save(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))) class test(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)
补充知识:django model 表与表的关系
一对多: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(可执行对象)
def func():
return 10
class mymodel(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}
from django.db.models import q
- 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列且唯一:
class c(models.model):
nid = models.autofield(primary_key=true)
part = models.charfield(max_length=12)
class a(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}
from django.db.models import q
- 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
class bb(models.model):
code = models.charfield(max_length=12)
m1 = models.manytomanyfield('self',symmetrical=true)
# 可选字段有: bb, code, id, m1
class bb(models.model):
code = models.charfield(max_length=12)
m1 = models.manytomanyfield('self',symmetrical=false)
through=none, # 自定义第三张表时,使用字段用于指定关系表
through_fields=none, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class person(models.model):
name = models.charfield(max_length=50)
class group(models.model):
name = models.charfield(max_length=128)
members = models.manytomanyfield(
person,
through='membership',
through_fields=('group', 'person'),
)
class membership(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()取值时可以用双下划线做跨表操作
for row in v:
print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])
前端:
{{ row.b__caption }} # 用双下划线做跨表操作
以上这篇django自定义非主键自增字段类型详解(auto increment field)就是小编分享给大家的全部内容了,希望能给大家一个参考,
森么辣么萌