【发布时间】:2011-07-10 03:00:34
【问题描述】:
如何在 Django (Python) 中创建一个 ListField,如 Google App Engine (Python) 中的 ListProperty 属性?我的数据是这样的列表:3,4,5,6,7,8。
我必须定义什么属性以及如何从中获取值?
【问题讨论】:
标签: python django google-app-engine
如何在 Django (Python) 中创建一个 ListField,如 Google App Engine (Python) 中的 ListProperty 属性?我的数据是这样的列表:3,4,5,6,7,8。
我必须定义什么属性以及如何从中获取值?
【问题讨论】:
标签: python django google-app-engine
使用您可以使用的ListField 类型重新访问此内容。但它做了一些假设,例如您没有在列表中存储复杂类型。出于这个原因,我使用ast.literal_eval() 来强制规定只有简单的内置类型才能作为成员存储在ListField 中:
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 Dummy(models.Model):
mylist = ListField()
试一试:
>>> from foo.models import Dummy, ListField
>>> d = Dummy()
>>> d.mylist
[]
>>> d.mylist = [3,4,5,6,7,8]
>>> d.mylist
[3, 4, 5, 6, 7, 8]
>>> f = ListField()
>>> f.get_prep_value(d.numbers)
u'[3, 4, 5, 6, 7, 8]'
你知道一个列表作为一个 unicode 字符串存储在数据库中,当它被拉出来时,它会通过ast.literal_eval() 运行。
之前我从这篇关于 Custom Fields in Django 的博文中建议了这个解决方案:
CommaSeparatedIntegerField 的替代方案,它允许您 存储任何分隔值。您还可以选择指定令牌 参数。
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)
【讨论】:
尝试使用此处记录的CommaSeparatedIntegerField:http://docs.djangoproject.com/en/1.2/ref/models/fields/#commaseparatedintegerfield
【讨论】:
[3,4,5],那么您将分配给CommaSeparatedIntegerField,如下所示:my_object.my_field = ",".join([str(x) for x in my_list])
考虑django-jsonfield,优点是:
还有:
【讨论】:
虽然 jathanism 的回答很好,但在尝试使用 dumpdata 命令时出现以下错误:
Error: Unable to serialize database: get_db_prep_value() takes at least 3 arguments (2 given)
问题是value_to_string 方法中的self.get_db_prep_value 调用需要提供connection 值(至少在Django 1.4.10 中,这是我正在使用的)。最后,我并没有真正看到通过首先调用 value_to_string 方法并将其删除,以及不必要的 __init__ 方法获得了什么。这就是我最终得到的结果:
class ListField(models.TextField):
__metaclass__ = models.SubfieldBase
description = "Stores a python list"
def to_python(self, value):
if not value:
value = []
if isinstance(value, list):
return value
converted = ast.literal_eval(value)
if not isinstance(converted, list):
raise ValueError('Value "%s" not a list' % converted)
return converted
【讨论】:
ListField 避免这个get_db_prep_value 问题的正确方法是什么?您的评论模棱两可:@jathanism 的实现没有定义 get_db_prep_value - 只是在没有 connection 参数可用的地方使用它。
ListField
如果您使用的是 postgresql,django 支持带有 arrayfield 的 postgres。
【讨论】:
我这样做:
def get_comma_field(self, field):
data = getattr(self, field)
if data:
return data.split(',')
return []
def set_comma_field(self, val, field):
if isinstance(val, types.StringTypes):
setattr(self, field, val)
else:
setattr(self, field, ','.join(val))
def make_comma_field(field):
def getter(self):
return get_comma_field(self, field)
def setter(self, val):
return set_comma_field(self, val, field)
return property(getter, setter)
class MyModel(models.Model):
_myfield = models.CharField(max_length=31)
myfield = make_comma_field('_myfield')
但我想现在它可能有点矫枉过正。我需要其中不少,这就是我编写 make_comma_field 函数的原因。
【讨论】:
简单地说,您可以将列表存储为字符串,并且无论何时使用它,首先使用 ast.literal_eval() 从字符串转换为列表。例如:
import ast
class MyModel(models.Model):
field_1 = models.any kind of field()
list_field = models.CharField(max_length=255)
def get_list(self):
list = ast.literal_eval(self.list_field)
return list
在视图等方面也是如此。 保存时,对列表进行操作,最后通过以下方式将其转换为字符串:
model.list_field = str(list)
model.save()
【讨论】: