如何从Django模型类继承并重写以创建listOfStringsField?

8 投票
5 回答
8022 浏览
提问于 2025-04-15 12:54

我想为 Django 模型创建一种新的字段类型,基本上是一个字符串列表。也就是说,在你的模型代码中,你会看到以下内容:

models.py:

from django.db import models

class ListOfStringsField(???):
    ???

class myDjangoModelClass():
    myName = models.CharField(max_length=64)
    myFriends = ListOfStringsField() # 

other.py:

myclass = myDjangoModelClass()
myclass.myName = "bob"
myclass.myFriends = ["me", "myself", "and I"]

myclass.save()

id = myclass.id

loadedmyclass = myDjangoModelClass.objects.filter(id__exact=id)

myFriendsList = loadedclass.myFriends
# myFriendsList is a list and should equal ["me", "myself", "and I"]

那么,如何编写这个字段类型呢?需要满足以下几点要求:

  • 我们不想创建一个字段,把所有字符串都挤在一起,用某个符号分开,就像这个方法那样。虽然在某些情况下这个方法不错,但我们希望保持字符串数据的规范化,这样除了 Django 之外的工具也能查询这些数据。
  • 这个字段应该自动创建任何需要的辅助表来存储字符串数据。
  • 辅助表最好每个唯一字符串只存一份。这是可选的,但如果能做到就更好了。

查看 Django 的代码,我觉得我需要做的事情和 ForeignKey 类似,但文档不太详细。

这引出了以下问题:

  • 这能做到吗?
  • 有没有人做过(如果有的话,在哪里可以找到)?
  • 关于如何扩展和重写 Django 的模型类,特别是它们的关系类,有没有相关的文档?我没有看到很多关于这方面的文档,但有这个

这来自于这个问题

5 个回答

5

我觉得你可能走错了方向。试图让Django的字段创建一个额外的数据库表,这几乎肯定不是个好主意。这会非常困难,而且如果你想让其他开发者也能用你的解决方案,可能会让他们感到困惑。

如果你想在一个列里存储一大堆没有规范的数据,我建议你采用类似你提到的那种方法,把Python的数据结构转成字符串,然后存储在一个TextField里。如果你希望除了Django以外的工具也能处理这些数据,可以把数据转成JSON格式(或者其他一些支持多种编程语言的格式):

from django.db import models
from django.utils import simplejson

class JSONDataField(models.TextField):
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if value is None: 
            return None
        if not isinstance(value, basestring): 
            return value
        return simplejson.loads(value)

    def get_db_prep_save(self, value):
        if value is None: 
            return None
        return simplejson.dumps(value)

如果你只是想要一个像Django Manager那样的描述符,让你能操作与模型关联的字符串列表,那么你可以手动创建一个连接表,并用一个描述符来管理这个关系。这可能不是你完全需要的,但这段代码可以帮助你入门

7

这里有一些很好的文档,介绍如何创建自定义字段,可以在这里查看

不过,我觉得你可能想得太复杂了。听起来你其实只是想要一个标准的外键,但希望能把所有的元素作为一个列表来获取。所以最简单的方法就是直接使用外键,并在模型上定义一个 get_myfield_as_list 方法:

class Friends(model.Model):
    name = models.CharField(max_length=100)
    my_items = models.ForeignKey(MyModel)

class MyModel(models.Model):
    ...

    def get_my_friends_as_list(self):
        return ', '.join(self.friends_set.values_list('name', flat=True))

现在,在 MyModel 的一个实例上调用 get_my_friends_as_list() 就会返回你需要的字符串列表。

5

你所描述的内容听起来很像标签的用法。
那么,为什么不试试django tagging呢?
这个工具非常好用,你可以独立安装它,不需要和你的应用程序捆绑在一起,而且它的使用方法也很简单。

撰写回答