如何在Django中创建列表字段

30 投票
7 回答
42955 浏览
提问于 2025-04-16 13:08

我想知道在Django(Python)中,如何创建一个像Google App Engine(Python)中的ListProperty那样的ListField?我的数据是一个像这样子的列表:3,4,5,6,7,8

我需要定义什么属性,怎么从中获取值呢?

7 个回答

6

考虑一下 django-jsonfield,它的优点有:

  • 可以直接保存和加载原生的列表对象,不需要转换
  • 经过充分测试,是一个成熟的解决方案
  • 在你的项目中可能还有其他好处
  • 支持在数据库中进行过滤和正则表达式(如果需要的话)

还有:

  • 支持多种数据库
  • 兼容Python 2.7到Python 3.4,以及Django 1.4到1.8
  • 使用起来非常简单 :)
6

试试使用一个叫做 CommaSeparatedIntegerField 的字段,具体的说明可以在这里找到:http://docs.djangoproject.com/en/1.2/ref/models/fields/#commaseparatedintegerfield

38

我们再来看看可以使用的 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() 进行处理。

之前我提到过这个解决方案,来源于一篇关于 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)

撰写回答