Django 2.0,Python 3.6,Django Rest Framework 3.8
我仍然对Django Rest Framework还是很陌生,我正在努力将观点包裹在视图集中使用函数的逻辑上(即使这是包含函数的正确位置)。
基本上,我想在用户在此特定视图集中将某些内容发布到api时发送电子邮件。我尝试使用send_mail
函数,但未成功。我有以下基于类的视图:
class SendInviteView(viewsets.ModelViewSet):
queryset = models.Message.objects.all()
serializer_class = serializers.MessageSerializer
@action(methods=['post'], detail=True)
def send_the_mail(self, request):
send_mail(
'Invitation',
'Try our app!',
'exampleemail@gmail.com',
['examplerecipient@gmial.com'],
fail_silently=False,
)
[模型和序列化器是非常基本的,对于这个问题,我认为不需要,基本上只是一个EmailField()。我最终计划使用该电子邮件字段的输入来替换examplerecipient@gmail.com
,但现在我只想了解如何向视图集添加功能]
运行python manage.py check
我通过sendgrid设置了我的电子邮件客户端,并且能够成功地将电子邮件发送给要求通过rest-auth
重设密码的用户,但是我不了解在该上下文之外如何发送电子邮件
非常感谢您的帮助。
答案 0 :(得分:5)
讨论之后,我将提出以下建议。
from django.conf import settings
from django.core.mail import send_mail
from django.db import models
from rest_framework import serializers, viewsets, routers, mixins
from rest_framework.response import Response
class Message(models.Model):
sender = models.ForeignKey(settings.AUTH_USER_MODEL)
recipient = models.EmailField()
class MessageSerializer(serializers.ModelSerializer):
message = serializers.CharField(write_only=True)
class Meta:
model = Message
fields = ['recipient', 'message']
def create(self, validated_data):
message = validated_data.pop('message')
message_obj = super().create(validated_data)
send_mail(
'Invitation',
message,
'exampleemail@gmail.com',
[message_obj.recipient]
)
return message_obj
class SendInviteView(mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = MessageSerializer
def perform_create(self, serializer):
serializer.save(sender=self.request.user)
router = routers.DefaultRouter()
router.register('send_invite', SendInviteView, base_name='send_invite')
urlpatterns = router.urls
让我们分解。
如果要存储发件人,则需要在模型中将ForeignKey
至User
。
对于序列化程序,您需要手动添加message
字段,因为该字段在您的模型中不存在,但用户应提交。我们将其设置为只写,因为该序列化程序还将用于将创建的Message
序列化回用户以供响应,并且Message
没有message
字段。该序列化程序还将根据recipient
模型为Message
自动生成字段。
然后,我们在此序列化程序中覆盖create
,因此无论何时使用它创建新的Message
,它都会发送一封电子邮件。它调用super().create(..)
来将Message
实际保存到数据库中,然后发送电子邮件。我们使用.pop()
从message
中删除validated_data
,因为Message
不包含这样的字段。
对于视图,我们不需要ModelViewSet
提供的全部内容。它增加了创建,读取,更新和删除(CRUD
)Message
的能力,而实际上并不需要。您只需要简单的Create(创建)就可以将HTTP请求转换为POST
。 GenericViewSet
与CreateModelMixin
正是我们想要的东西(实际上ModelViewSet
仅具有更多mixin)。来自用户的数据将由序列化程序验证,然后将调用perform_create
方法。我们将sender=self.request.user
传递给serializer.save()
是因为我们需要将sender
保存到Message
中,并且sender
字段实际上不在数据中,它是当前的用户登录。
serializer.save()
将运行我们的MessageSerializer.create()
,所以我们很高兴。
请注意,这些内容仅适用于登录用户,因为我们不知何故需要填充数据库中的sender
字段,因此添加
class SendInviteView(mixins.CreateModelMixin, viewsets.GenericViewSet):
permission_classes = [IsAuthenticated]
....
因此,只有经过身份验证的用户才能发出请求。 希望这会为您澄清事情。此致)
答案 1 :(得分:0)
如果我的理解正确,您可以在urls
中提及如下函数/方法,
url(r'some/end/point/', views.SendInviteView.as_view({"post": "send_the_mail"})
因此,您的看法就像,
class SendInviteView(viewsets.ModelViewSet):
queryset = models.Message.objects.all()
serializer_class = serializers.MessageSerializer
def send_the_mail(self, request):
recipient = request.data['recipient'] # json array
send_mail(
'Invitation',
'Try our app!',
'exampleemail@gmail.com',
recipient,
fail_silently=False,
)
return Response("mail sent successfully")
由于recipient
需要一个数组,所以POST payload
就像是
{
"recipient": ["mail1@dom.com", "mail2@dom.com", "mail3@dom.com"]
}