如何用DRF ModelViewSet实现存库并发邮件的生产级联系表单?
用ModelViewSet实现生产级联系表单(存库+发邮件)
原问题分析
你之前用APIView实现的联系表单仅能发送邮件,但未将用户数据存入数据库;尝试用ModelViewSet改写时,因为没有遵循ModelViewSet的封装逻辑(自行覆盖post方法却未调用数据保存流程),且邮件发送参数有误,导致功能未生效。
正确实现步骤
ModelViewSet已封装了create、list等CRUD方法,POST请求会自动映射到create方法。我们只需重写create方法,先完成数据入库,再执行邮件发送逻辑即可。
1. 确保模型与序列化器配置正确
假设你的Contact模型和序列化器如下(如果已有可跳过):
# models.py from django.db import models class Contact(models.Model): name = models.CharField(max_length=100) email = models.EmailField() phone_no = models.CharField(max_length=20, blank=True, null=True) message = models.TextField() created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name
# serializers.py from rest_framework import serializers from .models import Contact class ContactSerializer(serializers.ModelSerializer): class Meta: model = Contact fields = ['name', 'email', 'phone_no', 'message']
2. 正确的ModelViewSet实现
# views.py from django.core.mail import send_mail import logging from rest_framework import viewsets, status from rest_framework.response import Response from rest_framework.permissions import AllowAny from .models import Contact from .serializers import ContactSerializer logger = logging.getLogger(__name__) class CustomerContactViewSet(viewsets.ModelViewSet): permission_classes = [AllowAny] queryset = Contact.objects.all() http_method_names = ['post'] # 仅开放POST请求 serializer_class = ContactSerializer def create(self, request, *args, **kwargs): # 调用父类create方法,自动完成数据验证与入库 response = super().create(request, *args, **kwargs) contact_instance = self.get_object() # 格式化邮件内容 subject = f"联系表单消息来自: {contact_instance.name}" message_body = ( f"姓名: {contact_instance.name}\n" f"邮箱: {contact_instance.email}\n" f"电话: {contact_instance.phone_no or '未提供'}\n" f"消息内容:\n{contact_instance.message}" ) # 发送邮件,添加异常捕获避免阻塞请求 try: send_mail( subject, message_body, contact_instance.email, ['bibekjoshi34@gmail.com'], fail_silently=False ) except Exception as e: logger.error(f"联系邮件发送失败: {str(e)}") return Response( {"success": "消息已保存,但邮件发送失败"}, status=status.HTTP_201_CREATED ) return Response( {"success": "消息已保存并发送"}, status=status.HTTP_201_CREATED )
3. URL配置(使用DRF路由)
ModelViewSet需要通过DRF的路由注册来生成正确的URL:
# urls.py from django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'contactapi', views.CustomerContactViewSet, basename='contact') urlpatterns = [ path('', include(router.urls)), ]
生产级优化建议
- 异步发邮件:用Celery或Django的异步任务框架处理邮件发送,避免阻塞API请求(示例用Celery):
# 新增异步任务 from celery import shared_task @shared_task def send_contact_email(contact_id): contact = Contact.objects.get(id=contact_id) subject = f"联系表单消息来自: {contact.name}" message_body = f"姓名: {contact.name}\n邮箱: {contact.email}\n电话: {contact.phone_no or '未提供'}\n消息内容:\n{contact.message}" send_mail(subject, message_body, contact.email, ['bibekjoshi34@gmail.com'], fail_silently=False) # 修改create方法调用异步任务 def create(self, request, *args, **kwargs): response = super().create(request, *args, **kwargs) send_contact_email.delay(response.data['id']) return Response({"success": "消息已保存,邮件将稍后发送"}, status=status.HTTP_201_CREATED) - HTML邮件:使用
EmailMultiAlternatives发送格式更美观的HTML邮件。 - 验证增强:在序列化器中添加自定义验证规则(如消息最小长度、邮箱格式校验)。
内容的提问来源于stack exchange,提问作者Bibek
相关产品推荐
相关产品推荐

