在Django模型中存储列表的最有效方法是什么?
目前我在代码中有很多类似下面的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会有一个模型字段来处理它。我知道可以使用多对多或一对多的关系,但我希望能避免在代码中增加那种额外的复杂性。
编辑:
我添加了这个相关问题,可能会对大家有帮助。
15 个回答
在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'>
"过早优化是万恶之源."
记住这一点,我们开始吧!当你的应用程序发展到一定阶段后,数据的非规范化是很常见的做法。如果做得对,它可以节省很多昂贵的数据库查询时间,代价只是需要多花一点时间来整理数据。
为了返回一个朋友名字的 list
,我们需要创建一个自定义的 Django 字段类,这样在访问时就能返回一个列表。
David Cramer 在他的博客上发布了关于如何创建一个 SeparatedValueField 的指南。以下是代码:
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()
这个关系是不是更适合用一个一对多的外键关系来表示,比如指向一个叫做Friends
的表?我明白myFriends
只是一些字符串,但我觉得更好的设计是创建一个Friend
模型,然后让MyClass
和这个表之间建立外键关系。