Django:模型中的列表字段?

Kar*_*rus 62 django django-orm

在我的模型中,我想要一个包含三元组列表的字段.例如`[[1,3,4],[4,2,6],[8,12,3],[3,3,9]].是否有可以将此数据存储在数据库中的字段?

Ahm*_*med 87

您可以使用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]]'
Run Code Online (Sandbox Code Playgroud)

您可以在类中添加一个方法,以便自动为其转换.

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)
Run Code Online (Sandbox Code Playgroud)

如果您正在使用Django 1.9和postgresql,那么有一个名为JSONField的新类,您应该使用它.这是一个链接

youtube上有关于PostgreSQL JSON和Arrays的很好的讨论.观看它,它有非常好的信息.

  • 是否有一个特定的原因,我们可能使用json序列化而不是自定义List字段(如此线程中的第二个答案)?我主要是在表现方面有这种担忧,但我也想知道在选择这两种方法之前是否还有其他事情需要注意.提前致谢! (2认同)
  • 在Django 1.10及更高版本中,您可以使用一个新的"ArrayField"字段.见下面的答案. (2认同)

mad*_*ick 23

如果您使用的是更现代版本的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,
    )
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!看起来像它的[postgres特有的](https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#arrayfield)但很棒! (2认同)

Ris*_*nha 21

如果您使用的是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) .


Pra*_*aur 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]]
>>> 


ale*_*cxe 8

只需使用这些第三方软件包提供的JSON字段:

在这种情况下,您不需要关心字段值序列化 - 它将在引擎盖下发生.

希望有所帮助.


小智 6

这是一个相当古老的话题,但由于它在搜索“django list field”时返回,我将分享我修改后的自定义 django 列表字段代码,以使用 Python 3 和 Django 2。它现在支持管理界面,不使用 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)
Run Code Online (Sandbox Code Playgroud)