如何为同一模型的每个链接对象设置不同的 models.ForeignKey related_name?

How to have a different models.ForeignKey related_name for each linked objects of same model?

我正在使用 Django Rest 将多个“文本块”对象与文档对象链接起来。到目前为止,我已经通过一个简单的 models.ForeignKey 功能完成了此操作。

但是,我在前端的多列中呈现所有这些文本块。 Textblock 模型将有一个列字段来确定哪个到哪个列。由于这些文本块的顺序很重要,我害怕将它们全部混合在单个“all_columns”字段下 到目前为止,我认为最简单的方法是让 DRF return 像下面这样:

{
    "name": "Comparing Two Characters",
    "column_A": [
        {
            "title": "Text Block",
            "body": "lorem ipsum blah blah"
            "col": 1
        }
    ],
    "column_B": [
        {
            "title": "Text Block 2",
            "body": "lorem ipsum blah blah"
            "col": 2
        },
            {
            "title": "Text Block 3",
            "body": "lorem ipsum blah blah"
            "col": 2
        }
    ]
}

我怎样才能实现这样的东西?我不确定使用相关字段是否适合这种情况。如果有任何帮助,我将不胜感激!

这是我目前的 models.py 参考代码:

class Document(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    # other fields
    def __str__(self):
            return self.name

class TextBlock(models.Model):
    id = models.AutoField(primary_key=True)
    document = models.ForeignKey(Document, related_name='blocks', on_delete=models.CASCADE)
    col = models.IntegerField()
    title = models.CharField(max_length=100)
    body = models.CharField(max_length=100)

编辑:

我得到了什么 return使用 sayeed910

更新的代码
            "name": "outlineblock-test",
            "desc": "",
            "blocks": [
                {
                    "url": "http://0.0.0.0:8000/api/v1/layoutblocks/7/",
                    "col": 3,
                    "title": "col3",
                    "placeholder": "hehehe",
                    "template": "http://0.0.0.0:8000/api/v1/templates/3/"
                },
                {
                    "url": "http://0.0.0.0:8000/api/v1/layoutblocks/6/",
                    "col": 2,
                    "title": "col2",
                    "placeholder": "hehe",
                    "template": "http://0.0.0.0:8000/api/v1/templates/3/"
                },
                {
                    "url": "http://0.0.0.0:8000/api/v1/layoutblocks/5/",
                    "col": 1,
                    "title": "col1",
                    "placeholder": "haha",
                    "template": "http://0.0.0.0:8000/api/v1/templates/3/"
                }
            ],

serializers.py

class TextBlockSerializer(serializers.HyperlinkedModelSerializer):
   class Meta:
       model = TextBlock
       fields = '__all__'

class DocumentSerializer(serializers.HyperlinkedModelSerializer):
    blocks = LayoutBlockSerializer(many=True, read_only=True)
    class Meta:
       model = Document
       fields = '__all__'

试试这个:

from collections import defaultdict

class Document(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    # other fields
    def __str__(self):
            return self.name

    def blocks_by_column(self):
        block_group = defaultdict(list)
        for block in self.blocks.all():
            block_group[block.col].append(block)
        return block_group


class TextBlock(models.Model):
    id = models.AutoField(primary_key=True)
    document = models.ForeignKey(Document, related_name='blocks', on_delete=models.CASCADE)
    col = models.IntegerField()
    title = models.CharField(max_length=100)
    body = models.CharField(max_length=100)

如果您有排序机制,即排序栏,您可以将 self.blocks.all() 更改为 self.blocks.order_by(<column>).all()。您可以稍后根据需要更改 blocks_group 的键。 1 -> column_A.

根据 OP 的编辑:

您应该在序列化程序而不是模型中执行分组操作

from collections import defaultdict

class DocumentSerializer(serializers.HyperlinkedModelSerializer):
    blocks = LayoutBlockSerializer(many=True, read_only=True)

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        block_group = defaultdict(list)
        for block in ret["blocks"]:
            block_group[block["col"]].append(block)
        ret["blocks"] = dict(block_group)
        return ret

    class Meta:
       model = Document
       fields = '__all__'