I have a contact form on a site that is posting to a CreateAPIView
to create a new instance of a model (that is eventually emailed to the admin). On my serializer I have a honeypot field to help reject spam.
The model:
class Message(models.Model):
name = ...
message = ...
and serializer:
class MessageSerializer(serializers.ModelSerializer):
# Honeypot field
url = serializers.CharField(allow_blank=True, required=False)
class Meta:
model = Message
fields = '__all__'
def validate_url(self, value):
if value and len(value) > 0:
raise serializers.ValidationError('Spam')
return value
and view:
class MessageView(generics.CreateAPIView):
''' Create a new contact form message. '''
serializer_class = MessageSerializer
My problem is that as it stands, when I post to this view, I get the error:
TypeError: Got a
TypeError
when callingMessage.objects.create()
. This may be because you have a writable field on the serializer class that is not a valid argument toMessage.objects.create()
. You may need to make the field read-only, or override the MessageSerializer.create() method to handle this correctly.
so obviously the seriazlier is attempting to save the url
field to the model in CreateApiView.perform_create()
I tried adding read_only
to the serializer field, but this means that the url_validate
method is skipped altogether.
How can I keep the field on the serializer until validation has occurred, removing it before the serializer.save()
is called in perform_create()
?
you can do this overriding the create method like:
class MessageSerializer(serializers.ModelSerializer):
# Honeypot field
url = serializers.CharField(allow_blank=True, required=False)
class Meta:
model = Message
fields = '__all__'
def validate_url(self, value):
if value and len(value) > 0:
raise serializers.ValidationError('Spam')
return value
def create(self, validated_data):
data = validated_data.pop('url')
return Message.objects.create(**data)
OK, I didn't read the error correctly. As it clearly says:
override the MessageSerializer.create() method to handle this correctly.
I was looking at overwriting the CreateAPIView.create()
method which didn't make sense.
This works:
class MessageSerializer(serializers.ModelSerializer):
# Honeypot field
url = serializers.CharField(allow_blank=True, required=False)
class Meta:
model = Message
fields = '__all__'
def validate_url(self, value):
if value and len(value) > 0:
raise serializers.ValidationError('Error')
return value
def create(self, validated_data):
if "url" in validated_data:
del validated_data["url"]
return Message.objects.create(**validated_data)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With