在Django Rest Framework中编写嵌套的序列化程序并遇到验证程序问题

时间:2017-05-23 03:15:42

标签: django django-rest-framework

什么是写入与ForeignKey相关项已存在的嵌套序列化程序的最佳方法?

示例 - 我有一对多的调查模型和SurveyReponse模型。尚未创建调查模型的新SurveyResponse模型的POST无问题,并且还没有定义特定调查模型的模型的POST,我默认为特定的调查模型。但是,尝试提供该字段似乎会导致验证问题类似于过去提出的问题:https://github.com/encode/django-rest-framework/issues/2996 似乎只是添加验证器= []修复了我的问题。

到目前为止我做了什么: 我设置我的SurveyReponse.create()方法是为了发布一个SurveyResponse提供NO Survey,并将其保存到默认的Survey。 这非常有效。

{ "rating": 10 } 

创建一个新的SurveyReponse对象,并将其与名为“默认调查名称”的调查相关联

我还想做什么: 我希望能够提供一个特定的调查,以便将我的SurveyReponse联系起来。

{
 "rating": 10,
 "survey": {"name": "Other Survey Name"}
}

如果调查尚不存在,这对我当前的代码工作正常,但是,如果调查已经存在,我点击了唯一标识符重复错误

{
  "survey": {
    "name": [
      "survey with this name already exists."
    ]
  }
}

我如何解决这个问题? 删除此行,

     survey = SurveySerializer(required=False)

我能够做我想做的事,但是当我希望能够提供名称时,我必须只提供资源的URL。 (除非这个完整的想法是反模式或某种东西,在这种情况下,我应该总是只是写入/ survey /对象)

抽样调查和调查回复:

高级模特:

class Survey(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=255, unique=True)
    creator = models.ForeignKey(
        'auth.User',
        related_name='survey',
        to_field='id',
        null=True,
    )

class SurveyResponse(models.Model):
    """Response to the Survey"""
    survey = models.ForeignKey(Survey, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    rating = models.IntegerField(blank=False)
    creator = models.ForeignKey(
        'auth.User',
        related_name='survey_response',
        to_field='id',
        null=True,
    )

串行器

class SurveySerializer(serializers.HyperlinkedModelSerializer):
    creator = serializers.ReadOnlyField(source='creator.username')
    class Meta:
        model = Survey
        fields = '__all__'

class SurveyResponseSerializer(serializers.HyperlinkedModelSerializer):
    '''Question Serializer'''
    creator = serializers.ReadOnlyField(source='creator.username')
    survey = SurveySerializer(required=False)
    def create(self, validated_data):
        default_survey_name = "Default Survey Name"
        survey_data = validated_data.pop('survey', None)
        if survey_data is None:
            try:
                survey = Survey.objects.get(name=default_survey_name)
                validated_data['survey'] = survey
            except:
                print("Unable to get Survey, creating a new one")
                survey = Survey.objects.create(
                    name=default_survey_name,
                    description=default_survey_name,
                    creator=self.context['request'].user
                )
                validated_data['survey'] = survey
        else:
            survey, survey_created = Survey.objects.get_or_create(**survey_data)

        validated_data['survey'] = survey
        instance = self.Meta.model(**validated_data)
        instance.save()
        return instance

1 个答案:

答案 0 :(得分:0)

我最终对Serializer进行了一系列更改以删除验证程序,并在创建和更新期间手动执行名称验证。让我知道是否有更惯用的方法!

class SurveySerializer(serializers.HyperlinkedModelSerializer):
     creator = serializers.ReadOnlyField(source='creator.username')

    def create(self, validated_data):
        if Survey.objects.filter(name=self.validated_data['name']).exists():
            raise serializers.ValidationError("A survey with this name already exists")
        return Survey.objects.create(**validated_data)

    def update(self, instance, validated_data):
        all_other_survey = Survey.objects.exclude(name=instance.name)
        if all_other_survey.filter(name=self.validated_data['name']).exists():
            raise serializers.ValidationError("A survey with this name already exists (Not counting this instance)")
        else:
            instance.name = self.validated_data['name'] or instance.name
        instance.save()
        return instance

    class Meta:
        model = Survey
        fields = '__all__'
        extra_kwargs = {
            'name': {
                'validators': [],
            }
        }