在我的模型中,我想要一个包含三元组列表的字段。例如`[[1,3,4],[4,2,6],[8,12,3],[3,3,9]]。是否有可以将此数据存储在数据库中的字段?
答案 0 :(得分:78)
您可以使用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的新类,您应该使用它。 Here is a link to it
在youtube上有关于PostgreSQL JSON和数组的很好的讨论。观看它,它有非常好的信息。
答案 1 :(得分:20)
如果您使用的是PostgreSQL,则可以将ArrayField与嵌套的ArrayField结合使用:https://docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields/
这样,底层数据库将知道数据结构。此外,ORM为它带来了特殊的功能。
请注意,您必须自己创建一个GIN索引(请参阅上面的链接,进一步向下:https://docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields/#indexing-arrayfield)。
答案 2 :(得分:18)
如果您使用的是更现代版的Django,如1.10,而您的数据库是Postgres,则有一个新的 ArrayField 比django-taggit或其他替代品更好用,因为它是原生的到Django框架。
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,
)
答案 3 :(得分:16)
我认为它会对你有所帮助。
from django.db import models import ast class ListField(models.TextField): __metaclass__ = models.SubfieldBase description = "Stores a python list" def __init__(self, *args, **kwargs): super(ListField, self).__init__(*args, **kwargs) def to_python(self, value): if not value: value = [] if isinstance(value, list): return value return ast.literal_eval(value) def get_prep_value(self, value): if value is None: return value return unicode(value) def value_to_string(self, obj): value = self._get_val_from_obj(obj) return self.get_db_prep_value(value) class 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 1L >>> o.test_list [[1, 2, 3], [2, 3, 4, 4]] >>>
答案 4 :(得分:8)
答案 5 :(得分:1)
您可以展平列表,然后将值存储到CommaSeparatedIntegerField。当您从数据库中回读时,只需将值分组为三个。
免责声明:根据数据库规范化理论,最好不要将集合存储在单个字段中;相反,我们鼓励您将值存储在他们自己的字段中的三元组中,并通过外键链接它们。但在现实世界中,有时候太麻烦/慢。
答案 6 :(得分:1)
这是一个很老的话题,但是由于它是在搜索“ 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)
答案 7 :(得分:0)
如果您使用Google App Engine或MongoDB作为后端,并且使用的是djangoappengine
库,则内置ListField
可以完全按照您的要求执行操作。此外,可以轻松查询Listfield以查找列表中包含元素的所有对象。
答案 8 :(得分:0)
以我目前的声誉,我无法发表评论,因此我选择reply中Prashant Gaur中示例代码的答案引用评论(感谢Gaur,这很有帮助!)-他的示例适用于python2,因为python3没有
unicode方法。
下面的功能
get_prep_value(self, value):的替换应该与运行python3的Django一起使用(我将很快使用此代码-尚未经过测试)。 不过请注意,我正在将
encoding='utf-8', errors='ignore'参数传递给
decode()和
unicode() methods。编码应与您的Django settings.py配置匹配,并且传递
errors='ignore'是可选的(在极少数情况下,可能会导致静默数据丢失,而不是配置了django的异常)。
import sys ... def get_prep_value(self, value): if value is None: return value if sys.version_info[0] >= 3: if isinstance(out_data, type(b'')): return value.decode(encoding='utf-8', errors='ignore') else: if isinstance(out_data, type(b'')): return unicode(value, encoding='utf-8', errors='ignore') return str(value) ...