Django Rest Framework:如何将字段保存为不同模型的对象,然后将密钥返回到原始模型

时间:2014-11-25 10:20:19

标签: django django-rest-framework

抱歉这个奇怪的标题。

我有2个型号:

class TranslationWord(models.Model):
    translation = models.TextField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class TranslationByUser(models.Model):
    synset = models.ForeignKey(Synset)    
    user = models.ForeignKey(User)    
    translation = models.ForeignKey(TranslationWord)

第一个应该基本上只是保存单词。第二个应该是获得用户的输入。如果单词存在于第一个类中,则简单地存储外键值。如果它不存在,我想首先创建一个TranslationWord实例,然后将外键添加到第二个类。

我正在使用Django Rest Framework完成所有这些工作,所以我很难过。

目前,我已经拥有这2个模型,2个序列化程序(都是ModelSerializer的实例),还有一个保存它的视图(ListCreateAPIView)。

我该怎么做呢?

2 个答案:

答案 0 :(得分:0)

这些基本上是在ModelViewSet创建方法中创建成功验证对象的步骤(它在CreateModelMixin中定义):

if serializer.is_valid():
    self.pre_save(serializer.object)
    self.object = serializer.save(force_insert=True)
    self.post_save(self.object, created=True)
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED,
                    headers=headers)

这意味着您可以在ViewSet for TranslationByUser中覆盖您的操作的pre_save,将属性设置为对象中的副作用:

def pre_save(self, obj):
    #get your_translation_word from obj or self.kwargs
    your_translation_word = get_translation_word()
    translation = TranslationWord(translation=your_translation_word)
    translation.save()
    setattr(obj, 'translation', translation)

    #if you also want to support Update, call super method 
    super(TranslationByUserViewSet, self).pre_save(obj)

您可以尝试的另一件事是将TranslationWordSerializer定义为TranslationByUserSerializer中的嵌套字段。 docs中介绍了此主题。不确定DRF是否处理有关创建的所有内容。我只使用多表继承测试了这种行为(并且它可以工作)。

答案 1 :(得分:0)

无论如何,对于任何好奇的人,我在Serializer中创建了一个只写字段,并用它在restore_object方法中创建实例。

class MySerializer(serializers.ModelSerializer):
    user = UserSerializer(required=False)
    translation = TranslationLemmaSerializer(required=False)
    translation_text = serializers.WritableField(required=False, write_only=True)

    class Meta:
        model = TranslationByUser
        fields = ('id','user','synset', 'translation', 'translation_text',)
        read_only_fields = ('id', 'created_at', 'updated_at',)

    def restore_object(self, attrs, instance=None):
        print attrs
        if instance is not None:
            instance.synset = attrs.get('synset', instance.synset)
            return instance

        translation_text = attrs.get('translation_text')
        del attrs['translation_text'] #delete non-model attribute before actually creating it

        translationHIT = TranslationByUser(**attrs) #create model here
        translation_id = None
        try:
            translation_instance = TranslationWord.objects.get(translation=translation_text) #check if translationWord is already present
        except:
            translation_instance = TranslationWord(translation=translation_text)
            translation_instance.save() #otherwise, create it
        TranslationByUser.translation = translation_instance
        print attrs
        return TranslationByUser

    def get_validation_exclusions(self,instance=None):
        exclusions = super(MySerializer, self).get_validation_exclusions()
        return exclusions + ['user', 'translation']