django自定义非主键自增字段类型详解(auto increment field)

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'])

前端:

<td>{{ row.b__caption }}</td> # 用双下划线做跨表操作

以上这篇django自定义非主键自增字段类型详解(auto increment field)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

以上是 django自定义非主键自增字段类型详解(auto increment field) 的全部内容, 来源链接: utcz.com/z/312049.html

回到顶部