在我的模型中,我想要一个包含三联列表的字段。例如[[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]
。是否存在可以将该数据存储在数据库中的字段?
Answers:
您可以使用JSON将其转换为字符串并将其存储为字符串。
例如,
In [3]: json.dumps([[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]])
Out[3]: '[[1, 3, 4], [4, 2, 6], [8, 12, 3], [3, 3, 9]]'
您可以在类中添加方法以自动为您转换。
import json
class Foobar(models.Model):
foo = models.CharField(max_length=200)
def set_foo(self, x):
self.foo = json.dumps(x)
def get_foo(self):
return json.loads(self.foo)
如果您使用的是Django 1.9和PostgreSQL,则有一个名为JSONField的新类,您应该改用它。这是它的链接
在youtube上有关于PostgreSQL JSON和数组的好话。观看它,它具有非常好的信息。
ArrayField
您可以使用一个新字段。请参阅下面的答案。
如果您使用的是Django 1.10或更高版本的AND Postgres作为数据库,则可以使用 ArrayField。比起django-taggit
或其他替代方法,最好使用它,因为它是Django框架的本机。
https://docs.djangoproject.com/zh-CN/3.1/ref/contrib/postgres/fields/#arrayfield
from django.db import models
from django.contrib.postgres.fields import ArrayField
class ChessBoard(models.Model):
board = ArrayField(
ArrayField(
models.CharField(max_length=10, blank=True),
size=8,
),
size=8,
)
如果您使用的是Django 3.1或更高版本,则它们已添加了对JSONField的支持大多数数据库后端(MariaDB 10.2.7 +,MySQL 5.7.8 +,Oracle,PostgreSQL和SQLite 3.9.0+)。您可以使用它来存储您的数组!
https://docs.djangoproject.com/zh-CN/3.1/ref/models/fields/#jsonfield
from django.db import models
class ChessBoard(models.Model):
list_of_pieces = models.JSONField()
如果您使用的是PostgreSQL,则可以将ArrayField与嵌套的ArrayField一起使用:https ://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/
这样,底层数据库将知道数据结构。而且,ORM为其带来了特殊的功能。
请注意,尽管如此,您必须自己创建一个GIN索引(请参见上面的链接,网址为https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#indexing-arrayfield) 。
(编辑:更新了最新Django LTS的链接,此功能至少从1.8开始存在。)
我认为它将为您提供帮助。
从django.db导入模型 进口AST 类ListField(models.TextField): __metaclass__ = models.SubfieldBase description =“存储python列表” def __init __(self,* args,** kwargs): 超级(ListField,self).__ init __(* args,** kwargs) def to_python(自我,价值): 如果不值: 值= [] 如果isinstance(value,list): 返回值 返回ast.literal_eval(value) def get_prep_value(self,value): 如果值为None: 返回值 返回unicode(值) def value_to_string(self,obj): 值= self._get_val_from_obj(obj) 返回self.get_db_prep_value(value) ListModel(models.Model)类: test_list = ListField()
范例:
>>> ListModel.objects.create(test_list = [[1,2,3],[2,3,4,4]]) >>> ListModel.objects.get(id = 1) >>> o = ListModel.objects.get(id = 1) >>> o.id 1升 >>> o.test_list [[1、2、3],[2、3、4、4] >>>
这是一个很老的话题,但是由于它在搜索“ django list field”时返回,因此我将分享经过修改以与Python 3和Django 2一起使用的自定义django list field代码。它现在支持管理界面,并且不使用eval (这在Prashant Gaur的代码中是一个严重的安全漏洞)。
from django.db import models
from typing import Iterable
class ListField(models.TextField):
"""
A custom Django field to represent lists as comma separated strings
"""
def __init__(self, *args, **kwargs):
self.token = kwargs.pop('token', ',')
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs['token'] = self.token
return name, path, args, kwargs
def to_python(self, value):
class SubList(list):
def __init__(self, token, *args):
self.token = token
super().__init__(*args)
def __str__(self):
return self.token.join(self)
if isinstance(value, list):
return value
if value is None:
return SubList(self.token)
return SubList(self.token, value.split(self.token))
def from_db_value(self, value, expression, connection):
return self.to_python(value)
def get_prep_value(self, value):
if not value:
return
assert(isinstance(value, Iterable))
return self.token.join(value)
def value_to_string(self, obj):
value = self.value_from_object(obj)
return self.get_prep_value(value)
您可以展平列表,然后将值存储到CommaSeparatedIntegerField。当您从数据库中读回时,只需将值重新组合成三部分即可。
免责声明:根据数据库规范化理论,最好不要将集合存储在单个字段中;相反,建议您将值存储在这些三元组的各自字段中,并通过外键将其链接。但是,在现实世界中,有时这太麻烦/太慢了。
以我目前的信誉我没有能力作出评论,所以我选择的答案引用了示例代码注释中回复由PRASHANT高尔(感谢,高尔-这是有帮助的!) -他的样本是python2,因为python3没有
统一码方法。
以下功能替换
get_prep_value(自身,值):应该可以与运行python3的Django一起使用(我将很快使用此代码-尚未经过测试)。但是请注意,我正在通过
encoding ='utf-8',错误='ignore'参数
解码()和
unicode()方法。编码应匹配您的Django settings.py配置并传递
错误='忽略'是可选的(在极少数情况下,可能会导致静默数据丢失,而不是配置了错误的Django的异常)。
导入系统 ... def get_prep_value(self,value): 如果值为None: 返回值 如果sys.version_info [0]> = 3: 如果isinstance(out_data,type(b'')): 返回value.decode(encoding ='utf-8',errors ='ignore') 其他: 如果isinstance(out_data,type(b'')): 返回unicode(值,编码='utf-8',错误='忽略') 返回str(值) ...
有一个ArrayField
仅用于Postgres的本地字段。
在文档上阅读有关它的更多信息
from django.db import models
from django.contrib.postgres.fields import ArrayField
class ChessBoard(models.Model):
board = ArrayField(
ArrayField(
models.CharField(max_length=10, blank=True),
size=8,
),
size=8,
)
有两种存储数组的方法。(非官方)
from django.db import models
from typing import Iterable
class ListField(models.TextField):
def __init__(self, *args, **kwargs):
self.token = kwargs.pop('token', ',')
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs['token'] = self.token
return name, path, args, kwargs
def to_python(self, value):
class SubList(list):
def __init__(self, token, *args):
self.token = token
super().__init__(*args)
def __str__(self):
return self.token.join(self)
if isinstance(value, list):
return value
if value is None:
return SubList(self.token)
return SubList(self.token, value.split(self.token))
def from_db_value(self, value, expression, connection):
return self.to_python(value)
def get_prep_value(self, value):
if not value:
return
assert(isinstance(value, Iterable))
return self.token.join(value)
def value_to_string(self, obj):
value = self.value_from_object(obj)
return self.get_prep_value(value)
代码段形式@Yaroslav
CharField
import json
class List(models.Model):
list = models.CharField(max_length=200)
def set_list(self, x):
self.foo = json.dumps(x)
def get_list(self):
return json.loads(self.foo)