You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 14:05:22