如何在 Django Rest Framework 的视图集中使用更新方法并执行一些任务(如发送邮件)?
How to use update method in viewsets in Django Rest Framework and perform some task(like sending mail) along with it?
我正在开发一个简单的性能管理系统,前端有反应,后端有 django。他们是主管,可以对受监管者进行评论,受监管者可以做出回应。我希望所有员工在收到主管的评论时都能收到电子邮件,并且所有主管在他们的评论得到回复时都能收到电子邮件。对于评论和回复,我使用了两个不同的序列化器,但模型相同。
响应的序列化器是:
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
为了发送邮件,我正在使用 django.core
中的 send_mail 方法,并且我正在使用视图集进行评论和回复。
现在 Response 操作将始终是更新操作,因为 Response 将始终用于更新 response_text
字段将被更新的现有 Review 对象。
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)
所以,我面临的问题是,当我尝试在 ResponseViewset 中使用 update
方法发送邮件时,如上所示。我收到以下错误:
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'
所以,发生的事情是由于某种原因,当我尝试更新并因此获得 NoneType object has no attribute
时,该特定评论的所有字段都设置为 null
。我检查了数据库 table(MySQL),所有字段都设置为空。谁能告诉我为什么会这样?我哪里错了?正确的做法是什么?
最后我通过将方法 update
更改为 partial_update
找到了解决方案。显然,更新方法更新了所有字段,而在上述情况下,我正在尝试 Review 模型中名为 response_text
的字段,如果可能的话,将其他字段设置为 null。同样在这样做之后,我不得不在前端将请求从 PUT
更改为 PATCH
。此外,我还必须进行一些其他较小的编码更改,例如从 ResponseSerializer
中删除 read_only_fields
中的 supervisor
和 supervisee
字段。 ResponseViewset
的更新代码如下所示:
class ResponseViewSet(viewsets.ModelViewSet):
queryset = Review.objects.all()
permission_classes = [
permissions.IsAuthenticated,
#permissions.AllowAny,
]
serializer_class = ResponseSerializer
def partial_update(self, request,*args, **kwargs):
obj = self.get_object()
serializer = self.serializer_class(obj, data=request.data, partial=True)
if serializer.is_valid():
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(
serializer.data["supervisor_name"],
serializer.data["supervisee_name"],
get_product_link("UMS/reviewsForDR"),
)
try:
if not settings.DEFAULT_EMAIL_RECIPIENTS:
settings.DEFAULT_EMAIL_RECIPIENTS.append(
# supervisor_email
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,
)
settings.DEFAULT_EMAIL_RECIPIENTS = []
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)
我正在开发一个简单的性能管理系统,前端有反应,后端有 django。他们是主管,可以对受监管者进行评论,受监管者可以做出回应。我希望所有员工在收到主管的评论时都能收到电子邮件,并且所有主管在他们的评论得到回复时都能收到电子邮件。对于评论和回复,我使用了两个不同的序列化器,但模型相同。
响应的序列化器是:
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
为了发送邮件,我正在使用 django.core
中的 send_mail 方法,并且我正在使用视图集进行评论和回复。
现在 Response 操作将始终是更新操作,因为 Response 将始终用于更新 response_text
字段将被更新的现有 Review 对象。
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)
所以,我面临的问题是,当我尝试在 ResponseViewset 中使用 update
方法发送邮件时,如上所示。我收到以下错误:
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'
所以,发生的事情是由于某种原因,当我尝试更新并因此获得 NoneType object has no attribute
时,该特定评论的所有字段都设置为 null
。我检查了数据库 table(MySQL),所有字段都设置为空。谁能告诉我为什么会这样?我哪里错了?正确的做法是什么?
最后我通过将方法 update
更改为 partial_update
找到了解决方案。显然,更新方法更新了所有字段,而在上述情况下,我正在尝试 Review 模型中名为 response_text
的字段,如果可能的话,将其他字段设置为 null。同样在这样做之后,我不得不在前端将请求从 PUT
更改为 PATCH
。此外,我还必须进行一些其他较小的编码更改,例如从 ResponseSerializer
中删除 read_only_fields
中的 supervisor
和 supervisee
字段。 ResponseViewset
的更新代码如下所示:
class ResponseViewSet(viewsets.ModelViewSet):
queryset = Review.objects.all()
permission_classes = [
permissions.IsAuthenticated,
#permissions.AllowAny,
]
serializer_class = ResponseSerializer
def partial_update(self, request,*args, **kwargs):
obj = self.get_object()
serializer = self.serializer_class(obj, data=request.data, partial=True)
if serializer.is_valid():
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(
serializer.data["supervisor_name"],
serializer.data["supervisee_name"],
get_product_link("UMS/reviewsForDR"),
)
try:
if not settings.DEFAULT_EMAIL_RECIPIENTS:
settings.DEFAULT_EMAIL_RECIPIENTS.append(
# supervisor_email
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,
)
settings.DEFAULT_EMAIL_RECIPIENTS = []
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)