django自定義非主鍵自增字段類型詳解(auto increment field)
1.django自定義字段類型,實現(xiàn)非主鍵字段的自增
# -*- 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)
# 每張表只能設(shè)置一個字段為自增長字段,這個字段可以是主鍵,也可以不是主鍵,如果不是主鍵,則必須設(shè)置為一種“鍵(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
當(dāng)save()后并不能刷新instance,及save后numbering會為空值,需要重寫get一次.
如果您修復(fù)了這個問題請留言回復(fù)下,謝謝
4.bug修復(fù)
以一種非常不優(yōu)雅的方法進(jìn)行了簡單修復(fù),重寫了模型的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)
補(bǔ)充知識:Django model 表與表的關(guān)系
一對多:models.ForeignKey(其他表)
多對多:models.ManyToManyField(其他表)
一對一:models.OneToOneField(其他表)
應(yīng)用場景:
一對多:當(dāng)一張表中創(chuàng)建一行數(shù)據(jù)時,有一個單選的下拉框(可以被重復(fù)選擇)
例如:創(chuàng)建用戶信息時候,需要選擇一個用戶類型【普通用戶】【金牌用戶】【鉑金用戶】等。
多對多:在某表中創(chuàng)建一行數(shù)據(jù)是,有一個可以多選的下拉框
例如:創(chuàng)建用戶信息,需要為用戶指定多個愛好
一對一:在某表中創(chuàng)建一行數(shù)據(jù)時,有一個單選的下拉框(下拉框中的內(nèi)容被用過一次就消失了
例如:原有含10列數(shù)據(jù)的一張表保存相關(guān)信息,經(jīng)過一段時間之后,10列無法滿足需求,需要為原來的表再添加5列數(shù)據(jù)
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
to, # 要進(jìn)行關(guān)聯(lián)的表名
to_field=None, # 要關(guān)聯(lián)的表中的字段名稱
on_delete=None, # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時,當(dāng)前表與其關(guān)聯(lián)的行的行為
- models.CASCADE,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)也刪除
- models.DO_NOTHING,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯誤IntegrityError
- models.PROTECT,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯誤ProtectedError
- models.SET_NULL,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為null(前提FK字段需要設(shè)置為可空)
- models.SET_DEFAULT,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為默認(rèn)值(前提FK字段需要設(shè)置默認(rèn)值)
- models.SET,刪除關(guān)聯(lián)數(shù)據(jù),
a. 與之關(guān)聯(lián)的值設(shè)置為指定值,設(shè)置:models.SET(值)
b. 與之關(guān)聯(lián)的值設(shè)置為可執(zhí)行對象的返回值,設(shè)置:models.SET(可執(zhí)行對象)
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中顯示關(guān)聯(lián)數(shù)據(jù)時,提供的條件:
# 如:
- 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 # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束
parent_link=False # 在Admin中是否顯示關(guān)聯(lián)數(shù)據(jù)
OneToOneField(ForeignKey)
to, # 要進(jìn)行關(guān)聯(lián)的表名
to_field=None # 要關(guān)聯(lián)的表中的字段名稱
on_delete=None, # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時,當(dāng)前表與其關(guān)聯(lián)的行的行為
###### 對于一對一 ######
# 1. 一對一其實就是 一對多 + 唯一索引
# 2.當(dāng)兩個類之間有繼承關(guān)系時,默認(rèn)會創(chuàng)建一個一對一字段
# 如下會在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, # 要進(jìn)行關(guān)聯(lián)的表名
related_name=None, # 反向操作時,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作時,使用的連接前綴,用于替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中顯示關(guān)聯(lián)數(shù)據(jù)時,提供的條件:
# 如:
- 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, # 僅用于多對多自關(guān)聯(lián)時,symmetrical用于指定內(nèi)部是否創(chuàng)建反向操作的字段
# 做如下操作時,不同的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, # 自定義第三張表時,使用字段用于指定關(guān)系表
through_fields=None, # 自定義第三張表時,使用字段用于指定關(guān)系表中那些字段做多對多關(guān)系表
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, # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束
db_table=None, # 默認(rèn)創(chuàng)建第三張表時,數(shù)據(jù)庫中表的名稱
ForeignKey外鍵(跨表操作):
跨表操作1
v = models.Host.objects.filter(nid__gt=0)
v[0].b.caption #通過.進(jìn)行跨表操作,在對象中去做跨表操作用.
跨表操作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)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
python3基于TCP實現(xiàn)CS架構(gòu)文件傳輸
這篇文章主要為大家詳細(xì)介紹了python3基于TCP實現(xiàn)CS架構(gòu)文件傳輸,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
Python實現(xiàn)Microsoft Office自動化的幾種方式及對比詳解
辦公自動化是指利用現(xiàn)代化設(shè)備和技術(shù),代替辦公人員的部分手動或重復(fù)性業(yè)務(wù)活動,優(yōu)質(zhì)而高效地處理辦公事務(wù),實現(xiàn)對信息的高效利用,進(jìn)而提高生產(chǎn)率,實現(xiàn)輔助決策的目的,所以本文給大家介紹了Python實現(xiàn)Microsoft Office自動化的幾種方式,需要的朋友可以參考下2025-03-03
Python使用os.listdir()和os.walk()獲取文件路徑與文件下所有目錄的方法
今天小編就為大家分享一篇關(guān)于Python使用os.listdir()和os.walk()獲取文件路徑與文件下所有目錄的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04
Python守護(hù)進(jìn)程實現(xiàn)過程詳解
這篇文章主要介紹了Python守護(hù)進(jìn)程實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02
pandas實現(xiàn)excel中的數(shù)據(jù)透視表和Vlookup函數(shù)功能代碼
今天小編就為大家分享一篇pandas實現(xiàn)excel中的數(shù)據(jù)透視表和Vlookup函數(shù)功能代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
Python 運行 shell 獲取輸出結(jié)果的實例
今天小編就為大家分享一篇Python 運行 shell 獲取輸出結(jié)果的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01

