代码之家  ›  专栏  ›  技术社区  ›  grieve

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

  •  112
  • grieve  · 技术社区  · 15 年前

    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模型字段。我知道我可以使用多对多或一对多的关系,但我希望在代码中避免这种额外的间接性。

    编辑:

    我加了这个 related question ,人们可能会觉得有用。

    11 回复  |  直到 7 年前
        1
  •  138
  •   gr347wh173n0r7h    5 年前

    “过早优化是万恶之源。”

    list 对于朋友名,我们需要创建一个定制的Django字段类,当访问它时,它将返回一个列表。

    David Cramer在他的博客上发布了一个创建单独的价值域的指南。代码如下:

    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()
    
        2
  •  90
  •   Community basarat    7 年前

    Friends 桌子我明白 myFriends 只是字符串,但我认为更好的设计是创建 Friend MyClass

        3
  •  52
  •   mindthief    12 年前

    在Django中存储列表的一种简单方法是将其转换为JSON字符串,然后将其保存为模型中的文本。然后可以通过将(JSON)字符串转换回python列表来检索列表。以下是方法:

    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'>
    
        4
  •  33
  •   wolendranh    6 年前

    如果您使用的是Django>=1.9对于Postgres,您可以利用 ArrayField

    用于存储数据列表的字段。您可以使用大多数字段类型 只需传递另一个字段实例作为基本字段。你也可以 指定一个大小。ArrayField可以嵌套以存储多维数据 数组。

    也可以嵌套数组字段:

    from django.contrib.postgres.fields import ArrayField
    from django.db import models
    
    class ChessBoard(models.Model):
        board = ArrayField(
            ArrayField(
                models.CharField(max_length=10, blank=True),
                size=8,
            ),
            size=8,
        )
    

    reference

        5
  •  17
  •   sleblanc    11 年前

    由于这是一个老问题,而且Django技术自那以后肯定发生了重大变化,所以这个答案反映了Django版本1.4,并且很可能适用于V1.5。

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

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

        6
  •  10
  •   Andriy Drozdyuk Pickels    15 年前
    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')
    
        7
  •  9
  •   Martin v. Löwis    15 年前

    请记住,这最终必须在关系数据库中完成。所以使用关系真的很重要吗 解决这个问题的常用方法。如果绝对坚持在对象本身中存储列表,可以将其设置为逗号分隔,并将其存储在字符串中,然后提供将字符串拆分为列表的访问器函数。这样,您将被限制为最大数量的字符串,并且您将丢失有效的查询。

        8
  •  7
  •   Thane Brimhall    7 年前

    如果您正在使用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/

        9
  •  5
  •   Ahtisham    3 年前

    class Bar(models.Model):
        foo = models.TextField(blank=True)
        
        def set_list(self, element):
            if self.foo:
                self.foo = self.foo + "," + element
            else:
                self.foo = element
        
        def get_list(self):
            if self.foo:
                return self.foo.split(",")
            return None
    

    你可以这样称呼它:

    bars = Bar()
    bars.set_list("str1")
    bars.set_list("str2")
    list = bars.get_list()
    if list is not None:
        for bar in list:
            print bar
    else:
        print "List is empty."      
    
        11
  •  4
  •   Robert    3 年前

    这几天存在着很好的优雅解决方案

    MySql Docs

    PostgreSQL

    from django.db.models import CharField, Model
    from django_mysql.models import ListCharField
    
    class Person(Model):
        name = CharField()
        post_nominals = ListCharField(
            base_field=CharField(max_length=10),
            size=6,
            max_length=(6 * 11)  # 6 * 10 character nominals, plus commas
        )
    

    类型

    from django.db.models import IntegerField, Model
    from django_mysql.models import ListTextField
    
    class Widget(Model):
        widget_group_ids = ListTextField(
            base_field=IntegerField(),
            size=100,  # Maximum of 100 ids in list
        )
    

    查询

    >>> Person.objects.create(name='Horatio', post_nominals=['PhD', 'Esq.', 'III'])
    >>> Person.objects.create(name='Severus', post_nominals=['PhD', 'DPhil'])
    >>> Person.objects.create(name='Paulus', post_nominals=[])
    
    >>> Person.objects.filter(post_nominals__contains='PhD')
    [<Person: Horatio>, <Person: Severus>]
    
    >>> Person.objects.filter(post_nominals__contains='Esq.')
    [<Person: Horatio>]
    
    >>> Person.objects.filter(post_nominals__contains='DPhil')
    [<Person: Severus>]
    
    >>> Person.objects.filter(Q(post_nominals__contains='PhD') & Q(post_nominals__contains='III'))
    [<Person: Horatio>]
    
        12
  •  1
  •   Guard    15 年前

    使用一对多关系(FK from Friend to parent class)将使您的应用程序更具可伸缩性(因为您可以使用简单名称之外的附加属性轻松扩展Friend对象)。因此,这是最好的方法