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


Posted in Python onMarch 30, 2020

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

Python 相关文章推荐
Python牛刀小试密码爆破
Feb 03 Python
Python Web框架Flask中使用百度云存储BCS实例
Feb 08 Python
python使用Image处理图片常用技巧分析
Jun 01 Python
python实现计算倒数的方法
Jul 11 Python
详解Python中的相对导入和绝对导入
Jan 06 Python
python GUI实例学习
Nov 21 Python
Python 绘图库 Matplotlib 入门教程
Apr 19 Python
numpy下的flatten()函数用法详解
May 27 Python
Python爬取智联招聘数据分析师岗位相关信息的方法
Aug 13 Python
django 连接数据库 sqlite的例子
Aug 14 Python
已安装tensorflow-gpu,但keras无法使用GPU加速的解决
Feb 07 Python
基于PyTorch中view的用法说明
Mar 03 Python
Python GUI编程学习笔记之tkinter事件绑定操作详解
Mar 30 #Python
VSCode基础使用与VSCode调试python程序入门的图文教程
Mar 30 #Python
Python实现Wordcloud生成词云图的示例
Mar 30 #Python
Django ModelForm操作及验证方式
Mar 30 #Python
windows10环境下用anaconda和VScode配置的图文教程
Mar 30 #Python
Python GUI编程学习笔记之tkinter控件的介绍及基本使用方法详解
Mar 30 #Python
Python GUI编程学习笔记之tkinter界面布局显示详解
Mar 30 #Python
You might like
使用 php4 加速 web 传输
2006/10/09 PHP
PHP中str_replace函数使用小结
2008/10/11 PHP
php 图像函数大举例(非原创)
2009/06/20 PHP
解析php如何将日志写进syslog
2013/06/28 PHP
CodeIgniter框架URL路由总结
2014/09/03 PHP
PHP获取文件夹内文件数的方法
2015/03/12 PHP
php操作memcache缓存方法分享
2015/06/03 PHP
php错误日志简单配置方法
2016/07/11 PHP
IE和Firefox下event事件杂谈
2009/12/18 Javascript
JavaScript 页面编码与浏览器类型判断代码
2010/06/03 Javascript
jQuery对html元素取值与赋值的方法
2013/11/20 Javascript
让table变成exls的示例代码
2014/03/24 Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
2016/01/04 Javascript
jQuery 中的 DOM 操作
2016/04/26 Javascript
Javascript的无new构建实例详解
2016/05/15 Javascript
vue2.0使用swiper组件实现轮播效果
2017/11/27 Javascript
详解处理bootstrap4不支持远程静态框问题
2018/07/20 Javascript
详解滑动穿透(锁body)终极探索
2019/04/16 Javascript
JavaScript实现随机点名器
2020/03/25 Javascript
tensorflow: variable的值与variable.read_value()的值区别详解
2018/07/30 Python
对python 匹配字符串开头和结尾的方法详解
2018/10/27 Python
在linux下实现 python 监控usb设备信号
2019/07/03 Python
python3 打印输出字典中特定的某个key的方法示例
2019/07/06 Python
python基于plotly实现画饼状图代码实例
2019/12/16 Python
python如何实现复制目录到指定目录
2020/02/13 Python
python识别验证码的思路及解决方案
2020/09/13 Python
css3中检验表单的required,focus,valid和invalid样式
2014/02/21 HTML / CSS
用css3实现转换过渡和动画效果
2020/03/13 HTML / CSS
财务工作个人求职的自我评价
2013/12/19 职场文书
办公室秘书自我鉴定
2014/01/18 职场文书
工作违纪检讨书
2014/02/17 职场文书
个人三严三实对照检查材料
2014/09/25 职场文书
副校长个人对照检查材料思想汇报
2014/10/04 职场文书
家长通知书家长意见
2015/06/03 职场文书
2016年元旦主持词
2015/07/06 职场文书
html中显示特殊符号(附带特殊字符对应表)
2021/06/21 HTML / CSS