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

191

目前我的代码中有很多类似以下的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模型中会有一个相应的字段。我知道可以使用ManyToMany或OneToMany关系,但希望在代码中避免这种额外的间接性。

编辑:

我添加了这个相关问题,人们可能会发现它很有用。


1
@drozzy:我可能本可以用不同的短语,但基本上我的意思是,我想传入一个字符串列表,并获得一个字符串列表作为返回。 我不想创建一堆Friend对象,并为每个对象调用inst.myFriends.add(friendObj)。虽然这并不难,但是... - grieve
这个回答是否能解决您的问题?在Django模型中存储数组是否可能? - Kit
15个回答

4

3
不是的,请阅读片段描述。 - Harold
新的http://pypi.python.org/pypi/django-picklefield执行相同的任务(也独立于数据库)。 - Massagran

2

2023年的答案:取决于您在Django中使用的数据库

本答案将涵盖PostgreSQLMySQLSQLite


PostgreSQL 简单说:是的!PostgreSQL 有一个 ArrayField,而且很简单。模型的代码如下:

from django.db import models
from django.contrib.postgres.fields import ArrayField

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)
    myFriends = ArrayField(models.CharField(max_length=64)

关于Django与PostgreSQL中数组字段的文档在这里


MySQL 简而言之:是的!MySQL也可以处理列表,而且很简单。模型代码如下:

from django.db import models
from django_mysql.models import ListCharField

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)
    myFriends = ListCharField(base_field=CharField(max_length=64))

文档列出了在Django与MySQL中的字段在这里


SQLite 简而言之:不支持。Django与SQLite不直接支持列表。您可以使用其他答案中的其中一种hack/解决方法,或者使用其他答案中描述的JSON字段,或者按照目前已接受的答案所述使用外键来“正确地”完成它。我认为ManyToMany是这里正确的方法,而不是ForeignKey,因为可能有多个人拥有相同的朋友。模型代码:

from django.db import models

class myDjangoModelClass(models.Model):
    myName = models.CharField(max_length=64)

class myFriend(models.model):
    friend_name = models.CharField(max_length=64)
    myName = models.ManyToManyField(myDjangoModelClass, related_name='myFriends')

关于Django中使用SQLite的ManyToMany字段的文档在这里


1

有许多答案可以解决潜在的路径问题,例如如果使用PostgreSQL,则可以使用{{link1:ArrayField}},通过将列表转换为JSON字符串来使用{{link2:TextField}},创建自定义Django模型字段或者只是创建一个新模型,然后像{{link5:Daniel Roseman这里所指出的那样使用ForeignKey

尽管如此,我最喜欢的选项之一(与ForeignKey选项一起)被忽略了。更具体地说,我想引用{{link6:JSONField}}作为更好的选择。根据文档,

一个用于存储JSON编码数据的字段。在Python中,数据以其Python本地格式表示:字典、列表、字符串、数字、布尔值和None。
JSONField支持MariaDB、MySQL 5.7.8+、Oracle、PostgreSQL和SQLite(启用了JSON1扩展)。
它比ArrayField更有优势,因为它在比PostgreSQL更多的数据库中得到支持(Django 3.1以后)。
此外,它比TextField更好,因为它是专门用于存储JSON的,并且需要更少的操作步骤,例如读取。
此外,它比自定义字段更好,因为它已经随Django一起提供(无需额外的工作/维护)。

1

使用一对多关系(从朋友到父类的外键)将使您的应用程序更具可伸缩性(因为您可以轻松地将朋友对象扩展到简单名称之外的其他属性)。 因此,这是最好的方法


4
这不是可扩展性,而是可扩展性。通常情况下,这两者之间需要做出取舍。在这种情况下,如果您知道您始终需要一个字符串列表,则可以避免昂贵的连接操作,从而使您的代码更具伸缩性(即从去规范化的角度来看更高效)。 - Dustin Rasener
1
以上内容有一些注意事项:1)您知道您永远不想针对该数据进行查询,2)存储仍然比处理能力和内存便宜(谁知道,也许随着量子计算的出现这种情况会改变)。 - Dustin Rasener

0
作为ListCharField是CharField的子类,任何CharField选项也可以设置。最重要的是,您需要设置max_length来确定在数据库中保留多少个字符。
示例实例化:
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
    )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接