1
votes

Comment implémenter update_or_create dans la méthode create de ModelSerializer

Le code:

class OTP(AppModel):
    phone_regex = RegexValidator(regex=r'^[6789]\d{9}$', message="phone no. is invalid.")
    phone_number = models.CharField(validators=[phone_regex], max_length=10, unique=True)
    code = models.CharField(max_length=255)

    def __str__(self):
        return str(self.phone_number) + ": "+str(self.code)

class OTPSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=None, required=False)
    class Meta:
        model = OTP
        fields = ('id', 'code', 'phone_number')
        read_only_fields=('id', 'code')

    @transaction.atomic
    def create(self, validated_data):
        phone_number = validated_data.pop("phone_number")
        otp, created = OTP.objects.update_or_create(
            phone_number=phone_number, defaults={"code": generate_otp()})
        return otp

J'essaye de faire update_or_create dans la méthode create du django-rest- ModelSerializer du framework .

Mais, le champ phone_number à l'intérieur du modèle OTP doit être unique . D'où le unique=True.

J'ai pu poster un phone_number et créer l'objet. Mais, publier le même phone_number renvoie à nouveau l'erreur otp avec ce numéro de téléphone existe déjà , au lieu de le mettre à jour s'il existe déjà car j'ai remplacé le create code> méthode. Veuillez aider!


0 commentaires

3 Réponses :


0
votes

Vous pouvez rendre phone_number NON obligatoire, puis effectuer manuellement la vérification. Vous obtenez l'erreur, car DRF a validé phone_number avant vous. Donc, en gros, la solution pourrait être la suivante (code du sérialiseur uniquement):

class OTPSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=None, required=False)
    class Meta:
        model = OTP
        fields = ('id', 'code', 'phone_number')
        read_only_fields=('id', 'code')
        extra_kwargs = {'phone_number': {'required': False}}

    @transaction.atomic
    def create(self, validated_data):
        phone_number = validated_data.pop("phone_number")
        otp, created = OTP.objects.update_or_create(
        phone_number=phone_number, defaults={"code": generate_otp()})
        return otp


1 commentaires

Non, le phone_number est obligatoire. Et le problème est: UniqueValidator valide avant d'atteindre la méthode create .



0
votes

Essayez de définir le validateur dans votre classe de sérialiseur plutôt que dans la classe de modèle. Alors, faites ressembler votre classe de sérialiseur à quelque chose comme ceci:

class OTPSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=None, required=False)
    phone_regex = RegexValidator(regex=r'^[6789]\d{9}$', message="phone no. is invalid.")  # add this line
    phone_number = serializers.CharField(validators=[phone_regex])  # and this line
    
    class Meta:
        model = OTP
        fields = ('id', 'code', 'phone_number')
        read_only_fields=('id', 'code')

    @transaction.atomic
    def create(self, validated_data):
        phone_number = validated_data.pop("phone_number")
        otp, created = OTP.objects.update_or_create(
            phone_number=phone_number, defaults={"code": generate_otp()})
        return otp


0 commentaires

0
votes

Vous pouvez utiliser Signals pour le faire de manière propre. Simplement, vous pouvez envoyer une variable créée à un récepteur que vous définissez, et la traiter en fonction de la création ou non de votre objet. dans le cas de la réponse REST, remplacez simplement la méthode create dans le sérialiseur pour renvoyer des données en fonction de l'état dans lequel vous vous trouvez, ou la méthode get / post / patch vous utilisez dans l'APIView pour ne pas renvoyer serializer.data , mais renvoyer à la place ce que vous voulez. Voici un exemple de récepteur de signal:

@receiver(post_save, sender=settings.OTP_MODEL)
def update(sender, instance=None, created=False, **kwargs):
    if created:
        # Do Something
    else:
        # Do Some Other thing


0 commentaires