ArtSav
ArtSav

Reputation: 162

DRF Foreignkey serialization

I can't save model with Foreignkey field.

Thanks to "azudo" problem solved. Solution below

For example I have simple models:

class User(AbstractUser):
    class Meta:
        pass

    email_validator = EmailValidator()
    username = models.CharField('Name', max_length=150, )
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField('Email', blank=True, unique=True, validators=[email_validator], )
    ...

class Package(models.Model):

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='packages')
    description = models.CharField('Description', max_length=256, default='description')
    weight = models.CharField('weight', max_length=256, default='weight')
    ...

View (the user is guaranteed to be in the request):

@api_view(["POST"])
def test(request):
    data = request.data
    data['user'] = User.objects.get(id=request.user.id)
    serializer = PackageSerializer(data=data)
    if serializer.is_valid():
        serializer.save()
        return JsonResponse(serializer.data)
    else:
        return JsonResponse(serializer.errors)

My serializers:

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'


class PackageSerializer(ModelSerializer):

    class Meta:
        model = Package
        fields = (
            'user', 'description', 'weight', 'dimensions', 'estimated_shipping_cost', 'deliver_to_date')

    def to_representation(self, instance):
        self.fields['user'] = UserSerializer(many=False, read_only=True)
        self.fields['where_from'] = LocationSerializer(many=False, read_only=True)
        self.fields['destination'] = LocationSerializer(many=False, read_only=True)
        return super().to_representation(instance)

    def create(self, validated_data):
        user = User.objects.get(validated_data.pop('user'))
        package = Package.objects.create(user=user, **validated_data)
        return package

json in request:

{
    "description": "Some package",
    "weight": "12",
}

So, I'have user in database, and want create package for him. But in overridden create in PackageSerializer, validated_data doesn't have user. Please explain what I'm doing wrong.

Versions of django and drf:

django==2.2.4
djangorestframework==3.10.2   

Solution:

Serializer:

class PackageSerializer(ModelSerializer):
    user = UserSerializer(many=False, read_only=True)

    class Meta:
        model = Package
        fields = (
            'user', 'description', 'weight', 'dimensions', 'estimated_shipping_cost', 'deliver_to_date')

    def create(self, validated_data):
        user = User.objects.get(validated_data.pop('user'))
        package = Package.objects.create(user=user)
        return package

View:

@api_view(["POST"])
def create_package(request):
    data = request.data
    serializer = PackageSerializer(data=data)
    if serializer.is_valid():
        serializer.save(user=request.user)
        return JsonResponse(serializer.data)
    else:
        return JsonResponse(serializer.errors)

Upvotes: 0

Views: 104

Answers (1)

azundo
azundo

Reputation: 6052

DRF will ignore included fields that are marked as read-only so the caller cannot include read-only data. If you want to include additional attributes simply pass them as keyword args to save: https://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save

e.g.

@api_view(["POST"])
def test(request):
    data = request.data
    serializer = PackageSerializer(data=data)
    if serializer.is_valid():
        serializer.save(user=request.user)
        return JsonResponse(serializer.data)
    else:
        return JsonResponse(serializer.errors)

Upvotes: 1

Related Questions