2015-12-02 13 views
7

Ho un modulo di contatto su un sito che sta postando su un CreateAPIView per creare una nuova istanza di un modello (che alla fine verrà inviato all'amministratore) . Sul mio serializzatore ho un campo honeypot per aiutare a respingere lo spam.DRF: rimuovere il campo sul serializzatore del modello dopo la convalida ma prima della creazione (su CreateAPIView)

Il modello:

class Message(models.Model): 
    name = ... 
    message = ... 

e serializzatore:

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 

e panorama:

class MessageView(generics.CreateAPIView): 
    ''' Create a new contact form message. ''' 
    serializer_class = MessageSerializer 

mio problema è che così com'è, quando ho posto questo punto di vista, io visualizza l'errore:

TypeError: Got a TypeError when calling Message.objects.create() . This may be because you have a writable field on the serializer class that is not a valid argument to Message.objects.create() . You may need to make the field read-only, or override the MessageSerializer.create() method to handle this correctly.

quindi ovviamente la seriazlier sta tentando di salvare il campo url al modello CreateApiView.perform_create()

Ho provato ad aggiungere read_only al campo serializzatore, ma questo significa che il metodo url_validate viene saltato tutto.

Come è possibile mantenere il campo sul serializzatore fino a quando non si è verificata la convalida, rimuovendolo prima che venga chiamato in perform_create()?

risposta

5

si può fare questo l'override del metodo create come:

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) 
+0

Ah, ho capito e pubblicato esattamente come hai fatto. Puoi avere i punti;) –

+2

grazie per la tua risposta, ma 'Message.objects.create (** data)' non è corretto dovresti passare 'validated_data' invece intendo' Message.objects.create (** validated_data) ' – shotgunner

0

OK, non ho letto l'errore correttamente. Come si dice chiaramente:

override the MessageSerializer.create() method to handle this correctly.

stavo guardando sovrascrivendo il metodo CreateAPIView.create() che non aveva senso.

Questo funziona:

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) 
Problemi correlati