HFX
HFX

Reputation: 592

rest framework how to create optional nested object?

DRF 3.1.3,Django 1.8.3

i have several model just like following code:

Post

class Post(models.Model):
    class Meta:
        ordering = ['-updated_time']

    author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
    circle = models.ForeignKey('circle')

    TYPE_CHOICES = (
        ('M', _('Members')),
        ('O', _('Org')),
    )
    type = models.CharField(_('Type'), choices=TYPE_CHOICES, default='M', max_length=1, help_text=u"帖子类型,是成员发帖,还是组织发帖?")

    created_time = models.DateTimeField(auto_now_add=True, db_index=True, editable=False)
    updated_time = models.DateTimeField(auto_now=True, db_index=True, editable=False)

    like = models.PositiveIntegerField(default=0)

    comments = GenericRelation(PostComment)
    images = GenericRelation(PostImage)
    likes = GenericRelation(PostLike)

    is_removed = models.BooleanField(_('Is Removed'), default=False, db_index=True)

RichPost

class RichPost(models.Model):
    title = models.CharField(max_length=100)
    summary = models.TextField(max_length=560)
    content = models.TextField(max_length=16000)

    post = models.OneToOneField(Post, related_name='rich')

SimplePost

class SimplePost(models.Model):
    content = models.TextField(max_length=560)
    post = models.OneToOneField(Post, related_name='simple')

PostSerializer

class PostSerializer(serializers.ModelSerializer):
    images = PostImageSerializer(many=True)

    simple = SimplePostSerializer(many=False)
    rich = RichPostSerializer(many=False)

    is_liked = serializers.SerializerMethodField('is_liked_by_user')

    def create(self, validated_data):
        simple = validated_data.pop('simple')
        rich = validated_data.pop('rich')
        post = Post.objects.create(**validated_data)
        return post

    def is_liked_by_user(self, obj):
        request = self.context['request']
        obj_type = ContentType.objects.get_for_model(obj)
        if PostLike.objects.filter(author=request.user, content_type__pk=obj_type.id, object_id=obj.id).exists():
            return True
        else:
            return False

    class Meta:
        model = Post
        fields = ('id', 'author', 'circle', 'type', 'created_time', 'updated_time', 'like', 'is_removed',
                  'images', 'comments_count', 'is_liked', 'simple', 'rich')
        read_only_fields = ('comments_count', 'is_liked', 'created_time', 'updated_time', 'like', 'author')

Post belongs one of RichPost and SimplePost.

when i created the Post,both of them are required.

for instance,when i sent simple.content,the rich.title,rich.summary,rich.content are required.

then,i found the api document: writable-nested-representations

i overrode .create() methods

but it does not been invoked at all,is_valid() before attempting to access the validated data, or save an object instance

Anyone has an idea?Thanks for any answer.

Upvotes: 1

Views: 644

Answers (2)

HFX
HFX

Reputation: 592

When i from DRF 3.1.3 upgraded to DRF 3.2.2,I don't know what was going on,it just works :(

It pass through .is_valid() to reach the .create().

Upvotes: 0

miki725
miki725

Reputation: 27861

Both rich and simple posts are required in your serializer. You should make them optional. If you need at least one of them to be required, you can do that in validate():

class PostSerializer(serializers.ModelSerializer):
    simple = SimplePostSerializer(required=False)
    rich = RichPostSerializer(required=False)
    ...
    def validate(self, data):
        data = super(PostSerializer, self).validate(data)
        if not any([data.get('simple'), data.get('rich')]):
            raise serializers.ValidationError('Either simple or rich is required')
        return data

Upvotes: 2

Related Questions