Django Rest Framework - Create without providing a

2019-06-25 13:32发布

I'm building my first API with Django-Rest-Framework and I'm a little stuck with the validation process. Hopefully this is an easy answer but I couldn't figure it out from the 6-part intro tutorial...

I have a model:

class XYZMeta(models.Model):
    id = models.AutoField(primary_key=True)
    xyz_id = models.ForeignKey(XYZ)
    user_id = models.ForeignKey(User)
    field_name = models.CharField(blank=True, max_length=50)
    value = models.TextField(blank=True)

And a serializer:

class XYZMetaSerializer(serializers.ModelSerializer):
    class Meta:
        model = XYZMeta
        fields = ('id', 'xyz_id', 'user_id', 'field_name', 'value')

And a view:

class XYZMetaViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows xyz metadata to be viewed or edited.
    """
    queryset = XYZMeta.objects.all()
    serializer_class = serializers.XYZMetaSerializer

    def perform_create(self, serializer):
        serializer.save(user_id=self.request.user)

When I send a POST to create a new object, it works great and uses the ID of the authorized user rather than whatever value I provide. Example:

> curl -X POST -H "Content-Type:application/json" -d '{"xyz_id":"12345",**"user_id":2**,"field_name":"abc","value":"abc comment"}' -u admin:admin http://mysite/xyzmeta/
{"id":2,"dealer_id":12345,**"user_id":1**,"field_name":"abc","value":"abc comment","create_date":"2015-02-22T23:32:27.928991Z"}

However, if I leave the user_id off entirely (since it doesn't matter anyway), I get an error that the field is required:

> curl -X POST -H "Content-Type:application/json" -d '{"xyz_id":"12345","field_name":"abc","value":"abc comment"}' -u admin:admin http://mysite/xyzmeta/
{"user_id":["This field is required."]}

How do I specify that I want the user_id foreign key field to be programmatically set during the create process, and not have to provide a dummy value?

3条回答
叼着烟拽天下
2楼-- · 2019-06-25 14:10

How about just having required=False for user_id field?

I haven't tested this..but something like this should work!

class XYZMetaSerializer(serializers.ModelSerializer):
    user_id = serializers.RelatedField(source='user_id', required=False)

    class Meta:
        [...]
查看更多
Viruses.
3楼-- · 2019-06-25 14:10

Since the user_id is useless in the request, you could simply skip it from the serializer, and add it later in the ViewSet's perform_create method:

class XYZMetaViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows xyz metadata to be viewed or edited.
    """
    queryset = XYZMeta.objects.all()
    serializer_class = serializers.XYZMetaSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)
查看更多
我想做一个坏孩纸
4楼-- · 2019-06-25 14:22

One approach: make user_id field non-required

class XYZMetaSerializer(serializers.ModelSerializer):
    class Meta:
        model = XYZMeta
        fields = ('id', 'xyz_id', 'user_id', 'field_name', 'value')
        extra_kwargs = {
            'user_id': {'required': False}
        }

Another approach: alter request.data before the get_serializer(data=request.data) method call.

class XYZMetaViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows xyz metadata to be viewed or edited.
    """
    queryset = XYZMeta.objects.all()
    serializer_class = serializers.XYZMetaSerializer

    def create(self, request, *args, **kwargs):
        request.data['user_id'] = request.user.id
        return super(self.__class__, self).create(request, *args, **kwargs)
查看更多
登录 后发表回答