Python 如何在django中创建列表字段
如何在Django(Python)中创建一个类似于Google App Engine(Python)中的属性的列表字段?我的数据是这样的列表:Python 如何在django中创建列表字段,python,django,google-app-engine,Python,Django,Google App Engine,如何在Django(Python)中创建一个类似于Google App Engine(Python)中的属性的列表字段?我的数据是这样的列表:3,4,5,6,7,8 我必须定义什么属性以及如何从中获取值?尝试使用CommaSeparatedIntegerField,该字段记录在此处:我执行以下操作: def get_comma_field(self, field): data = getattr(self, field) if data: return data.
3,4,5,6,7,8
我必须定义什么属性以及如何从中获取值?尝试使用
CommaSeparatedIntegerField
,该字段记录在此处:我执行以下操作:
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函数的原因。使用您可以使用的
ListField
类型重新讨论这个问题。但它做出了一些假设,例如您没有在列表中存储复杂类型。出于这个原因,我使用了ast.literal\u eval()
来强制执行只有简单的内置类型才能作为成员存储在列表字段中
:
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字符串的形式存储在数据库中,当被拉出时,它将被执行
在此之前,我在这篇博客文章中提出了以下解决方案:
作为CommaseParatedIntegraterField的替代方案,它允许您
存储任何分隔的值。您还可以选择指定令牌
参数
虽然jathanism的答案很好,但在尝试使用
dumpdata
命令时,我遇到了以下错误:
Error: Unable to serialize database: get_db_prep_value() takes at least 3 arguments (2 given)
问题是self.get\u db\u prep\u value
调用value\u to\u string
方法需要提供一个连接
值(至少在中,这是我正在使用的)。最后,我没有真正看到通过首先调用value\u to\u string
方法并删除它以及不必要的\uuuu init\uuu
方法所获得的效果。这就是我的结局:
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
考虑到这一点,优势在于:
- 保存并加载本机列表对象,无需转换
- 经过充分测试和成熟的解决方案
- 在您的项目中可能有其他优势
- 支持对数据库和正则表达式进行筛选(如果需要)
- 跨数据库支持
- 支持Python2.7到Python3.4和Django 1.4到1.8
- 很简单:)
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()
你能给我们看一下为CommaseOperatedIntegraterField获取单个值的代码吗?如果你的数据在列表中,比如说
[3,4,5]
,那么你会像这样分配给CommaseOperatedIntegraterField
:my_object.my_field=“,”。join([str(x)for x in my_list])
应用引擎本机支持列表;以逗号分隔的方式存储列表似乎是个糟糕的主意。我是应用程序引擎团队的成员,我知道它如何存储列表:作为一系列字段。尼克,我很想看看你的替代方案,在那之前,贾塔尼主义的分离价值场方法对我的GAE Django Norel项目非常有效。谢谢。@NickJohnson你说的“本机”是什么意思?当然你不是说它在关系数据库中被规范化了。我希望GAE使用文档驱动的东西。Django(1.5.2)Field对象在get\u db\u prep\u value()方法上请求一个“connection”参数。但根本不用它?我现在明白你的意思了。你对这个问题的理解与我不同。我问这个问题是为了回答“如何在Django中创建ListField?”(列表字段类似于应用程序引擎)。它与SeparatedValuesField类几乎相同,只是不是字段类,也没有可配置的分隔符。从功能上讲,是的,但我的意思是,只要在Django框架内设置了以下约定,您所要做的就是将该方法更改为:def get_db_prep_value(self、value、connection、prepared=False)作为该方法的签名changed@OritK:怎么做?实现ListField
的正确方法是什么?如何避免这个get\u db\u prep\u值的问题?您的评论模棱两可:@jathanism的实现并没有定义get\u db\u prep\u值
——只是在没有连接
参数的地方使用它。必须承认,我不是100%确定我记得它。。但根据我的评论:您应该更改jathanism对ListField的实现。将“def get_prep_value(self,value)”改为“def get_db_prep_value(self,value,connection,prepared=False)”,它应该可以工作。我同意@OritK,这是使@jathanim的实现工作所需的最小更改。不过,我认为在该实现中有一些不必要的更改,所以除了我认为创建ListField
model.list_field = str(list)
model.save()