Django自定义字段列未创建

时间:2013-11-23 01:40:59

标签: django orm field

我尝试定义两个自定义字段,但Django不会创建数据库列。

import struct

from django.db.models import BinaryField,Field
from django.core import validators
from django.utils.translation import ugettext_lazy as _


class ArrayField(BinaryField):
    description = _('Array stored as binary')

    def __init__(self, *args, **kwargs):
        super(ArrayField, self).__init__(*args, **kwargs)
        if self.max_length is not None:
            self.validators.append(validators.MaxLengthValidator(self.max_length))

    def get_internal_type(self):
        return "ArrayField"

    def get_default(self):
        default = super(ArrayField, self).get_default()
        if default == '':
            arr = []
            return arr

    def get_db_prep_value(self, value, connection, prepared=False):
        value = super(ArrayField, self
        ).get_db_prep_value(value, connection, prepared)
        arr = []
        if value is not None and len(value) > 4:
            pos = 4
            while True:
                length = struct.unpack("i", value[pos:pos + 4])
                pos += 4
                arr.append(value[pos:pos + length])
                pos += length
                if pos == len(value):
                    break
        return arr

    def pre_save(self, model_instance, add):
        value = getattr(model_instance, self.attname)
        if value is not None and len(value) > 3:
            byte = value[0:4]
            for val in value:
                byte += struct.pack("i", len(val))
                byte += val
            return byte
        return b''

    def get_data_type(self, value):
        if value is None or len(value) < 4:
            return None
        return struct.unpack("i", value)


class StringArrayField(ArrayField):
    description = _('String array stored as binary')

    def __init__(self, *args, **kwargs):
        super(StringArrayField, self).__init__(*args, **kwargs)
        kwargs['editable'] = False
        if 'encoding' in kwargs:
            self.encoding = kwargs['encoding']
        else:
            self.encoding = 'utf8'

    def get_db_prep_value(self, value, connection, prepared=False):
        arr = super(StringArrayField, self).get_db_prep_value(value, connection, prepared)
        if arr is not None and len(arr) > 0:
            for i in range(0, len(arr) - 1):
                arr[i] = bytes(arr[i]).decode(self.encoding)

    def get_internal_type(self):
        return "StringArrayField"

    def get_data_type(self, value):
        return str

测试模型:

from django.db import models


class Test(models.Model):
    arrs = fields.ArrayField()
    strs = fields.StringArrayField()
    name = models.CharField(max_length=16) #Ensure that somethink happens

同步db:

之后
SHOW FIELDS FROM liste_test;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(16) | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

我的领域不见了,我认为这只是一个小错误,但我找不到它。我把桌子垂了几下并再次同步,但我的场地仍然缺失,有人知道这是什么错误吗?

1 个答案:

答案 0 :(得分:3)

创建表时,调用方法字段的db_type()方法以获取该字段的数据类型。如果db_type返回None,则Django将在创建表[1]时跳过该字段。

未创建ArrayField字段,因为ArrayField未定义返回非None值的db_type()方法。 Nor ArrayField也没有BinaryField定义db_type()方法,然后使用Field的db_type()方法,他对ArrayField一无所知,因此返回None。

只需在ArrayField和StringArrayField中定义一个db_type()方法,你就可以了:

class ArrayField(BinaryField):
    [...]

    def db_type(self, connection):
        return 'array'  # use 'array' or whatever you want

class StringArrayField(ArrayField):
    [...]

    def db_type(self, connection):
        return 'stringarray'  # use 'stringarray' or whatever you want

欲了解更多信息,请阅读:

[1] https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#django.db.models.Field.db_type