如何在Django Rest Framework中一次创建多个连接的对象?

时间:2019-04-11 19:23:47

标签: django django-models django-rest-framework django-serializer

我的Django模型中有以下模型

class Match(models.Model):

    initiator = models.ForeignKey('CustomUser', related_name='match_initiator', on_delete=models.CASCADE)
    matched_person = models.ForeignKey('CustomUser', related_name='matched_person', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now=True)
    algo_version = models.IntegerField()
    room_no = models.ForeignKey('Room', related_name='room_match', on_delete=models.CASCADE, null=True, blank=True)


class Room(models.Model):

    name = models.CharField(max_length=20, unique=True)
    members = models.ManyToManyField(CustomUser, related_name="joined_rooms")
    created_at = models.DateTimeField(auto_now=True,editable=False)
    is_active = models.BooleanField(default=True)

所以基本上我有两个模型,RoomMatch,其中Match具有房间的外键。现在,我想一次创建这两个对象,但是我不能这样做,因为首先我必须创建Room对象,获取该对象的ID,并将其分配给Match对象实例,然后再次保存。问题在于,如果任何模型保存失败,都会破坏代码。

有什么办法可以同时创建Match和Room对象?

我在Django文档中找到了这个reference:但是我不确定Django是否自动处理它还是我需要处理它。

提前谢谢!

3 个答案:

答案 0 :(得分:1)

如果您的序列化器是嵌套的,则需要您自己处理。

可能是以下内容。这完全是一种猜测,因为我没有可用的序列化器,但我希望它能帮助您理解目标。

class MatchSerializer(serializers.ModelSerializer):
    room = RoomSerializer()

    class Meta:
        model = Match
        fields = (...)

    def create(self, validated_data):
        room_data = validated_data.pop('room')
        room = Room.objects.create(**profile_data)
        validated_data['room'] = room
        return super().create(self, validated_data)

您还需要处理链接到文档中的update方法。

答案 1 :(得分:1)

您可以使用atomic transactions保存两个对象,如果失败则不保存。

from django.db import IntegrityError, transaction

def your_function(...):
    try:
        with transaction.atomic():
            room = Room.objects.create(...)
            match = Match.objects.create(room_no=room, ...)
            ....
    except IntegrityError:
        handle_exception()

如果事务中的某些操作失败,将不会保存任何内容。

答案 2 :(得分:0)

您可以简单地使用:

fmt = mpl.ticker.StrMethodFormatter("{x:g}")
ax.yaxis.set_major_formatter(fmt)
ax.yaxis.set_minor_formatter(fmt)