django 模型里面自定义定长字段类

char和varchar区别

1, char的长度是不可变的,而varchar在长度是可变的(当然是在你设定的最大的长度范围内可变)

2, 定义一个char[10]和varchar[10],如果存进去的是‘abcd’,那么char所占的长度依然为10,除了字符‘abcd’外,后面跟六个空格,而varchar就立马把长度变为4了(4+1,后面解释),取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的。

3, char的存取数度还是要比varchar要快得多,因为其长度固定,方便程序的存储与查找;但是char也为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间。varchar是可变长度.由于是可变长度,因此存储的是实际字符串再加上一个记录字符串长度的字节。
4,VARCHAR虽然比CHAR节省空间,但是如果一个VARCHAR列经常被修改,而且每次被修改的数据的长度不同,这会引起‘行迁移’(Row Migration)现象,而这造成多余的I/O,是数据库设计和调整中要尽力避免的,在这种情况下用CHAR代替VARCHAR2会更好一些。

综上:各有千秋。

django内部已经支持的字段类型:

从里面看字符串类型的全部都是varchar而没有char,所以我们有时需要自定义char字段类型。

  data_types = {
        'AutoField': 'NUMBER(11) GENERATED BY DEFAULT ON NULL AS IDENTITY',
        'BigAutoField': 'NUMBER(19) GENERATED BY DEFAULT ON NULL AS IDENTITY',
        'BinaryField': 'BLOB',
        'BooleanField': 'NUMBER(1)',
        'CharField': 'NVARCHAR2(%(max_length)s)',
        'DateField': 'DATE',
        'DateTimeField': 'TIMESTAMP',
        'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
        'DurationField': 'INTERVAL DAY(9) TO SECOND(6)',
        'FileField': 'NVARCHAR2(%(max_length)s)',
        'FilePathField': 'NVARCHAR2(%(max_length)s)',
        'FloatField': 'DOUBLE PRECISION',
        'IntegerField': 'NUMBER(11)',
        'BigIntegerField': 'NUMBER(19)',
        'IPAddressField': 'VARCHAR2(15)',
        'GenericIPAddressField': 'VARCHAR2(39)',
        'NullBooleanField': 'NUMBER(1)',
        'OneToOneField': 'NUMBER(11)',
        'PositiveIntegerField': 'NUMBER(11)',
        'PositiveSmallIntegerField': 'NUMBER(11)',
        'SlugField': 'NVARCHAR2(%(max_length)s)',
        'SmallIntegerField': 'NUMBER(11)',
        'TextField': 'NCLOB',
        'TimeField': 'TIMESTAMP',
        'URLField': 'VARCHAR2(%(max_length)s)',
        'UUIDField': 'VARCHAR2(32)',
    }
字段类型的父类Field源码分析:

把类变量删掉,把没注释的方法删掉,看似不重要的方法也删掉,重点看注释多的方法,尤其是关注‘override’重载和‘custom ’用户自定义这两个关键词的方法。


@total_ordering
class Field(RegisterLookupMixin):
    def __init__(self, verbose_name=None, name=None, primary_key=False,
                 max_length=None, unique=False, blank=False, null=False,
                 db_index=False, rel=None, default=NOT_PROVIDED, editable=True,
                 serialize=True, unique_for_date=None, unique_for_month=None,
                 unique_for_year=None, choices=None, help_text='', db_column=None,
                 db_tablespace=None, auto_created=False, validators=(),
                 error_messages=None):
        self.name = name
        self.verbose_name = verbose_name  # May be set by set_attributes_from_name
        self._verbose_name = verbose_name  # Store original for deconstruction
        self.primary_key = primary_key
        self.max_length, self._unique = max_length, unique
        self.blank, self.null = blank, null
        self.remote_field = rel
        self.is_relation = self.remote_field is not None
        self.default = default
        self.editable = editable
        self.serialize = serialize
        self.unique_for_date = unique_for_date
        self.unique_for_month = unique_for_month
        self.unique_for_year = unique_for_year
        if isinstance(choices, collections.abc.Iterator):
            choices = list(choices)
        self.choices = choices or []
        self.help_text = help_text
        self.db_index = db_index
        self.db_column = db_column
        self._db_tablespace = db_tablespace
        self.auto_created = auto_created

        # Adjust the appropriate creation counter, and save our local copy.
        if auto_created:
            self.creation_counter = Field.auto_creation_counter
            Field.auto_creation_counter -= 1
        else:
            self.creation_counter = Field.creation_counter
            Field.creation_counter += 1

        self._validators = list(validators)  # Store for deconstruction later

        messages = {}
        for c in reversed(self.__class__.__mro__):
            messages.update(getattr(c, 'default_error_messages', {}))
        messages.update(error_messages or {})
        self._error_messages = error_messages  # Store for deconstruction later
        self.error_messages = messages


    def db_type(self, connection):
        """
        Return the database column data type for this field, for the provided
        connection.返回该字段的数据库列数据类型
        """
        # The default implementation of this method looks at the
        # backend-specific data_types dictionary, looking up the field by its
        # "internal type".该方法的默认实现查看后端特定的data_types字典,根据其“内部类型”查找字段
        #
        # A Field class can implement the get_internal_type() method to specify
        # which *preexisting* Django Field class it's most similar to -- i.e.,
        # a custom field might be represented by a TEXT column type, which is
        # the same as the TextField Django field type, which means the custom
        # field's get_internal_type() returns 'TextField'.
        #字段类可以实现get_internal_type()方法来指定它最类似于哪个*预先存在的* Django字段类。,
        #例如:自定义字段可能由文本列类型表示,它与TextField Django字段类型
        #相同,这意味着自定义字段的get_internal_type()将返回“TextField”。
        #
        # But the limitation of the get_internal_type() / data_types approach
        # is that it cannot handle database column types that aren't already
        # mapped to one of the built-in Django field types. In this case, you
        # can implement db_type() instead of get_internal_type() to specify
        # exactly which wacky database column type you want to use.
        # 但是get_internal_type() / data_types方法的限制是,它不能处理尚未映射到内置Django
        # 字段类型之一的数据库列类型。在这种情况下,你可以实现db_type(),而不是get_internal_type(),
        # 以明确指定你想要使用哪种古怪的数据库列类型
        data = self.db_type_parameters(connection)
        try:
            return connection.data_types[self.get_internal_type()] % data
        except KeyError:
            return None

    def db_parameters(self, connection):
        """
        Extension of db_type(), providing a range of different return values
        (type, checks). This will look at db_type(), allowing custom model
        fields to override it.
        扩展db_type(),提供一系列不同的返回值(类型和检查)。这将取决于db_type(),允许自定义模型字段覆盖它
        """
        type_string = self.db_type(connection)
        check_string = self.db_check(connection)
        return {
            "type": type_string,
            "check": check_string,
        }

自定义char字段类型示例:
from django.db import models

# Create your models here.
class CCharField(models.Field):
    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super(CCharField, self).__init__(max_length=max_length, *args, **kwargs)
    def db_type(self, connection):
        return 'char(%s)' %(self.max_length)
        

class Users(models.Model):
    username = models.CharField(max_length=20)
    pwd = CCharField(max_length=20)
更精简的 自定义char字段类型示例
from django.db import models

# Create your models here.
class CCharField(models.Field):
    def db_type(self, connection):
        return 'char(%s)' %(self.max_length)      
class Users(models.Model):
    username = models.CharField(max_length=20)
    pwd = CCharField(max_length=20)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值