Hemkumar
Hemkumar

Reputation: 13

Not able to send email overriding create method django rest framework

I got to know that we can override create method in order to send email but it's not working with my code.

views.py:

class FileUploadView(APIView):
    parser_class = (MultiPartParser,)

    def post(self, request, *args, **kwargs):

      file_serializer = FileSerializer(data=request.data)

      if file_serializer.is_valid():
          file_serializer.save()
          return Response(file_serializer.data, status=status.HTTP_201_CREATED)
      else:
          return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def create(self, request, *args, **kwargs):
        response = super(FileUploadView, self).create(request, *args, **kwargs)
        send_email()  # sending mail
        return response

def send_email(request):
    email = EmailMessage(
        'Title',
        (FileSerializer.Fullname, FileSerializer.Email, FileSerializer.Contact),
        '[email protected]',
        ['[email protected]']
    )
    email.attach_file(FileSerializer.Upload)
    email.send()

Help me in figuring out what's the problem here

Edit: APIView doesn't support create method, above code doesn't work . I want to send the contents received from post method from rest API through a mail. Suggest me a proper method in order to do it with respect to above code.

Upvotes: 0

Views: 355

Answers (1)

alamshafi2263
alamshafi2263

Reputation: 659

APIView does not support create

You have got this part right. You want to send an email after the model object has been saved to database. Actually there are several ways to do that. You can do it from view, you can do it from your serializer, you can do it from your model, you can do it from a post_save signal hooked to your model. I am going to show you what was wrong with your code and then some of the other ways -

  1. The corrections to be made in your code that, you could call the send_email function just after file_serializer.save() in your FileUploadView.post
class FileUploadView(APIView):
   parser_class = (MultiPartParser,)

   def post(self, request, *args, **kwargs):

     file_serializer = FileSerializer(data=request.data)

     if file_serializer.is_valid():
         file_serializer.save()
         send_email() #sending Email
         return Response(file_serializer.data, status=status.HTTP_201_CREATED)
     else:
         return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def send_email(request):
   email = EmailMessage(
       'Title',
       (FileSerializer.Fullname, FileSerializer.Email, FileSerializer.Contact),
       '[email protected]',
       ['[email protected]']
   )
   email.attach_file(FileSerializer.Upload)
   email.send()
  1. This process also calls the send_email function from view, but this view is a bit different. This view inherits from generics.CreateAPIView
from rest_framework import generics

class FileUploadView(generics.CreateAPIView):
   serializer_class = FileUploadSerializer
   parser_class = [MultiParser, ]
   queryset = FileUploadModel.objects.all()

   def perform_create(self, serializer):
       serializer.save()
       send_email()

  1. You can call the send_email function from the create method of your seiralizer. You can override serializer.create method
class FileUploadSerializer(serializers.ModelSerializer):
    class Meta:
        model = FileUploadModel
        fields = ['your', 'model', 'fields']
    
    def create(self, validated_data):
        instance = super(FileUploadSerializer, self).create(validated_data)
        send_email()
        return instance

  1. Sending Email from your FileUploadModel model class. Here you override the save method of the model
class FileUploadModel(models.Model):
   ...your model fields definition...

   def save(self, *args, **kwargs):
       if not self.pk:  #assuming we want to send email only when object is created first time in database
           send_email()
       super(FileUploadModel, self).save(*args, **kwargs)

On catch about overriding model.save method is that, it will not be called when you're performing bulk operations. Also it will be called every time you save the model i.e. both create and update that's why we added the pk check. This logic will send email before the object is inserted in your database if you want to send email only when the object is completely saved in database then do the following way with signals

  1. You can hook a post_save signal to your model. In this way you send an email only after the object is saved in database
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=FileUploadModel)
def file_upload_post_save(sender, instance, **kwargs):
    send_email()

Catch with using signals is that it will not be called when you do bulk operation.

I am assuming you're fairly new to the django enviornment. You should also have a look on celery to perform long running background tasks such as - sending emails.

Upvotes: 2

Related Questions