Django 序列化程序根据外键关系列表的一侧显示不同的字段
Django serializer to show different fields based on the side of a foreign key relation list
我正在为电影和演员编写一个 Django API(使用 Django REST 框架),并将它们放在单独的 table 中,另一个 table 用于存储每部电影的演员列表存储两者的密钥。我对它们都有不同的模型和序列化器。我想知道是否有可能根据我得到的是电影还是演员,为两者之间的连接显示不同的字段选择(table 用于按电影存储演员列表)。换句话说,当我拿到电影时,我只想要演员和角色字段,但当我拿到演员时,我只想要电影和角色字段。获取与当前所选对象相关的字段将是多余的,而且会变得令人讨厌和混乱(当我获得安东尼霍普金斯的电影角色列表时,为什么我需要知道安东尼霍普金斯在每部电影中?)。
以下是模型的简化版本:
class Film(models.Model):
title = models.CharField(max_length=100, null=False, blank=False)
...Plus other fields
def __str__(self):
return f"{self.title}"
class Meta:
ordering = ['title']
class Person(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
...Plus other fields
def __str__(self):
return f"{self.name}"
class Meta:
ordering = ['name']
class ActorRole(models.Model):
film = models.ForeignKey(
Film, on_delete=models.CASCADE, related_name='cast', null=False, blank=False)
person = models.ForeignKey(
Person, on_delete=models.CASCADE, related_name='filmCredits', null=False, blank=False)
role = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return f"{self.film}: {self.person.name} - {self.role}"
class Meta:
ordering = ['film__title']
unique_together = ['film', 'person', 'role']
这里是序列化程序的简化版本。
class FilmSerializer(serializers.ModelSerializer):
cast = ActorRoleSerializer(many=True, read_only=True)
class Meta:
model = Film
fields = ['id', 'title', 'cast']
class PersonSerializer(serializers.ModelSerializer):
filmCredits = ActorRoleSerializer(many=True, read_only=True)
class Meta:
model = Person
fields = ['id', 'name', 'filmCredits']
class ActorRoleSerializer(serializers.ModelSerializer):
film = serializers.CharField(source='film.title')
actor = serializers.CharField(source='person.name')
class Meta:
model = ActorRole
fields = ['actor', 'role', 'film']
以下是我取回胶片时希望得到的:
{
"title": "Doctor Strange (2016)"
...other fields
"cast": [
{
"actor": "Pumpernickle Samsquanch",
"role": "Dr. Stephen Strange"
}
{
"actor": "Benedict Wong",
"role": "Wong"
}
{
"actor": "Mads Mikkelsen",
"role": "Kaecilius"
}
...etc
]
}
以下是我检索演员时希望得到的内容:
{
"name": "Mads Mikkelsen",
...other fields
"filmCredits": [
{
"film": "Casino Royale (2006)",
"role": "Le Chiffre"
},
{
"film": "Hunt, The (2012)",
"role": "Lucas"
}
{
"film": "Doctor Strange (2016)",
"role": "Kaecilius"
}
...etc
]
}
注意 film 如何在 cast 列表中获取演员和角色字段而不是 film 字段以及演员如何在 filmCredits 列表中获取电影和角色字段而不是 actor 字段。
我想这在某种程度上是可能的,但我不知道如何做。我考虑制作两个单独的序列化程序,一个用于关系的每一方,但这似乎有点愚蠢。我想我可能需要对我的模型进行一些修改,所以我对此持开放态度。我也完全希望有人指出我对整个事情的看法都是错误的。无论哪种方式,我都希望在不添加大量额外样板代码的情况下获得所需的输出。
您可以使用 DRF docs
:
中的这个漂亮的 class 支持动态修改序列化程序的字段
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
有了它你可以做这样的事情:
class FilmSerializer(serializers.ModelSerializer):
cast = ActorRoleSerializer(many=True, read_only=True, fields=['actor', 'role'])
class Meta:
model = Film
fields = ['id', 'title', 'cast']
class PersonSerializer(serializers.ModelSerializer):
filmCredits = ActorRoleSerializer(many=True, read_only=True, fields=['film', 'role'])
class Meta:
model = Person
fields = ['id', 'name', 'filmCredits']
class ActorRoleSerializer(DynamicFieldsModelSerializer):
film = serializers.CharField(source='film.title')
actor = serializers.CharField(source='person.name')
class Meta:
model = ActorRole
fields = ['actor', 'role', 'film']
您现在可以设置您希望 ActorRoleSerializer
使用的字段,具体取决于使用它的序列化程序。
我正在为电影和演员编写一个 Django API(使用 Django REST 框架),并将它们放在单独的 table 中,另一个 table 用于存储每部电影的演员列表存储两者的密钥。我对它们都有不同的模型和序列化器。我想知道是否有可能根据我得到的是电影还是演员,为两者之间的连接显示不同的字段选择(table 用于按电影存储演员列表)。换句话说,当我拿到电影时,我只想要演员和角色字段,但当我拿到演员时,我只想要电影和角色字段。获取与当前所选对象相关的字段将是多余的,而且会变得令人讨厌和混乱(当我获得安东尼霍普金斯的电影角色列表时,为什么我需要知道安东尼霍普金斯在每部电影中?)。
以下是模型的简化版本:
class Film(models.Model):
title = models.CharField(max_length=100, null=False, blank=False)
...Plus other fields
def __str__(self):
return f"{self.title}"
class Meta:
ordering = ['title']
class Person(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
...Plus other fields
def __str__(self):
return f"{self.name}"
class Meta:
ordering = ['name']
class ActorRole(models.Model):
film = models.ForeignKey(
Film, on_delete=models.CASCADE, related_name='cast', null=False, blank=False)
person = models.ForeignKey(
Person, on_delete=models.CASCADE, related_name='filmCredits', null=False, blank=False)
role = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return f"{self.film}: {self.person.name} - {self.role}"
class Meta:
ordering = ['film__title']
unique_together = ['film', 'person', 'role']
这里是序列化程序的简化版本。
class FilmSerializer(serializers.ModelSerializer):
cast = ActorRoleSerializer(many=True, read_only=True)
class Meta:
model = Film
fields = ['id', 'title', 'cast']
class PersonSerializer(serializers.ModelSerializer):
filmCredits = ActorRoleSerializer(many=True, read_only=True)
class Meta:
model = Person
fields = ['id', 'name', 'filmCredits']
class ActorRoleSerializer(serializers.ModelSerializer):
film = serializers.CharField(source='film.title')
actor = serializers.CharField(source='person.name')
class Meta:
model = ActorRole
fields = ['actor', 'role', 'film']
以下是我取回胶片时希望得到的:
{
"title": "Doctor Strange (2016)"
...other fields
"cast": [
{
"actor": "Pumpernickle Samsquanch",
"role": "Dr. Stephen Strange"
}
{
"actor": "Benedict Wong",
"role": "Wong"
}
{
"actor": "Mads Mikkelsen",
"role": "Kaecilius"
}
...etc
]
}
以下是我检索演员时希望得到的内容:
{
"name": "Mads Mikkelsen",
...other fields
"filmCredits": [
{
"film": "Casino Royale (2006)",
"role": "Le Chiffre"
},
{
"film": "Hunt, The (2012)",
"role": "Lucas"
}
{
"film": "Doctor Strange (2016)",
"role": "Kaecilius"
}
...etc
]
}
注意 film 如何在 cast 列表中获取演员和角色字段而不是 film 字段以及演员如何在 filmCredits 列表中获取电影和角色字段而不是 actor 字段。
我想这在某种程度上是可能的,但我不知道如何做。我考虑制作两个单独的序列化程序,一个用于关系的每一方,但这似乎有点愚蠢。我想我可能需要对我的模型进行一些修改,所以我对此持开放态度。我也完全希望有人指出我对整个事情的看法都是错误的。无论哪种方式,我都希望在不添加大量额外样板代码的情况下获得所需的输出。
您可以使用 DRF docs
:
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
有了它你可以做这样的事情:
class FilmSerializer(serializers.ModelSerializer):
cast = ActorRoleSerializer(many=True, read_only=True, fields=['actor', 'role'])
class Meta:
model = Film
fields = ['id', 'title', 'cast']
class PersonSerializer(serializers.ModelSerializer):
filmCredits = ActorRoleSerializer(many=True, read_only=True, fields=['film', 'role'])
class Meta:
model = Person
fields = ['id', 'name', 'filmCredits']
class ActorRoleSerializer(DynamicFieldsModelSerializer):
film = serializers.CharField(source='film.title')
actor = serializers.CharField(source='person.name')
class Meta:
model = ActorRole
fields = ['actor', 'role', 'film']
您现在可以设置您希望 ActorRoleSerializer
使用的字段,具体取决于使用它的序列化程序。