I am working on a simple performance management system with react on frontend and django on the backend. They are supervisors who can give reviews to supervisees and supervisees can respond. I want all employees to receive email when they receive reviews from their supervisors and all the supervisors to receive email when their reviews are responded. For reviews and responses I am using two different serializers but same model.
Serializer for Response is:
class ResponseSerializer(serializers.ModelSerializer):
supervisor_name = serializers.SerializerMethodField('get_supervisor_name')
supervisor_email = serializers.SerializerMethodField('get_supervisor_email')
supervisee_name = serializers.SerializerMethodField('get_supervisee_name')
supervisee_email = serializers.SerializerMethodField('get_supervisee_email')
class Meta:
model = Review
fields = (
'id', 'review_text', 'response_text', 'date_of_review', 'date_of_response', 'supervisor', 'supervisor_name',
'supervisor_email', 'supervisee', 'supervisee_name', 'supervisee_email')
read_only_fields = ('review_text', 'date_of_review', 'supervisor', 'supervisee')
def get_supervisor_name(self, obj):
return obj.supervisor.first_name + " " + obj.supervisor.last_name
def get_supervisor_email(self, obj):
return obj.supervisor.email
def get_supervisee_name(self, obj):
return obj.supervisee.first_name + " " + obj.supervisee.last_name
def get_supervisee_email(self, obj):
return obj.supervisee.email
For sending mail I am using send_mail method from django.core And I am using Viewsets for Reviews and Responses.
Now Response operation will always be an update operation because Response will always be used to update existing Review object in which response_text field will be updated.
class ResponseViewSet(viewsets.ModelViewSet):
queryset = Review.objects.all()
permission_classes = [
# permissions.IsAuthenticated,
permissions.AllowAny,
]
serializer_class = ResponseSerializer
def update(self, request, *args, **kwargs):
serializer = ResponseSerializer(data=request.data)
if serializer.is_valid():
supervisor = serializer.data["supervisor_name"]
supervisee = serializer.data["supervisee_name"]
query = serializer.save()
mail_text = "Hi {}\n\nYou got a response for your 1:1 from {}.\n\nClick below to see the response:\n\n{}".format(
supervisor,
supervisee,
"https://example.com/#/pms/reviewsBySupervisor",
)
try:
if not settings.DEFAULT_EMAIL_RECIPIENTS:
settings.DEFAULT_EMAIL_RECIPIENTS.append(
str(serializer.data["supervisor_email"])
)
send_mail(
subject="New Response Received",
message=mail_text,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=settings.DEFAULT_EMAIL_RECIPIENTS,
fail_silently=False,
)
except (SMTPRecipientsRefused, SMTPSenderRefused):
LOGGER.exception("There was a problem submitting the form.")
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
So, the problem that I am facing is that when I try to send mail with update method in ResponseViewset as shown above. I get the following error:
Internal Server Error: /UMS/api/responses/38/
Traceback (most recent call last):
File "/home/shishir/Projects/performance_management/performance_management/reviews/serializers.py", line 77, in get_supervisor_name
return obj.supervisor.first_name + " " + obj.supervisor.last_name
AttributeError: 'NoneType' object has no attribute 'first_name'
So, what is happening is due to some reason, all the fields of that particular review are getting set to null as soon as I try to update and hence getting NoneType object has no attribute. I have checked in database table(MySQL), all the fields are getting set to null. Can anyone tell me why is this happening ? Where am I going wrong ? And what is the correct way to do it?