代码之家  ›  专栏  ›  技术社区  ›  aalberti333

将modelviewset中的自定义函数与django rest框架一起使用

  •  3
  • aalberti333  · 技术社区  · 6 年前

    django 2.0、python 3.6、django rest framework3.8

    我对django rest框架还很陌生,我正试图理解在视图集中使用函数的逻辑(如果这是包含函数的正确位置的话)。

    基本上,当用户在这个特定的视图集中向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 ,但我不明白在这种情况下如何发送电子邮件。

    任何帮助都非常感谢。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Alexandr Tatarinov    6 年前

    讨论之后,我会提出以下建议。

    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 返回用户进行响应,并且 消息 没有 消息 字段。此序列化程序还将为 recipient 自动从 消息 模型。

    然后我们重写 create 在这个序列化程序中,所以每当 消息 将使用它创建,它将发送电子邮件。它叫 super().create(..) 真正的拯救 消息 发送到数据库,然后发送电子邮件。我们用 .pop() 删除 消息 validated_data ,因为 消息 不包含此类字段。

    我们不需要所有的东西 ModelViewSet 提供。它增加了创建、读取、更新和删除的能力( CRUD )你的 消息 ,实际上并不需要。你只需要简单的创建 POST 在http请求方面。 GenericViewSet 具有 CreateModelMixin 正是我们想要的 模型视图集 只要有更多的混合物。来自用户的数据将由序列化程序验证,并且 perform_create 方法将被调用。我们路过 sender=self.request.user serializer.save() 因为我们需要拯救 sender 进入之内 消息 ,和 发件人 字段实际上不在数据中,它是当前登录的用户。 序列化程序.save() 将运行我们的 MessageSerializer.create() 所以我们很高兴。

    注意,这些东西只对登录的用户有效,因为我们需要以某种方式填充 发件人 数据库中的字段,因此添加

    class SendInviteView(mixins.CreateModelMixin, viewsets.GenericViewSet):
        permission_classes = [IsAuthenticated]
        ....
    

    所以只有经过身份验证的用户才能发出请求。 希望这能为你澄清一些事情。致以最良好的问候)

        2
  •  0
  •   JPG    6 年前

    如果我理解正确,您可以在 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"]
    }