如何为同一模型的每个链接对象设置不同的 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__'
我正在使用 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__'