1.复制模型对象
产生原因:项目增加某部分表数据的复制功能,但是很难受由于项目是初始阶段,表中字段一直变化,通过对象复制操作
每次增加一些字段我就需要改代码,特别烦人,所以产生了这个东西.
代码如下很简单:
from django.db.models import AutoField, DateTimeField
from PublicMethod.CustomDjangoModelFiled import AutoIncreField # 这个字段是我自定义的一个自增类型字段(google可以找到)
def copy_object(obj):
"""
拷贝模型对象对象,并排除exclude中的字段,返回一个新的对象
:param obj 表示要copy的对象
:param exclude 表示哪些字段排除之外
:return 返回一个新的对象
"""
# 关于其中排除字段的原因AutoField和AutoIncreField由于是自增字段所以该字段对应的值不应该复制过来,
DateTimeField字段也是auto_now=True所以排除掉
initial = dict([(f.name, getattr(obj, f.name))for f in obj._meta.fields
if not (isinstance(f, AutoField) or isinstance(f, DateTimeField) or isinstance(f, AutoIncreField))
and not f in obj._meta.parents.values()])
return obj.__class__(**initial)
2.自定义自增字段
产生原因:我们的项目我来公司之前的表没有设置id字段,使用Char类型的字段当做主键的,但是后期项目需要我给所有的表添加自增的id
字段,但是如果你在django里面使用AutoField那么primary_key=True是必须的,而现在我只需要一个自增的主键id,所以通过google和
看AutoField的源码拼出来了一个新字段.
建议:每个表设置主键id字段或者一个唯一的字段,此字段建议不要出现中文(项目中使用了的基本后期全部改掉了,所以不要尝试)使用自
增字段或者使用uuid(推荐使用:因为是根据时间戳生成的所以基本不存在重复性问题),同时建议加上updated_time以及created_time
字段方便后期查询过滤使用如下即可(推荐使用继承方式将下面三个字段写入父类中,通过其他模型继承,某写表不需要是可以不继承,同时
建议将id字段和时间字段分开两个父类):
id = models.AutoField(primary_key=True, verbose_name="ID")
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
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):
def __init__(self, *args, **kwargs):
kwargs["blank"] = True
super(AutoIncreField, self).__init__(*args, **kwargs)
empty_strings_allowed = False
default_error_messages = {
'invalid': _('“%(value)s” value must be an integer.'),
}
description = _("Integer")
def check(self, **kwargs):
return [
*super().check(**kwargs),
*self._check_key(),
]
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 validate(self, value, model_instance):
pass
def get_prep_value(self, value):
value = super().get_prep_value(value)
if value is None:
return None
try:
return int(value)
except (TypeError, ValueError) as e:
raise e.__class__(
"Field '%s' expected a number but got %r." % (self.name, value),
) from e
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
del kwargs['blank']
kwargs['unique'] = True
return name, path, args, kwargs
def get_internal_type(self):
# return "AutoIncreField" # 请注意这里,不要随便起名字,这个就是我自己起的,但是迁移的时候这个字段迁移不到数据库中,
# 你创建的字段类型和已经存在的哪个相似,就写那个比如我的和AutoField类似,就写这个,否则找不到错误在哪里除非你自己看源码
return "AutoField"
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 rel_db_type(self, connection):
return IntegerField().db_type(connection=connection)
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 contribute_to_class(self, cls, name, **kwargs):
assert not cls._meta.auto_field, (
"Model %s can't have more than one auto-generated field."
% cls._meta.label
)
super().contribute_to_class(cls, name, **kwargs)
cls._meta.auto_field = self
def formfield(self, **kwargs):
return None