如何在Django REST Framework中基于allauth的EmailAddress模型创建用户邮箱ChoiceField
问题原因
你的代码存在两个核心问题:
- 自定义字段
CustomChoiceField的__init__方法执行时,序列化器的context还未注入到字段实例中,此时无法获取当前登录用户 - 序列化器中声明
email字段时,误用了默认的serializers.ChoiceField,没有调用你自定义的CustomChoiceField类
解决方案
方案一(更推荐,无需自定义字段):在序列化器__init__方法中动态赋值choices
直接修改users/serializers.py代码如下:
from rest_framework import serializers from users.models import * class AuthUserSerializer(serializers.ModelSerializer): # 先声明ChoiceField,初始choices设为空,后续动态赋值 email = serializers.ChoiceField(choices=[]) class Meta: model = User fields = ('id', 'username', 'first_name', 'last_name', 'email', 'avatar', 'bio', 'country', 'is_staff', 'is_active', 'is_superuser', 'last_login', 'date_joined') extra_kwargs = { 'is_staff': { 'read_only': True }, 'is_superuser': { 'read_only': True }, 'last_login': { 'read_only': True }, 'date_joined': { 'read_only': True } } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 此时context已完成注入,可以正常获取请求对象 request = self.context.get('request') if request and request.user.is_authenticated: # 过滤当前登录用户的所有邮箱作为选项 self.fields['email'].choices = EmailAddress.objects.filter(user=request.user).values_list('email', 'email')
这个方案逻辑更直观,DRF可浏览API可以直接识别到动态赋值的choices,自动将邮箱字段渲染为下拉选择框。
方案二:修复自定义字段逻辑
如果你需要保留自定义字段的实现,修改代码如下:
class CustomChoiceField(serializers.ChoiceField): # 重写get_choices方法,此时context已注入完成 def get_choices(self, cutoff=None): request = self.context.get('request') if request and request.user.is_authenticated: self.choices = EmailAddress.objects.filter(user=request.user).values_list('email', 'email') return super().get_choices(cutoff) class AuthUserSerializer(serializers.ModelSerializer): # 注意此处要调用你自定义的CustomChoiceField,不是默认的ChoiceField email = CustomChoiceField(choices=[]) class Meta: model = User fields = ('id', 'username', 'first_name', 'last_name', 'email', 'avatar', 'bio', 'country', 'is_staff', 'is_active', 'is_superuser', 'last_login', 'date_joined') extra_kwargs = { 'is_staff': { 'read_only': True }, 'is_superuser': { 'read_only': True }, 'last_login': { 'read_only': True }, 'date_joined': { 'read_only': True } }
内容的提问来源于stack exchange,提问作者Ajay Lingayat
相关产品推荐
相关产品推荐

