Serializers
ManyToMany Fields
存储对象时处理多对多关系
需求
对于提交一个新文章,其标签有则关联,没有则新建
Model
class ArticleTag(models.Model):
"""标签"""
name = models.CharField('标签名', max_length=50, primary_key=True)
def __str__(self):
return self.name
class Article(models.Model):
"""文章"""
MARKDOWN = 'MD'
RICH_TEXT = 'RT'
ARTICLE_CONTENT_TYPE = (
(MARKDOWN, 'Markdown'),
(RICH_TEXT, 'RichText'),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField('标题', max_length=200)
category = models.ForeignKey(ArticleCategory, on_delete=models.SET_NULL, null=True)
content = models.TextField('文章内容')
content_type = models.CharField('文章内容类型', choices=ARTICLE_CONTENT_TYPE, max_length=20)
tags = models.ManyToManyField(ArticleTag, blank=True)
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
public = models.BooleanField('是否公开', default=True)
create_datetime = models.DateTimeField(auto_now_add=True)
update_datetime = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
Serializer
class ArticleSerializer(serializers.ModelSerializer):
"""文章"""
class Meta:
model = Article
fields = '__all__'
def run_validation(self, data=serializers.empty):
"""验证数据"""
if 'tags' in data:
# 标签判断; 如果不存在则新建
for tag in data['tags']:
ArticleTag.objects.get_or_create(name=tag)
return super(ArticleSerializer, self).run_validation(data)
def create(self, validated_data):
"""新建文章"""
tags = validated_data.pop('tags')
instance = Article.objects.create(**validated_data)
instance.tags.set(tags)
instance.save()
return instance
示例
# Request body (JSON)
{
"title": "HELLO",
"content_type": "MD",
"content": "This is content.",
"tags": ["sadfasdf", "asdfasdf"]
}
# response
{
"id": "2970dd7f-2169-46f3-b2de-571cd83be778",
"title": "HELLO",
"content": "This is content.",
"content_type": "MD",
"public": true,
"create_datetime": "2018-06-25T02:56:36.327163Z",
"update_datetime": "2018-06-25T02:56:36.349320Z",
"category": null,
"author": null,
"tags": [
"asdfasdf",
"sadfasdf"
]
}
清空返回的Null和空列表字段
class ArticleCategorySerializer(serializers.ModelSerializer):
"""文章分类"""
children = RecursiveField(many=True)
class Meta:
model = ArticleCategory
fields = '__all__'
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
fields = [field for field in self.fields.values() if not field.write_only]
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
if attribute is not None:
represenation = field.to_representation(attribute)
if represenation is None:
# Do not seralize empty objects
continue
if isinstance(represenation, list) and not represenation:
# Do not serialize empty lists
continue
ret[field.field_name] = represenation
return ret
Context
send context infomation to serializers from view set
# send: serializer = AlbumSerializer(qs, many=True, context={'request': request})
class AlbumViewSet(viewsets.ModelViewSet):
queryset = Album.objects.all()
serializer_class = AlbumSerializer
authentication_classes = [TokenAuth]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
def list(self, request, *args, **kwargs):
qs = Album.objects.filter(Q(author=self.request.user) | Q(albumsubscribe__subscriber=self.request.user))
serializer = AlbumSerializer(qs, many=True, context={'request': request})
return Response(serializer.data)
# obtain: self.context['request']
class AlbumSerializer(serializers.ModelSerializer):
photos = AlbumPhotoSerializer(many=True, allow_null=True, read_only=True)
class Meta:
model = Album
fields = '__all__'
def to_representation(self, instance):
response = super().to_representation(instance)
response['ownership'] = 'creator' if self.context['request'].user == instance.author else 'subscribe'
return response
最后更新于
这有帮助吗?