我想问你,如何使用DRF处理添加/编辑/删除具有许多内联对象(如Django Admin + FormSet)的对象。例如:
Publication:
- title
- description
+ Notofications (1 and more)
- first_name
- email
+ Images (1 and more)
- title
- url
+ Attributes (1 and more)
- name
- value
JSON输入:
{
"title": "..",
"description": "..",
"notifications": [{"first_name": "", "email": ""}, ...]
"images": [{"title": "", "url": ""}, ...]
"attributes": [{"name": "", "value": ""}, ...]
}
所以我认为"添加"这样的结构很简单,但是如何更新" (或"修补")和"删除" (例如,其中一张图片)?整个请求应该在事务中完成,例如:如果我们对发布的标题和图像的URL进行一些编辑,并且url的格式错误,我们不应该既不保存发布对象也不保存图像对象。
REST API中是否有一个好的模式?
谢谢。
答案 0 :(得分:3)
我建议使用嵌套序列化程序:
class NestedNotificationSerializer(serializers.ModelSerializer):
class Meta:
model = models.Notification
fields = ('id', 'first_name', 'email')
def to_internal_value(self, data):
""" Return exist notification as internal value if id is provided """
if 'id' in data:
try:
return models.Notification.objects.get(id=data['id'])
except models.Notification.DoesNotExists:
raise serializers.ValidationError('Notification with id %s does not exist' % data['id'])
else:
internal_data = super(NestedNotificationSerializer, self).to_internal_value(data)
return models.Notification(**internal_data)
class PublicationSerializer(serializers.ModelSerializer):
notifications = NestedNotificationSerializer(many=True)
...
def create(self, validated_data):
notifications = validated_data.pop('notifications', [])
# create publication and its notifications in one transaction
with transaction.atomic():
publication = super(PublicationSerializer, self).create(validated_data)
for notification in notifications:
publication.notifications.add(notification)
return publication
def update(self, instance, validated_data):
notifications = validated_data.pop('notifications', [])
new_notifications = [notification for notification in notifications if notification.id is None]
existed_notifications = set([notification for notification in notifications if notification.id is not None])
# update publication and its notifications in one transaction:
with transaction.atomic():
publication = super(PublicationSerializer, self).update(instance, validated_data)
old_notifications = set(publication.notifications.all())
removed_notifications = old_notifications - existed_notifications
for notification in removed_notifications:
notification.delete()
for notification in new_notifications:
publication.notifications.add(notification)
return publication