python - 具有自定义用户模型的 Django rest_framework - 重复键值违反唯一约束
问题描述
我开始学习 django (rest_framework) 并构建一个应用程序。我在代码下方创建了一个自定义用户模型和管理器:
class CustomUserManager(BaseUserManager):
"""Define a model manager for User model with no username field."""
def _create_user(self, email, password=None, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **extra_fields):
"""Create and save a SuperUser with the given email and password."""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
username = models.CharField(_('username'), max_length=255, unique=False, blank=True)
mobile = models.CharField(_('mobile'),max_length=255, blank=True)
picture = models.ImageField(upload_to='images/thumbnail/%Y/%m/%d/', null=True, blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
@property
def picture_preview(self):
if self.picture:
return mark_safe('<img src="{}" width="300" height="300" />'.format(self.picture.url))
return ""
objects = CustomUserManager()
我还为管理员自定义了视图……一切正常。
现在,当我从管理员处注册新用户时,例如,我两次发送同一封电子邮件时,我收到此错误消息:具有此电子邮件地址的用户已存在。
但是,如果我使用邮递员注册一个新用户来调用 api,我会收到以下错误:
django.db.utils.IntegrityError: duplicate key value violates unique constraint "accounts_customuser_email_key"
DETAIL: Key (email)=(mario@mario.it) already exists.
在序列化器类之下
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
email = serializers.EmailField()
class Meta:
model = CustomUser
fields = ['email', 'password']
def validate(self, attrs):
# Check if user exist
email = attrs.get('email', '')
# if CustomUser.objects.filter(email=email).exists():
# raise serializers.ValidationError(
# 'User with this Email address already exists.')
# Validate password
errors = dict()
user = CustomUser(**attrs)
password = attrs.get('password', '')
try:
# validate the password and catch the exception
validators.validate_password(password=password, user=user)
# the exception raised here is different than serializers.ValidationError
except ValidationError as e:
errors['password'] = list(e.messages)
if errors:
raise serializers.ValidationError(errors)
return attrs
def create(self, validated_data):
return CustomUser.objects.create_user(**validated_data)
在验证器中,我评论了检查用户是否已经注册的代码,因为我希望 django 应该知道电子邮件是否已经在没有额外代码的情况下注册,因为在管理员中它可以正常工作。
和视图类:
class RegisterView(generics.GenericAPIView):
serializers_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializers_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
return Response(user_data, status.HTTP_201_CREATED)
我的问题是我做错了什么?我错过了什么吗?
谢谢大家...任何帮助将不胜感激。
解决方案
如果您使用相同的电子邮件创建用户,django 会检查并引发 IntegrityError。您必须捕获此异常并返回响应。此外,最好在视图部分而不是在序列化程序验证方法中执行此操作,因为序列化程序的验证方法的工作是仅检查给定的输入是否正确。所以你的视图应该是这样的。
class RegisterView(generics.GenericAPIView):
serializers_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializers_class(data=user)
serializer.is_valid(raise_exception=True)
try:
user = User.objects.create_user(
email=serializer.data.get("email"),
password=request.data.get("password"),
)
except IntegrityError:
return Response("Email already exists.",
status=status.HTTP_406_NOT_ACCEPTABLE,
)
response = jwt_response_payload_handler(user.get_jwt_token(), user, request) # some payload handler, for user information
return Response(response, status.HTTP_201_CREATED)
推荐阅读
- javascript - PHP $_GET 值未从 jQuery AJAX 调用中提取 - PHP 包含问题?
- mysql - withCount() - 获得 2 个计数的差值
- php - 如何使用 REST API 为 WooCommerce 产品指定产品图像排序顺序?
- python - Pyinstaller 生成空 dist 文件夹
- javascript - 在 React Native 上调节按钮
- python - 将多个 Vega/vincent 图表添加到 Folium 弹出窗口
- django - 如何使用视图从 PostGIS 中提取几何图形,然后使用 Django 将其添加到模板中的传单地图中
- node.js - 猫鼬聚合不返回最新文档
- python - 使用 pydrive 从 google 共享驱动器下载文件,文件存在,但 API 返回 404 File not found 错误
- javascript - 测试从AngularJS中另一个方法的return语句调用一个方法的次数