我对 Djoser 提供的 UserCreateSerializer 进行了修改。在 Perform_create 方法中,我尝试创建 UserProfile 和 AddressDetails 模型的实例。虽然服务器似乎运行正常,但数据似乎并未按预期持续存在。我正在寻求有关识别和纠正此过程中任何错误的指导。您建议如何解决这个问题?
accounts.serializers.py
from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model
from rest_framework import serializers
from django.db import transaction
from django.db.utils import IntegrityError
from django.contrib.auth.password_validation import validate_password
from .models import AddressDetails, UserProfile
User = get_user_model()
class UserCreateSerializer(UserCreateSerializer):
address_line_one = serializers.CharField(write_only=True)
address_line_two = serializers.CharField(write_only=True)
address_line_three = serializers.CharField(write_only=True)
province = serializers.CharField(write_only=True, required=True)
barangay = serializers.CharField(write_only=True, required=True)
city = serializers.CharField(write_only=True, required=True)
zip_code = serializers.CharField(write_only=True, required=True)
first_name = serializers.CharField(write_only=True, required=True)
middle_name = serializers.CharField(write_only=True, required=True)
last_name = serializers.CharField(write_only=True, required=True)
date_of_birth = serializers.DateField()
gender = serializers.CharField(write_only=True, required=True)
relationship_status = serializers.CharField(write_only=True, required=True)
phone_number = serializers.CharField(write_only=True, required=True)
class Meta(UserCreateSerializer.Meta):
model = User
fields = (
"id",
"email",
"user_role",
"password",
"address_line_one",
"address_line_two",
"address_line_three",
"province",
"barangay",
"city",
"zip_code",
"first_name",
"middle_name",
"last_name",
"date_of_birth",
"gender",
"relationship_status",
"phone_number"
)
@transaction.atomic
def perform_create(self, validated_data):
address_line_one = validated_data.pop("address_line_one")
address_line_two = validated_data.pop("address_line_two")
address_line_three = validated_data.pop("address_line_three")
province = validated_data.pop("province")
barangay = validated_data.pop("barangay")
city = validated_data.pop("city")
zip_code = validated_data.pop("zip_code")
first_name = validated_data.pop("first_name")
middle_name = validated_data.pop("middle_name")
last_name = validated_data.pop("last_name")
date_of_birth = validated_data.pop("date_of_birth")
gender = validated_data.pop("gender")
relationship_status = validated_data.pop("relationship_status")
phone_number = validated_data.pop("phone_number")
with transaction.atomic():
user = User.objects.create_user(**validated_data)
address_details = AddressDetails.objects.create(
address_line_one = address_line_one,
address_line_two = address_line_two,
address_line_three = address_line_three,
province = province,
barangay = barangay,
city = city,
zip_code = zip_code
)
UserProfile.objects.create(
user = user,
first_name = first_name,
middle_name = middle_name,
last_name = last_name,
date_of_birth = date_of_birth,
gender = gender,
relationship_status = relationship_status,
phone_number = phone_number,
address_details = address_details
)
return user
def validate_password(self, value):
user = self.user if self.user else self.Meta.model()
try:
validate_password(value, user)
except serializers.ValidationError as e:
serializer_error = serializers.as_serializer_error(e)
raise serializers.ValidationError(
{"password": serializer_error[api_setting.NON_FIELDS_ERRORS_KEY]}
)
return value
accounts.models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models #type: ignore
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField #type: ignore
# Create your models here.
class UserAccountManager(BaseUserManager):
def create_user(self, email, user_role, password=None, **extra_fields):
if not email:
raise ValueError("Users must have an email address.")
if not user_role:
raise ValueError("Users must have a user role.")
email = self.normalize_email(email)
user = self.model(email=email, user_role=user_role, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, user_role="admin", password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_admin", True)
extra_fields.setdefault("is_active", 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_admin") is not True:
raise ValueError(_("Superuser must have is_admin=True."))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must have is_superuser=True."))
return self.create_user(email, user_role, password, **extra_fields)
class UserAccount(AbstractBaseUser, PermissionsMixin):
USER_ROLES = (
("resident", "Resident"),
("healthworker", "Health Worker"),
("admin", "Admin")
)
email = models.EmailField(_("email address"), unique=True)
user_role = models.CharField(max_length=100, choices=USER_ROLES)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["user_role",]
objects = UserAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
def save(self, *args, **kwargs):
if self.user_role == "admin":
self.is_staff = True
self.is_admin = True
elif self.user_role == "healthworker":
self.is_staff = True
self.is_admin = False
else:
self.is_staff = False
self.is_admin = False
super().save(*args, **kwargs)
class AddressDetails(models.Model):
address_line_one = models.CharField(max_length=150, blank=True,)
address_line_two = models.CharField(max_length=150, blank=True,)
address_line_three = models.CharField(max_length=150, blank=True,)
province = models.CharField(max_length=150, blank=True,)
barangay = models.CharField(max_length=150, blank=True,)
city = models.CharField(max_length=150, blank=True,)
zip_code = models.CharField(max_length=5, blank=True,)
class UserProfile(models.Model):
GENDER_CHOICES = (
("F", "Female",),
("M", "Male",),
("U", "Unsure",),
)
user = models.OneToOneField(UserAccount, on_delete=models.CASCADE)
first_name = models.CharField(max_length=150,)
middle_name = models.CharField(max_length=150,)
last_name = models.CharField(max_length=150,)
date_of_birth = models.DateField()
gender = models.CharField(max_length=1, choices=GENDER_CHOICES,)
relationship_status = models.CharField(max_length=50,)
phone_number = PhoneNumberField()
address_details = models.OneToOneField(AddressDetails, on_delete=models.CASCADE)
我最近遇到了同样的问题,我假设您已经在 settings.py:
中添加了这一行DJOSER = {
...
"SERIALIZERS": {
"user_create": "accounts.serializers.UserCreateSerializer",
...
}
}
如果您的设置中没有此功能,请添加它,问题很可能仍然存在。 解决方案是将以下行添加到之前提到的“SERIALIZERS”字典中
"user_create_password_retype": "accounts.serializers.UserCreateSerializer"
这对我有用,我使用 djoser 版本 2.2.2
在检查 djoser 库中的 views.py 中的 UserViewSet 时发现了此方法起作用的原因:
def get_serializer_class(self):
if self.action == "create":
if settings.USER_CREATE_PASSWORD_RETYPE:
return settings.SERIALIZERS.user_create_password_retype
return settings.SERIALIZERS.user_create
USER_CREATE_PASSWORD_RETYPE 序列化程序会覆盖 settings.py 中指定的 user_create 序列化程序,这就是它返回到默认 djoser 的原因 UserCreateSerializer