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

作者:pushiqiang 时间:2021-08-22 02:11:42 

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> # 用双下划线做跨表操作

来源:https://blog.csdn.net/pushiqiang/article/details/77621677

标签:django,自定义,主键,自增字段
0
投稿

猜你喜欢

  • 使用GitHub和Python实现持续部署的方法

    2022-07-16 22:54:35
  • 如何把图片也存到数据库中去?

    2009-11-06 13:56:00
  • 使用Python3中的gettext模块翻译Python源码以支持多语言

    2022-10-17 21:36:07
  • python base64库给用户名或密码加密的流程

    2021-01-30 16:30:39
  • Mybatis应用mysql存储过程查询数据实例

    2024-01-16 09:05:52
  • django配置DJANGO_SETTINGS_MODULE的实现

    2023-06-18 20:14:26
  • python实现textrank关键词提取

    2021-11-01 16:47:58
  • 在Python的Flask框架中使用日期和时间的教程

    2022-08-14 21:13:09
  • Python+Turtle绘制一个可爱的生日蛋糕

    2022-12-29 04:05:39
  • pandas获取groupby分组里最大值所在的行方法

    2021-08-14 21:39:14
  • Go语言协程处理数据有哪些问题

    2024-02-12 04:54:53
  • 多个域名后缀同时查询的域名查询系统代码

    2008-05-20 11:53:00
  • 如何实现SQL Server 2005快速Web分页

    2009-01-21 14:51:00
  • Python descriptor(描述符)的实现

    2021-12-22 09:07:56
  • pandas 添加空列并赋空值案例

    2022-12-04 13:48:16
  • 趁热打铁!HTTPGet与HTTPPost的区别详解

    2022-07-15 02:46:00
  • 浅析python打包工具distutils、setuptools

    2021-03-30 14:45:14
  • Python实现的序列化和反序列化二叉树算法示例

    2021-06-11 07:14:23
  • Python利用pygame模块制作代码雨

    2021-02-13 02:53:24
  • django处理select下拉表单实例(从model到前端到post到form)

    2023-09-02 13:47:09
  • asp之家 网络编程 m.aspxhome.com