DRF可寫的嵌套(DRF Writable Nested)
“DRF Writable Nested”是Django REST框架的可寫嵌套模型序列化器,它允許您使用相關嵌套數據創建/更新模型。
支持下列關系:
OneToOne (direct/reverse)-----一對一(直接的/反向)
ForeignKey (direct/reverse)-----一對多(直接的/反向)
ManyToMany (direct/reverse excluding m2m relations with through model)-----多對多(直接/反向不包括通過模型的m2m關系)
GenericRelation (this is always only reverse)-----一般關系(這總是反過來的)
Requirements(需求)
Python (2.7, 3.5, 3.6)
Django (1.9, 1.10, 1.11, 2.0)
djangorestframework (3.5+)
Installation(安裝)
pip install drf-writable-nested
Usage(用法)
例如,對于以下模型結構:
from django.db import models
class Site(models.Model):
url = models.CharField(max_length=100)
class User(models.Model):
username = models.CharField(max_length=100)
class AccessKey(models.Model):
key = models.CharField(max_length=100)
class Profile(models.Model):
sites = models.ManyToManyField(Site)
user = models.OneToOneField(User)
access_key = models.ForeignKey(AccessKey, null=True)
class Avatar(models.Model):
image = models.CharField(max_length=100)
profile = models.ForeignKey(Profile, related_name='avatars')
我們應該創建以下序列化器列表:
from rest_framework import serializers
from drf_writable_nested import WritableNestedModelSerializer
class AvatarSerializer(serializers.ModelSerializer):
image = serializers.CharField()
class Meta:
model = Avatar
fields = ('pk', 'image',)
class SiteSerializer(serializers.ModelSerializer):
url = serializers.CharField()
class Meta:
model = Site
fields = ('pk', 'url',)
class AccessKeySerializer(serializers.ModelSerializer):
class Meta:
model = AccessKey
fields = ('pk', 'key',)
class ProfileSerializer(WritableNestedModelSerializer):
# Direct ManyToMany relation
sites = SiteSerializer(many=True)
# Reverse FK relation
avatars = AvatarSerializer(many=True)
# Direct FK relation
access_key = AccessKeySerializer(allow_null=True)
class Meta:
model = Profile
fields = ('pk', 'sites', 'avatars', 'access_key',)
class UserSerializer(WritableNestedModelSerializer):
# Reverse OneToOne relation
profile = ProfileSerializer()
class Meta:
model = User
fields = ('pk', 'profile', 'username',)
另外,如果您想只支持創建或更新邏輯,您可以使用這個包中的NestedCreateMixin或NestedUpdateMixin。
例如,我們可以將以下帶有相關嵌套字段的數據傳遞給我們的主序列化器:
data = {
'username': 'test',
'profile': {
'access_key': {
'key': 'key',
},
'sites': [
{
'url': 'http://google.com',
},
{
'url': 'http://yahoo.com',
},
],
'avatars': [
{
'image': 'image-1.png',
},
{
'image': 'image-2.png',
},
],
},
}
user_serializer = UserSerializer(data=data)
user_serializer.is_valid(raise_exception=True)
user = user_serializer.save()
這個序列化器將自動創建所有嵌套的關系,我們將收到一個完整的實例,其中包含已填充的數據。
user_serializer = UserSerializer(instance=user)
print(user_serializer.data)
{
'pk': 1,
'username': 'test',
'profile': {
'pk': 1,
'access_key': {
'pk': 1,
'key': 'key'
},
'sites': [
{
'pk': 1,
'url': 'http://google.com',
},
{
'pk': 2,
'url': 'http://yahoo.com',
},
],
'avatars': [
{
'pk': 1,
'image': 'image-1.png',
},
{
'pk': 2,
'image': 'image-2.png',
},
],
},
}
還可以通過調用基序列化器的save方法將值傳遞給嵌套的序列化器。這些kwarg必須是dict類型。
# user_serializer created with 'data' as above
user = user_serializer.save(
profile={
'access_key': {'key': 'key2'},
},
)
print(user.profile.access_key.key)
'key2'
注意:相同的值將用于所有嵌套實例,比如默認值,但是優先級更高。
已知的解決方案問題
更新時帶有唯一字段的嵌套序列化器的驗證問題
我們有一種特殊的mixin單字段smixin可以解決這個問題。mixin將uniquevalidator從驗證階段移動到保存階段。
如果你想知道更多的細節,你可以閱讀相關的問題和文章:
https://github.com/beda-software/drf-writable-nested/issues/1 http://www.django-rest-framework.org/api-guide/validators/#updating-nested-serializers
使用的例子:
class Child(models.Model):
field = models.CharField(unique=True)
class Parent(models.Model):
child = models.ForeignKey('Child')
class ChildSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
class Meta:
model = Child
class ParentSerializer(NestedUpdateMixin, serializers.ModelSerializer):
child = ChildSerializer()
class Meta:
model = Parent
注意:UniqueFieldsMixin必須僅應用于具有唯一字段的序列化程序。
Mixin ordering
當您同時使用mixin (UniqueFieldsMixin和NestedCreateMixin或NestedUpdateMixin)時,您應該將UniqueFieldsMixin放在前面。
例如:
class ChildSerializer(UniqueFieldsMixin, NestedUpdateMixin,
serializers.ModelSerializer):