Django集成Djoser时用户资料接口未返回关联Worker信息
问题
我正在开发一个Django应用,用户分为普通应用用户和带有额外详情的Worker两类,用Djoser实现用户认证与注册。现在调用api/v1/auth/users/me/接口时,响应只返回用户基础信息,关联的Worker信息没返回,但已经确认该用户对应的Worker实例存在且关联正确。
已做的排查:
- 验证Worker实例确实存在
- 请求携带有效JWT令牌
- 数据库关联关系无误
相关代码:
models.py
from django.db import models from django.contrib.auth.models import AbstractUser, PermissionsMixin from django.utils.translation import gettext_lazy as _ from .managers import CustomUserManager class User(AbstractUser, PermissionsMixin): username = None first_name = models.CharField(_('First name'), max_length=100) last_name = models.CharField(_('last name'), max_length=100) email = models.EmailField(_('Email Address'), max_length=254, unique=True) is_staff = models.BooleanField(default=False) is_active = models.BooleanField(default=False) date_joined = models.DateTimeField(auto_now_add=True) USERNAME_FIELD = "email" REQUIRED_FIELDS = ["first_name", "last_name"] objects = CustomUserManager() class Meta: verbose_name = _("User") verbose_name_plural = _("Users") def __str__(self): return self.email @property def get_full_name(self): return f"{self.first_name} {self.last_name}" class Worker(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) categories = models.ManyToManyField('Category', related_name='workers') rating = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True) numReviews = models.IntegerField(null=True, blank=True, default=0) pricePerHour = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True) gender_choices = [ ('M', 'Male'), ('F', 'Female'), ] gender = models.CharField(max_length=1, choices=gender_choices) profile_photo = models.ImageField(upload_to='profile_photos/', null=True, blank=True) num_tel = models.CharField(max_length=20) small_description = models.TextField(null=True, blank=True) description = models.TextField(null=True, blank=True) _id = models.AutoField(primary_key=True, editable=False) def __str__(self): return f"{self.user.email} - {self.num_tel}"
serializers.py(注:原代码标注为views.py,实际是序列化器文件)
from django.contrib.auth import get_user_model from rest_framework.serializers import ModelSerializer from .models import Category, Worker from djoser.serializers import UserCreateSerializer from djoser.serializers import UserSerializer as DjoserUserSerializer from rest_framework import serializers User = get_user_model() class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'email', 'first_name', 'last_name'] class WorkerSerializer(serializers.ModelSerializer): user = UserSerializer() # Serialize user details class Meta: model = Worker fields = '__all__' class CustomUserSerializer(DjoserUserSerializer): worker = WorkerSerializer(read_only=True) class Meta(DjoserUserSerializer.Meta): model = User fields = ['id', 'email', 'first_name', 'last_name', 'worker'] class CreateUserSerializer(UserCreateSerializer): class Meta(UserCreateSerializer.Meta): model = User fields = ['id', 'email', 'first_name', 'last_name', 'password'] class CategorySerializer(ModelSerializer): class Meta: model = Category fields = '__all__' class ProvidersSerializer(ModelSerializer): user = UserSerializer() # Include detailed user information class Meta: model = Worker fields = '__all__'
Djoser配置
DJOSER = { 'LOGIN_FIELD': 'email', "USER_CREATE_PASSWORD_RETYPE": True, "USERNAME_CHANGED_EMAIL_CONFIRMATION": True, "PASSWORD_CHANGED_EMAIL_CONFIRMATION": True, "SEND_CONFIRMATION_EMAIL": True, "PASSWORD_RESET_CONFIRM_URL": "password/reset/confirm/{uid}/{token}", "SET_PASSWORD_RETYPE": True, "PASSWORD_RESET_CONFIRM_RETYPE": True, 'USERNAME_RESET_CONFIRM_URL': 'username/reset/confirm/{uid}/{token}', 'ACTIVATION_URL': 'activate/{uid}/{token}', 'SEND_ACTIVATION_EMAIL': True, 'SERIALIZERS': { 'user_create': 'base.serializers.CreateUserSerializer', 'user': 'base.serializers.CustomUserSerializer', 'user_delete': 'djoser.serializers.UserDeleteSerializer', }, }
疑问
导致Worker信息未出现在个人资料响应中的原因可能是什么?如何结合Djoser解决该问题?
原因分析与解决方案
核心原因
你遇到的问题主要有两个关键点:
- 循环序列化导致字段被忽略:
CustomUserSerializer嵌套了WorkerSerializer,而WorkerSerializer又嵌套了UserSerializer,形成循环引用。Django REST Framework为防止无限递归,会自动跳过这类嵌套字段的序列化,导致Worker信息无法显示。 - 未预取关联数据(潜在性能问题):即使没有循环引用,默认查询逻辑不会预取Worker数据,会触发额外数据库查询,虽不影响显示但会降低接口性能。
解决步骤
1. 修复循环序列化问题
直接修改WorkerSerializer,移除嵌套的UserSerializer——在users/me/接口中,我们已经从User视角返回数据,无需反向嵌套User信息:
class WorkerSerializer(serializers.ModelSerializer): # 移除这一行:user = UserSerializer() class Meta: model = Worker fields = '__all__' # 也可明确排除user字段彻底避免循环: # exclude = ['user']
如果业务需要保留用户关联信息,可改用主键或仅返回必要字段:
class WorkerSerializer(serializers.ModelSerializer): user = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Worker fields = '__all__'
2. 让Djoser预取Worker数据
重载Djoser的UserViewSet,添加预取逻辑避免N+1查询,同时确保序列化器能获取到关联数据:
在views.py中添加:
from djoser.views import UserViewSet class CustomUserViewSet(UserViewSet): def get_queryset(self): # 调用父类查询集并添加预取worker的逻辑 return super().get_queryset().select_related('worker')
然后在urls.py中替换默认的users/me/路由:
from django.urls import path, include from .views import CustomUserViewSet urlpatterns = [ # 替换默认me接口路由 path('auth/users/me/', CustomUserViewSet.as_view({'get': 'me', 'put': 'me', 'patch': 'me'}), name='user-me'), # 保留其他Djoser路由 path('auth/', include('djoser.urls')), path('auth/', include('djoser.urls.jwt')), ]
3. 确认序列化器字段配置
你的CustomUserSerializer已经正确包含worker字段,这一步无需修改:
class CustomUserSerializer(DjoserUserSerializer): worker = WorkerSerializer(read_only=True) class Meta(DjoserUserSerializer.Meta): model = User fields = ['id', 'email', 'first_name', 'last_name', 'worker']
4. 测试验证
重启服务后,再次调用api/v1/auth/users/me/接口,即可看到返回的Worker信息。
额外优化建议
- 如果需要返回Worker关联的分类信息,可在
WorkerSerializer中添加categories = CategorySerializer(many=True, read_only=True),注意避免与Category模型形成新的循环引用。 - 给
CustomUserSerializer的worker字段加上required=False,适配普通用户没有Worker实例的场景。
内容的提问来源于stack exchange,提问作者Medyahya
相关产品推荐
相关产品推荐

