问答中心分类: PYTHON在Django模型中存储列表最有效的方法是什么?
0
匿名用户 提问 1小时 前

目前,我的代码中有许多类似于以下内容的python对象:

class MyClass():
  def __init__(self, name, friends):
      self.myName = name
      self.myFriends = [str(x) for x in friends]

现在我想把它转换成Django模型,其中self。myName是一个字符串字段,是self。myFriends是一个字符串列表。

from django.db import models

class myDjangoModelClass():
    myName = models.CharField(max_length=64)
    myFriends = ??? # what goes here?

由于列表在python中是如此常见的数据结构,我有点希望它会有一个Django模型字段。我知道我可以使用多对多或一对多的关系,但我希望在代码中避免这种额外的间接性。
编辑:
我加了这个相关问题,人们可能会觉得有用。

12 Answers
0
jb. 回答 1小时 前

“过早优化是万恶之源。”
牢记这一点,让我们这样做吧!一旦你的应用达到某一点,数据非规范化就很常见了。如果操作正确,它可以节省大量昂贵的数据库查找,而代价是稍微多一些内务管理。
返回list对于朋友姓名,我们需要创建一个自定义Django字段类,该类在访问时将返回一个列表。
DavidCramer在他的博客上发布了一个创建单独的价值域的指南。代码如下:

from django.db import models

class SeparatedValuesField(models.TextField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        self.token = kwargs.pop('token', ',')
        super(SeparatedValuesField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        if not value: return
        if isinstance(value, list):
            return value
        return value.split(self.token)

    def get_db_prep_value(self, value):
        if not value: return
        assert(isinstance(value, list) or isinstance(value, tuple))
        return self.token.join([unicode(s) for s in value])

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)

这段代码的逻辑处理从数据库到Python的序列化和反序列化值,反之亦然。现在,您可以在模型类中轻松导入和使用我们的自定义字段:

from django.db import models
from custom.fields import SeparatedValuesField 

class Person(models.Model):
    name = models.CharField(max_length=64)
    friends = SeparatedValuesField()
grieve 回复 1小时 前

+这是一个很好的答案,但我们已经在做类似的事情了。它实际上是将所有值压缩成一个字符串,然后将它们拆分出来。我想我希望得到更像ListofStringsField的东西,它实际上构建单独的表并自动生成外键。我不确定这在Django是否可行。如果是,并且我找到了答案,我会将其发布在stackoverflow上。

jb. 回复 1小时 前

如果是这种情况,那么您需要查找initcrash的django-denorm。您可以在github上找到它:github。com/initcrash/django-denorm/tree/master

sbeliakov 回复 1小时 前

+但字符串中的逗号可能存在问题。如何从json序列化和反序列化?

John Lehmann 回复 1小时 前

正在尝试使用将其添加到现有模型my_vals = SeparatedValuesField(blank=True, default="")但由于Null而获得IntegrityError。默认参数是否未正确传递?

theadriangreen 回复 1小时 前

请注意,在Django 2.1中to_python不再需要读取。因此,要完成这项工作,您需要添加:def from_db_value(self, value, expression, connection, context): return self.to_python(value)

0
mindthief 回答 1小时 前

在Django中存储列表的一种简单方法是将其转换为JSON字符串,然后将其保存为模型中的文本。然后可以通过将(JSON)字符串转换回python列表来检索列表。方法如下:
“列表”将存储在Django模型中,如下所示:

class MyModel(models.Model):
    myList = models.TextField(null=True) # JSON-serialized (text) version of your list

在视图/控制器代码中:
将列表存储在数据库中:

import simplejson as json # this would be just 'import json' in Python 2.7 and later
...
...

myModel = MyModel()
listIWantToStore = [1,2,3,4,5,'hello']
myModel.myList = json.dumps(listIWantToStore)
myModel.save()

从数据库检索列表:

jsonDec = json.decoder.JSONDecoder()
myPythonList = jsonDec.decode(myModel.myList)

从概念上讲,情况如下:

>>> myList = [1,2,3,4,5,'hello']
>>> import simplejson as json
>>> myJsonList = json.dumps(myList)
>>> myJsonList
'[1, 2, 3, 4, 5, "hello"]'
>>> myJsonList.__class__
<type 'str'>
>>> jsonDec = json.decoder.JSONDecoder()
>>> myPythonList = jsonDec.decode(myJsonList)
>>> myPythonList
[1, 2, 3, 4, 5, u'hello']
>>> myPythonList.__class__
<type 'list'>
GreenAsJade 回复 1小时 前

不幸的是,这不能帮助您使用django admin管理列表

0
wolendranh 回答 1小时 前

如果您在Postgres中使用Django>=1.9,您可以使用ArrayField公司优势

用于存储数据列表的字段。可以使用大多数字段类型

也可以嵌套数组字段:

from django.contrib.postgres.fields import ArrayField
from django.db import models

class ChessBoard(models.Model):
    board = ArrayField(
        ArrayField(
            models.CharField(max_length=10, blank=True),
            size=8,
        ),
        size=8,
    )

正如@thane brimhall提到的,也可以直接查询元素。文档reference

Thane Brimhall 回复 1小时 前

这样做的最大优点是可以直接从数组字段查询元素。

wolendranh 回复 1小时 前

@ThaneBrimhall你是对的。也许我应该用这些信息更新答案。谢谢

Joel G Mathew 回复 1小时 前

遗憾的是,mysql没有解决方案

theadriangreen 回复 1小时 前

应该提到的是,这只适用于PostGres。

kontextify 回复 1小时 前

Django 1.8也有ArrayField:文档。Django项目。com/en/1.8/ref/contrib/postgres/fields

0
sleblanc 回答 1小时 前

由于这是一个老问题,而且Django技术自那以后肯定发生了重大变化,所以这个答案反映了Django版本1.4,很可能适用于版本1.5。
Django默认使用关系数据库;你应该利用它们。使用ManyToManyField将友谊映射到数据库关系(外键约束)。这样做可以让您为好友列表使用RelatedManager,这将使用智能查询集。您可以使用所有可用的方法,例如filtervalues_list.
使用ManyToManyField关系和属性:

class MyDjangoClass(models.Model):
    name = models.CharField(...)
    friends = models.ManyToManyField("self")

    @property
    def friendlist(self):
        # Watch for large querysets: it loads everything in memory
        return list(self.friends.all())

您可以通过以下方式访问用户的好友列表:

joseph = MyDjangoClass.objects.get(name="Joseph")
friends_of_joseph = joseph.friendlist

但是请注意,这些关系是对称的:如果约瑟夫是鲍勃的朋友,那么鲍勃就是约瑟夫的朋友。

0
Martin v. Löwis 回答 1小时 前

请记住,这最终必须在关系数据库中完成。所以使用关系真的解决此问题的常用方法。如果绝对坚持在对象本身中存储列表,可以将其设置为逗号分隔,并将其存储在字符串中,然后提供将字符串拆分为列表的访问器函数。这样,您将被限制在最大数量的字符串上,并且您将失去高效的查询。

grieve 回复 1小时 前

我对将其存储为关系的数据库很满意,我希望Django模型已经为我抽象出了这一部分。从应用程序方面来说,我总是希望将其视为字符串列表。