序列化多对多字段的Django Rest框架
Django rest framework serializing many to many field
如何将多对多字段序列化为某些内容的列表,并通过 rest 框架 return 它们?在下面的示例中,我尝试 return post 以及与其关联的标签列表。
models.py
class post(models.Model):
tag = models.ManyToManyField(Tag)
text = models.CharField(max_length=100)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ("text", "tag"??)
views.py
class PostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
您需要 TagSerializer
,class Meta
有 model = Tag
。创建 TagSerializer
后,将 PostSerializer
修改为 many=True
以获得 ManyToManyField
关系:
class PostSerializer(serializers.ModelSerializer):
tag = TagSerializer(read_only=True, many=True)
class Meta:
model = Post
fields = ('tag', 'text',)
这对我有用。
tag = TagSerializer(source="tag", read_only=True, many=True)
在 init 方法的序列化程序中,您可以将查询集传递给字段并 rest_framework 验证该查询集上的 ID
1) 首先从 serializers.ModelSerializer
扩展你的序列化器
class YourSerializer(serializers.ModelSerializer):
2) 在元数据中包含字段 class
class YourSerializer(serializers.ModelSerializer):
class Meta:
fields = (..., 'your_field',)
3) 在init方法中:
def __init__(self, *args, **kwargs):
super(YourSerializer, self).__init__(*args, **kwargs)
self.fields['your_field].queryset = <the queryset of your field>
您可以像往常一样使用过滤器或排除在任何参数下限制该字段的查询集。如果您想要包含所有内容,只需使用 .objects.all()
Django 2.0
对于多对多字段,如果你想要特定的字段:
class QuestionSerializer(serializers.ModelSerializer):
topics_list = serializers.SerializerMethodField()
def get_topics_list(self, instance):
names = []
a = instance.topics.get_queryset()
for i in a:
names.append(i.desc)
return names
class Meta:
model = Question
fields = ('topics_list',)
这就是我所做的,假设一本书可以有多个作者,而一个作者可以有多个书:
型号:
class Author(models.Model):
name = models.CharField(max_length=100, default="")
last_name = models.IntegerField(default=0)
class Book(models.Model):
authors = models.ManyToManyField(Author, related_name="book_list", blank=True)
name = models.CharField(max_length=100, default="")
published = models.BooleanField(default=True)
关于序列化程序:
class BookSerializer(serializers.ModelSerializer):
authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True)
class Meta:
model = Book
fields = ('id', 'name', 'published', 'authors')
class AuthorSerializer(serializers.ModelSerializer):
book_list = BookSerializer(many=True, read_only=True)
class Meta:
model = Author
fields = ('id', 'name', 'last_name', 'book_list')
添加到@Brian 的回答
"tags": [{"name": "tag1"}] 可以简化为 "tags": ["tag1", "tag2",...] 这样:
class TagListingField(serializers.RelatedField):
def to_representation(self, value):
return value.name
class PostSerializer(serializers.ModelSerializer):
tag = TagListingField(many=True, read_only=True)
class Meta:
...
更多信息在这里:https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields
默认 ModelSerializer
使用主键建立关系。但是,您可以使用 Meta
depth
属性轻松生成嵌套表示:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ("text", "tag")
depth = 1
如documentation所述:
The depth
option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
您好,我将展示多对多的更新和创建。上下文是事件可以有很多舞蹈,舞蹈可以有很多事件。
请求如下。
{
"competition": 2,
"title": "the title",
"dances":[ {"id":1},{"id":2}],
"description": "the desc"
}
创建功能将如下所示。
def create(self, validated_data):
try:
dance_ids = []
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
new_event = models.Event.objects.create(**validated_data)
if dance_ids:
for dance_id in dance_ids:
new_event.dances.add(dance_id)
new_event.save()
return new_event
except Exception as e:
raise serializers.ValidationError({'detail': e})
更新功能如下。
def update(self, instance, validated_data):
# Delete all records of genres.
try:
for current_genre in instance.dances.all():
instance.dances.remove(current_genre)
# Repopulate genres into instance.
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_obj = models.Dance.objects.get(pk=dance['id'])
instance.dances.add(dance_obj)
event_updated = super().update(instance, validated_data)
return event_updated
except Exception as e:
raise serializers.ValidationError({'detail': e})
如果你只想做“舞蹈”:[1,2],只需对
做一些修改
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
部分。我希望这能帮助大家! :)
models.py
class Tag(models.Model):
name = models.CharField(max_length=100)
# ===============
# ... rest of the fields ...
class Post(models.Model):
tag = models.ManyToManyField(Tag)
text = models.CharField(max_length=100)
serialiazers.py
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ("text", "tag")
views.py
## FUNCTION BASED VIEW
def fbvPost_ListView(request):
# list
if request.method == "GET":
posts = Post.objects.all()
serializer = PostSerializer(instance=posts, many=True)
return JsonResponse(serializer.data, safe=False)
return JsonResponse({"success": False})
# ===========================================================
## CLASS BASED VIEW
class cbvPost_ListView(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
注意:标签,Post 是两个模型,我们需要将它们序列化。这里,Post 模型依赖于 Tag 模型,所以这里我们明确提到它,[tags = TagSerializer(many=True, read_only=True)] 或者它的 return 它是主字段值。
首先,Tag 也需要自己的序列化器
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
然后在你的Post序列化器中,添加一行
class PostSerializer(serializers.ModelSerializer):
tag = TagSerializer(read_only=True, many=True).data
class Meta:
model = Post
fields = ("text", "tag")
这将使 Post 中的标签字段成为标签 ID 数组。如果你不放“.data”部分,它会放标签的所有属性,这在大多数情况下可能太多了
如何将多对多字段序列化为某些内容的列表,并通过 rest 框架 return 它们?在下面的示例中,我尝试 return post 以及与其关联的标签列表。
models.py
class post(models.Model):
tag = models.ManyToManyField(Tag)
text = models.CharField(max_length=100)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ("text", "tag"??)
views.py
class PostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
您需要 TagSerializer
,class Meta
有 model = Tag
。创建 TagSerializer
后,将 PostSerializer
修改为 many=True
以获得 ManyToManyField
关系:
class PostSerializer(serializers.ModelSerializer):
tag = TagSerializer(read_only=True, many=True)
class Meta:
model = Post
fields = ('tag', 'text',)
这对我有用。
tag = TagSerializer(source="tag", read_only=True, many=True)
在 init 方法的序列化程序中,您可以将查询集传递给字段并 rest_framework 验证该查询集上的 ID
1) 首先从 serializers.ModelSerializer
扩展你的序列化器class YourSerializer(serializers.ModelSerializer):
2) 在元数据中包含字段 class
class YourSerializer(serializers.ModelSerializer):
class Meta:
fields = (..., 'your_field',)
3) 在init方法中:
def __init__(self, *args, **kwargs):
super(YourSerializer, self).__init__(*args, **kwargs)
self.fields['your_field].queryset = <the queryset of your field>
您可以像往常一样使用过滤器或排除在任何参数下限制该字段的查询集。如果您想要包含所有内容,只需使用 .objects.all()
Django 2.0
对于多对多字段,如果你想要特定的字段:
class QuestionSerializer(serializers.ModelSerializer):
topics_list = serializers.SerializerMethodField()
def get_topics_list(self, instance):
names = []
a = instance.topics.get_queryset()
for i in a:
names.append(i.desc)
return names
class Meta:
model = Question
fields = ('topics_list',)
这就是我所做的,假设一本书可以有多个作者,而一个作者可以有多个书: 型号:
class Author(models.Model):
name = models.CharField(max_length=100, default="")
last_name = models.IntegerField(default=0)
class Book(models.Model):
authors = models.ManyToManyField(Author, related_name="book_list", blank=True)
name = models.CharField(max_length=100, default="")
published = models.BooleanField(default=True)
关于序列化程序:
class BookSerializer(serializers.ModelSerializer):
authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True)
class Meta:
model = Book
fields = ('id', 'name', 'published', 'authors')
class AuthorSerializer(serializers.ModelSerializer):
book_list = BookSerializer(many=True, read_only=True)
class Meta:
model = Author
fields = ('id', 'name', 'last_name', 'book_list')
添加到@Brian 的回答 "tags": [{"name": "tag1"}] 可以简化为 "tags": ["tag1", "tag2",...] 这样:
class TagListingField(serializers.RelatedField):
def to_representation(self, value):
return value.name
class PostSerializer(serializers.ModelSerializer):
tag = TagListingField(many=True, read_only=True)
class Meta:
...
更多信息在这里:https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields
默认 ModelSerializer
使用主键建立关系。但是,您可以使用 Meta
depth
属性轻松生成嵌套表示:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ("text", "tag")
depth = 1
如documentation所述:
The
depth
option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
您好,我将展示多对多的更新和创建。上下文是事件可以有很多舞蹈,舞蹈可以有很多事件。
请求如下。
{
"competition": 2,
"title": "the title",
"dances":[ {"id":1},{"id":2}],
"description": "the desc"
}
创建功能将如下所示。
def create(self, validated_data):
try:
dance_ids = []
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
new_event = models.Event.objects.create(**validated_data)
if dance_ids:
for dance_id in dance_ids:
new_event.dances.add(dance_id)
new_event.save()
return new_event
except Exception as e:
raise serializers.ValidationError({'detail': e})
更新功能如下。
def update(self, instance, validated_data):
# Delete all records of genres.
try:
for current_genre in instance.dances.all():
instance.dances.remove(current_genre)
# Repopulate genres into instance.
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_obj = models.Dance.objects.get(pk=dance['id'])
instance.dances.add(dance_obj)
event_updated = super().update(instance, validated_data)
return event_updated
except Exception as e:
raise serializers.ValidationError({'detail': e})
如果你只想做“舞蹈”:[1,2],只需对
做一些修改for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
部分。我希望这能帮助大家! :)
models.py
class Tag(models.Model):
name = models.CharField(max_length=100)
# ===============
# ... rest of the fields ...
class Post(models.Model):
tag = models.ManyToManyField(Tag)
text = models.CharField(max_length=100)
serialiazers.py
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ("text", "tag")
views.py
## FUNCTION BASED VIEW
def fbvPost_ListView(request):
# list
if request.method == "GET":
posts = Post.objects.all()
serializer = PostSerializer(instance=posts, many=True)
return JsonResponse(serializer.data, safe=False)
return JsonResponse({"success": False})
# ===========================================================
## CLASS BASED VIEW
class cbvPost_ListView(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
注意:标签,Post 是两个模型,我们需要将它们序列化。这里,Post 模型依赖于 Tag 模型,所以这里我们明确提到它,[tags = TagSerializer(many=True, read_only=True)] 或者它的 return 它是主字段值。
首先,Tag 也需要自己的序列化器
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
然后在你的Post序列化器中,添加一行
class PostSerializer(serializers.ModelSerializer):
tag = TagSerializer(read_only=True, many=True).data
class Meta:
model = Post
fields = ("text", "tag")
这将使 Post 中的标签字段成为标签 ID 数组。如果你不放“.data”部分,它会放标签的所有属性,这在大多数情况下可能太多了