methuselah
methuselah

Reputation: 13216

Reject POST request if particular columns are not unique

How can I prevent a POST request from being saved if the following items: 'email', 'youtube_channel_username', 'youtube_channel_url', 'youtube_channel_title' already exist in the database? In effect, I want to add a validation step that ensures that what the user is trying to post is unique for the above-mentioned. Ideally the server should send back an error message to the user informing them that their request failed for whatsoever reason.

Here is my code so far. I am not sure where to add this feature, so I would appreciate some help!

serializers.py

class CreatorSignupSerializer(serializers.Serializer):
    """
    Create Creator profile
    """
    first_name = serializers.CharField(required=True, write_only=True)
    last_name = serializers.CharField(required=True, write_only=True)
    email = serializers.CharField(required=True, write_only=True)
    youtube_channel_username = serializers.CharField(required=True, write_only=True)
    youtube_channel_url = serializers.CharField(required=True, write_only=True)
    youtube_channel_title = serializers.CharField(required=True, write_only=True)
    youtube_channel_description = serializers.CharField(required=True, write_only=True)
    photo = serializers.CharField(required=True, write_only=True)
    youtube_channel_start_date = serializers.CharField(required=True, write_only=True)
    keywords = serializers.CharField(required=True, write_only=True)
    no_of_subscribers = serializers.IntegerField(required=True, write_only=True)
    no_of_videos = serializers.IntegerField(required=True, write_only=True)
    no_of_views = serializers.IntegerField(required=True, write_only=True)
    no_of_likes = serializers.IntegerField(required=True, write_only=True)
    no_of_dislikes = serializers.IntegerField(required=True, write_only=True)
    location = serializers.CharField(required=True, write_only=True)
    avg_views = serializers.IntegerField(required=True, write_only=True)
    gender = serializers.IntegerField(required=True, write_only=True)
    password = serializers.CharField(required=True, write_only=True)

    class Meta:
        model = Creator
        fields = (
            'first_name', 'last_name', 'email', 'youtube_channel_username', 'youtube_channel_url',
            'youtube_channel_title', 'youtube_channel_description', 'photo', 'youtube_channel_start_date', 'keywords',
            'no_of_subscribers', 'no_of_videos', 'no_of_views', 'no_of_dislikes', 'no_of_likes' 'location', 'avg_views',
            'gender', 'password',
        )
        read_only_fields = 'id'

    def create(self, validated_data):
        creator = Creator.objects.create(**validated_data)
        creator.save()
        return creator

    def update(self, instance, validated_data):
        pass

views.py

class CreatorSignup(generics.CreateAPIView):
    """
    Creator signup
    HTTP POST
    """
    queryset = Creator.objects.all()
    serializer_class = CreatorSignupSerializer

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        return Response(data=serializer.data, status=status.HTTP_201_CREATED)

Upvotes: 1

Views: 48

Answers (2)

Manan Mehta
Manan Mehta

Reputation: 5919

You can achieve unique validation at the Model level very easily. You just have to override save to call the full_clean method (if you have any other validation at the model level). Moreover, as a note, it will throw django.exceptions.ValidationError and you can configure DRF to catch django.exceptions.ValidationError and convert it to rest_framework.exceptions.ValidationError and then DRF will automatically send a good error message back with 400.

# models.py
class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=255, unique=True)  # NOTE unique=True
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    phone = models.CharField(max_length=20)

    def save(self, *args, **kwargs):
        self.full_clean()
        return super().save(*args, **kwargs)

Upvotes: 3

JPG
JPG

Reputation: 88569

What about adding unique_together in models' Meta class, as below

class Creator(models.Model):
    email = models.EmailField()
    youtube_channel_username = some_field
    youtube_channel_url = some_field
    youtube_channel_title = some_field

    # etc
    class Meta:
        unique_together = ('email', 'youtube_channel_username', 'youtube_channel_url', 'youtube_channel_title')


Note : If you add this, you dont have to define any special validator method in your serializers

Upvotes: 2

Related Questions