Somil
Somil

Reputation: 1941

Django Rest framework, how to include '__all__' fields and a related field using foreignkey_id field

So here is my files - Models.py

class Model1(models.Model):
    user = models.ForeignKey(User)
    other_fields = models.CharField(max_length=40)

Serializers.py

class MySerializer(ModelSerializer):
    class Meta:
        model = Model1
        fields = '__all__'


Here  json request
{"user_id":1, "other_fields":"details"}

and in views.py

serializer = MySerializer(data=request.data)
serializer.data

**Throws keyerror "user"**

When i try to change request parameter "user_id" to "user" it works for me . But I can't change request json. Is there any way to handle this issue in serializer?

I can set all the fields inplace of '_all_' but it is not a good solution due to large number of fields .

I also tried with -

 class MySerializer(ModelSerializer):
    user = serializers.CharField(source='user_id')
    class Meta:
        model = Model1
        fields = '__all__'

but it was not worked for me.

Upvotes: 0

Views: 914

Answers (3)

Tobey
Tobey

Reputation: 1440

Try using PrimaryKeyRelatedField

class MySerializer(ModelSerializer):

    def to_internal_value(self, data):
        data = data.copy() # incase request data is immutable
        data['user'] = data['user_id']
        return super().to_internal_value(data)

    user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())

    class Meta:
        model = Model1
        fields = '__all__'

This should allow for payload:

 {"user_id": 1, "other_fields": "details"}

Upvotes: 1

Ehsan Nouri
Ehsan Nouri

Reputation: 2040

try this:

class MySerializer(ModelSerializer):
    user_id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), source='user', write_only=True)
    class Meta:
        model = Model1
        fields = '__all__'

Upvotes: 1

JPG
JPG

Reputation: 88619

I assume you are using viewset class for your views. then this will work

Override the __init__ method as,

class MySerializer(ModelSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'view' in self.context and self.context['view'].action in ['create', 'update', 'partial_update']:
            self.fields['user_id'] = self.fields.pop('user')

    class Meta:
        model = Model1
        fields = '__all__'



The ['create', 'update', 'partial_update'] are the actions of viewset class which are representing HTTP POST, HTTP PUT and HTTP PATCH respectively.

Upvotes: 1

Related Questions