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

Django Rest Framework对接Android发送邮件时重复创建用户问题

Hey there! Let's break down what's causing that duplicate user issue and fix it step by step.

The Root Cause

When you enable send_mail() in your view, it runs synchronously—meaning your server pauses to send the email before sending a response back to the Android app. If the email takes too long to send, the Android client might time out and retry the registration request. This leads to two identical requests hitting your server, creating duplicate users (and triggering the "user already exists" error). Postman doesn't have this problem because it waits longer for responses, so it doesn't retry.

Fix 1: Send Emails Asynchronously (Most Critical)

The biggest fix is to offload email sending to a background task so your view can respond immediately to the Android app, preventing retries. Here are two easy ways to do this:

Option A: Use Threading (Quick & Simple)

Wrap the send_mail call in a thread to let it run in the background:

# In your views.py
import threading
from django.core.mail import send_mail

def send_activation_email():
    send_mail('mail_subject', 'message','test.com <no-reply@test.com>', ['test@gmail.com'])

# Inside the create method
if not social_acc == "Yes":
    # Start the email in a separate thread
    threading.Thread(target=send_activation_email).start()
    return Response(
        {'code': 'reg_success', 'message': 'User created successfully. Please confirm your email'}, 
        status=HTTP_201_CREATED
    )

Option B: Use Celery (Scalable for Production)

For production apps, Celery is a better choice for background tasks. First set up Celery with your Django project, then create a task:

# tasks.py
from celery import shared_task
from django.core.mail import send_mail

@shared_task
def send_activation_email():
    send_mail('mail_subject', 'message','test.com <no-reply@test.com>', ['test@gmail.com'])

Then call the task asynchronously in your view:

# views.py
from .tasks import send_activation_email

# Inside the create method
if not social_acc == "Yes":
    send_activation_email.delay()  # Async call
    return Response(...)

Fix 2: Add Atomic Transactions to Prevent Duplicates

Even if the app retries, we can make sure the database doesn't create duplicate users. Your current check-then-create logic isn't atomic—two requests could pass the existence check at the same time before either creates a user. Wrap the logic in a transaction and handle database integrity errors:

from django.db import transaction, IntegrityError

def create(self, request, *args, **kwargs):
    data = request.data
    serializer = self.get_serializer(data=data)
    
    try:
        with transaction.atomic():
            if serializer.is_valid():
                self.perform_create(serializer)
                social_acc = data.get('social_acc')
                if not social_acc == "Yes":
                    send_activation_email.delay()  # Use async email here
                    return Response(
                        {'code': 'reg_success', 'message': 'User created successfully. Please confirm your email'}, 
                        status=HTTP_201_CREATED
                    )
                return Response(
                    {'code': 'reg_success', 'message': 'User created successfully.'}, 
                    status=HTTP_201_CREATED
                )
    except IntegrityError:
        # Check which field caused the duplicate
        if UserModel.objects.filter(username=data.get("username")).exists():
            return Response({'code': 'reg_fail', 'message': 'Username already exists.'})
        if UserModel.objects.filter(email=data.get("email")).exists():
            return Response({'code': 'reg_fail', 'message': 'Current email has already been used.'})
    
    return Response({'code': 'reg_fail', 'message': 'Please check your data.'})

This leverages your User model's unique=True constraints on username and email, and catches the database error if a duplicate is attempted.

Fix 3: Optimize Android Client Behavior

Work with your Android team to:

  • Set a reasonable timeout for registration requests (long enough to wait for a response without retrying prematurely)
  • Disable retries for registration requests, or add a unique request ID (like a UUID) to avoid processing duplicate requests on the server

Extra Check

Your post_save signal for creating ActivateUser looks fine (the try-except prevents it from breaking user creation if something goes wrong), but double-check that your serializer is handling all fields correctly—especially social_acc—to avoid unexpected validation delays.

内容的提问来源于stack exchange,提问作者Antef Technologies

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:54:49