我尝试定义两个自定义字段,但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 | |
+-------+-------------+------+-----+---------+----------------+
我的领域不见了,我认为这只是一个小错误,但我找不到它。我把桌子垂了几下并再次同步,但我的场地仍然缺失,有人知道这是什么错误吗?
答案 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