在Django模型中存储列表最有效的方法是什么?

目前我在我的代码中有很多类似于以下的python对象:

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

现在我想把它变成一个Django模型,其中self.myName是一个string字段,而self.myFriends是一个string列表。

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

由于这个列表是python中的一个常见的数据结构,所以我期望有一个Django模型字段。 我知道我可以使用ManyToMany或OneToMany关系,但我希望避免在代码中的额外间接。

编辑:

我添加了这个相关的问题 ,哪些人可能会觉得有用。

这种关系不能更好地expression为一个与Friends表的一对多外键关系吗? 我明白我的myFriends只是string,但我会认为一个更好的devise将是创build一个Friend模型,并让MyClass包含一个外键的realtionship结果表。

“不成熟的优化是万恶之源”。

牢记这一点,让我们来做这个! 一旦你的应用程序达到某个特定的点,反规范化数据是非常普遍的。 做得正确,它可以节省大量的昂贵的数据库查找,但需要多一点的pipe家。

要返回朋友名称list ,我们需要创build一个定制的Django Field类,它将在访问时返回一个列表。

David Cramer在他的博客上发布了一个创buildSeperatedValueField的指南 。 这里是代码:

 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() 

在Django中存储列表的简单方法是将其转换为JSONstring,然后将其另存为模型中的文本。 然后,您可以通过将(JSON)string转换回python列表来检索列表。 就是这样:

“list”将被存储在你的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'> 

由于这是一个老问题,Django技术必须有很大的改变,因此这个答案反映了Django版本1.4,最有可能适用于v 1.5。

Django默认使用关系数据库; 你应该利用他们。 使用ManyToManyField将友谊映射到数据库关系(外键约束)。 这样做可以让您使用RelatedManagers来使用智能查询集。 您可以使用所有可用的方法,例如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 

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

 class Course(models.Model): name = models.CharField(max_length=256) students = models.ManyToManyField(Student) class Student(models.Model): first_name = models.CharField(max_length=256) student_number = models.CharField(max_length=128) # other fields, etc... friends = models.ManyToManyField('self') 

如果你在Postgres中使用1.9 Django,你可以使用ArrayField的优点

用于存储数据列表的字段。 大多数字段types都可以使用,只需传递另一个字段实例作为base_field。 你也可以指定一个尺寸。 ArrayField可以嵌套存储multidimensional array。

请记住,这最终必须在关系数据库中结束。 所以使用关系确实解决这个问题的常用方法。 如果你绝对坚持在对象本身存储一个列表,你可以使它例如逗号分隔,并将其存储在一个string中,然后提供访问器函数将string分割成列表。 这样,你将被限制在最大数量的string,你将失去高效的查询。

你可以使用Django Pickle Field存储几乎任何对象,ala这个片段:

http://www.djangosnippets.org/snippets/513/

如果你正在使用postgres,你可以使用这样的东西:

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

如果你需要更多的细节,你可以阅读下面的链接: https : //docs.djangoproject.com/pt-br/1.9/ref/contrib/postgres/fields/

使用一对多关系(从Friend到父类的FK)将使您的应用程序更具可扩展性(因为您可以使用除简单名称之外的其他属性来平等地扩展Friend对象)。 因此,这是最好的方法