2014-12-21 19 views
13

SituationZusätzliche Serializer Felder in Django REST-Framework 3

ich einen einfachen Endpunkt bin schaffen, die für die Erstellung eines Benutzers ermöglicht. Ich brauche ein Feld, das nicht in meinem Benutzermodell ist (d. H. confirm_password). Ich werde Validierung ausführen, die dieses Feld mit einem anderen Feld vergleicht, das sich in meinem Modell befindet, und das zusätzliche Feld nie wieder in dem Serialisierungsprogramm verwenden.

Problem

DRF Version 3 hat den Prozess verändert dies zu erreichen, und ich verstehe nicht ganz, was die Dokumentation schlägt vor, ich tun. Die Dokumentation finden Sie unter here.

Versuch Lösung

ich eine UserSerializer erstellt haben, die wie folgt aussieht:

from django.contrib.auth import get_user_model 
from rest_framework import serializers 

class UserSerializer(serializers.ModelSerializer): 
    confirm_password = serializers.CharField(allow_blank=False) 

    def validate(self, data): 
     """ 
     Checks to be sure that the received password and confirm_password 
     fields are exactly the same 
     """ 
     if data['password'] != data.pop('confirm_password'): 
      raise serializers.ValidationError("Passwords do not match") 
     return data 

    def create(self, validated_data): 
     """ 
     Creates the user if validation succeeds 
     """ 
     password = validated_data.pop('password', None) 
     user = self.Meta.model(**validated_data) 
     user.set_password(password) 
     user.save() 
     return user 

    class Meta: 
     # returns the proper auth model 
     model = get_user_model() 
     # fields that will be deserialized 
     fields = ['password', 'confirm_password', 
        'username', 'first_name', 'last_name', 'email'] 
     # fields that will be serialized only 
     read_only_fields = ['is_staff', 'is_superuser'] 
     # fields that will be deserialized only 
     write_only_fields = ['password' 'confirm_password'] 

Ich hatte gehofft, dass confirm_password in validate popping meiner Probleme kümmern würde, aber ich habe nur die folgende:

Erhalten KeyError beim Versuch, ein zu erhalten Wert für das Feld confirm_password am Serializer UserSerializer. Der Serializer Feld könnte falsch und nicht überein jedes Attribut oder Taste auf der

+0

Nur ein Heads-up, ist es üblich, für die meisten Menschen die setzen Meta-Klasse an der Spitze des Serialisierers, da sie die meisten Informationen enthält, nach denen Sie normalerweise suchen. –

+0

Ah, das würde Sinn machen. Ich schätze es! – nmagerko

Antwort

18

Sie suchen einen schreibgeschützten Feld OrderedDict Instanz mit dem Namen, wie ich nehme an, Sie werden nicht die Passwortbestätigung angezeigt werden soll in die API. Django REST Framework führte den write_only-Parameter in der 2.3.x-Zeitleiste ein, um den Parameter read_only zu ergänzen, sodass die einzige Zeitvalidierung ausgeführt wird, wenn ein Update durchgeführt wird. Die Meta-Eigenschaft write_only_fields wurde ungefähr zur gleichen Zeit hinzugefügt, aber es ist wichtig zu verstehen, wie diese beiden zusammenarbeiten.

Die write_only_fields Meta-Eigenschaft wird die write_only Eigenschaft auf ein Feld automatisch hinzu, wenn es automatisch erstellt wird, wie für ein password Feld auf ein User Modell. Es wird nicht tun dies für alle Felder, die nicht auf dem Modell sind, oder Felder, die explizit auf dem Serialisierungsprogramm angegeben wurden. In Ihrem Fall geben Sie das Feld confirm_password auf Ihrem Serializer explizit an, weshalb es nicht funktioniert.

KeyError Got beim Versuch, einen Wert für das Feld UserSerializerconfirm_password auf Serializer zu bekommen. Das Serializer Feld könnte während der erneuten Serialisierung des erstellten Benutzers Dies erhöht

falsch und nicht überein jedes Attribut oder Taste auf der OrderedDict Instanz mit dem Namen, wenn es versucht, Ihr confirm_password Feld serialisiert werden. Da das Feld im Modell User nicht gefunden werden kann, löst es diesen Fehler aus, der das Problem zu erklären versucht. Leider, weil dies auf einem neuen Benutzer ist, werden Sie aufgefordert, die OrderedDict Instanz anstelle der User Instanz zu betrachten.

class UserSerializer(serializers.ModelSerializer): 
    confirm_password = serializers.CharField(allow_blank=False, write_only=True) 

Wenn Sie explizit write_only auf dem Serializer Feld angeben, und entfernen Sie das Feld von Ihrem write_only_fields, dann sollten Sie das Verhalten sehen Ihre erwarten.

Sie können link

0

Auch nützlich für verschachtelte Serializer Implementierung darstellt Modelle auf dieser Dokumentation darüber finden, wenn das Wurzelmodell nicht direkt auf Felder, die Sie verwenden möchten, Zugriff hat. Danke @vyscond;) Fyi hier ist mein Fall:

models.py

class Company(models.Model): 
    permission_classes = (
     IsCompanyMember, 
    ) 

    name = models.CharField(
     unique=True, 
     max_length=100, 
     verbose_name='company name', 
     null=False 
    ) 
class Profile(models.Model): 

    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True) 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    is_company_admin = models.BooleanField(default=False, null=False) 
    is_email_validated = models.BooleanField(default=False, null=False) 
    is_approved_by_company_admin = models.BooleanField(default=False, null=False) 

serializer.py

class CompanySerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Company 
     fields = ('name',) 

class CustomUserRegistrationSerializer(serializers.ModelSerializer): 
    password = serializers.CharField(style={'input_type': 'password'}, 
           write_only=True, 
           validators=settings.get('PASSWORD_VALIDATORS')) 

    company = CompanySerializer(allow_null=False, required=True,write_only=True) 

    class Meta: 
     model = User 
     fields = ('username', 
        'email', 
        'password', 
        'company', 
        'first_name', 
        'last_name') 
Verwandte Themen