Marco Fernandes
Marco Fernandes

Reputation: 553

Django: How to check if data is correct before saving it to a database on a post request?

I would like to be able to parse the data from a post request in my django rest api project by sending it to my function that will return true or false if the number is valid before saving it to the database and if it's wrong send a custom bad request message to the client that did the request.

I've been told I can overwrite the create method todo this but I'm not sure how to go about it.

My code so far looks like this:

class Messages(models.Model):
    phone_number = models.CharField(max_length=256, default='')
    message_body = models.CharField(max_length=256, default='')
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.phone_number + ' ' + self.message_body + ' ' + self.created

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        # I assume this is where I would do the check before saving it but not sure how? example would be like:
        # if numberValid(self.phone_number):
        #    then save to the database
        # else:
        #    then send back a bad request?
        super(Messages, self).save(force_update=force_update)
        send_sms(self.phone_number, self.message_body)

    def delete(self, using=None, keep_parents=False):
        super(Messages, self).delete(using=using, keep_parents=keep_parents)

So basically just would like some direction on how to solve this problem. Even helpful links would be appreciated. I did look on stackoverflow but was not successful, maybe I don't know how to phrase the question right when searching.

Upvotes: 6

Views: 10471

Answers (4)

ruddra
ruddra

Reputation: 51938

You can use DRF Serializer's validation. For example, create a serializer, and add a validation method naming validate_<field_name>. Then add the validation code there:

import re

class MessagesSerializer(serializers.ModelSerializer):
    class Meta:
        model = Messages
        fields = "__all__"

    def validate_phone_number(self, value):
        rule = re.compile(r'(^[+0-9]{1,3})*([0-9]{10,11}$)')
        if not rule.search(value):
            raise serializers.ValidationError("Invalid Phone Number")
        return value

And use it in the view:

class SomeView(APIView):
    def post(self, request, *args, **kwargs):
       serializer = MessagesSerializer(
            data=request.data
        )
       if serializer.is_valid():  # will call the validate function
          serializer.save()
          return Response({'success': True})
       else:
          return Response(
               serializer.errors,
               status=status.HTTP_400_BAD_REQUEST
          )

Upvotes: 8

Nelson Sequiera
Nelson Sequiera

Reputation: 1374

You want to validate the fields before saving.

There are quite a few techniques to do that.

For your scenario i would suggest second option. Override the method clean_fields as in documentation. Then call the method just before saving.

Upvotes: 1

ritlew
ritlew

Reputation: 1682

Check the official documentation for how this is to be done: https://docs.djangoproject.com/en/2.2/ref/models/instances/#django.db.models.Model.clean

This method should be used to provide custom model validation, and to modify attributes on your model if desired. For instance, you could use it to automatically provide a value for a field, or to do validation that requires access to more than a single field:

def clean(self):
    # Don't allow draft entries to have a pub_date.
    if self.status == 'draft' and self.pub_date is not None:
        raise ValidationError(_('Draft entries may not have a publication date.'))
    # Set the pub_date for published items if it hasn't been set already.
    if self.status == 'published' and self.pub_date is None:
        self.pub_date = datetime.date.today()

Implement a clean method that will raise a ValidationError if it detects a problem with the data. You can then catch this in the view by calling model_obj.full_clean():

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
try:
    article.full_clean()
except ValidationError as e:
    non_field_errors = e.message_dict[NON_FIELD_ERRORS]

Upvotes: 2

Dwight Gunning
Dwight Gunning

Reputation: 2525

Model.save() is an option although it's more common to validate input data, like a phone number being posted, in the DRF Serializer.

Where to perform checks is a decision you can make based on the principal of separation of concerns.

Upvotes: 1

Related Questions