Django rest fraemwork. Сохраните данные пользователя extendet в БД
Я пытаюсь реализовать конечную точку регистрации для пользователя с дополнительными атрибутами, такими как номер_телефона и полное_имя.
Я реализовал logick для сохранения данных пользователя, которые приходят из запроса, но я не могу понять, как я могу сохранить данные профиля, такие как телефон_номер и полное_имя.
У меня есть модель пользователя:
class User(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_verified = models.BooleanField(_('is verified by admin'), default=False)
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
def __str__(self):
return self.email
def save(self, *args, **kwargs):
if not self.username:
self.set_username()
super().save(*args, **kwargs)
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this user."""
send_mail(subject, message, from_email, [self.email], **kwargs)
def set_username(self):
pass
И модель профиля:
class Profile(TimeStampedModel):
STATUS = Choices(
("inactive", _("inactive")),
("active", _("active")),
("banned", _("banned"))
)
user = models.OneToOneField(
User,
verbose_name=_('related user'),
on_delete=models.CASCADE,
related_name='profile',
related_query_name='profile'
)
description = models.TextField(
_("description of user's profile"),
blank=True,
default=''
)
status = StatusField(
_("status of the user")
)
birth_date = models.DateField(
_("Date of birth"),
validators=[
MinValueValidator(
datetime.date(1910, 1, 1)
),
MaxValueValidator(
datetime.date.today
)
],
null=True,
blank=True
)
avatar = models.OneToOneField(
"files.Avatar",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="profile"
)
full_name = models.CharField(
max_length=30,
default='',
blank=False
)
phone_number_regex_validator = RegexValidator(regex=COMPILED_REGEXP)
phone_number = models.CharField(
max_length=16,
default='',
blank=False,
validators=[phone_number_regex_validator]
)
objects = ProfileQuerySet.as_manager()
def __str__(self):
return f"profile of user {self.user_id}"
class Meta:
verbose_name = _('profile')
verbose_name_plural = _('profiles')
Вот мой сереализатор для пользователей:
class RegisterSerializer(serializers.Serializer): # pylint: disable=abstract-method
email = serializers.EmailField(
required=True, help_text=_('Email address')
)
password1 = serializers.CharField(
write_only=True, help_text=_('Password')
)
password2 = serializers.CharField(
write_only=True, help_text=_('Password Confirmation')
)
phone_number = serializers.CharField(
write_only=True, help_text=_('Phone number')
)
full_name = serializers.CharField(
write_only=True, help_text=_('Full name')
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.cleaned_data = {}
@staticmethod
def validate_email(email):
email = get_adapter().clean_email(email)
if email and email_address_exists(email):
raise serializers.ValidationError(_(
"A user is already registered with this e-mail address.")
)
return email
@staticmethod
def validate_password1(password):
return get_adapter().clean_password(password)
def validate(self, attrs):
if attrs['password1'] != attrs['password2']:
raise serializers.ValidationError(_(
"The two password fields didn't match.")
)
return attrs
def custom_signup(self, request, user):
pass
def get_cleaned_data(self):
return {
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
'phone_number': self.validated_data.get('phone_number', ''),
'full_name': self.validated_data.get('full_name', '')
}
def save(self, request): # pylint: disable=arguments-differ
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
self.custom_signup(request, user)
setup_user_email(request, user, [])
return user
И сигналы, где объект профиля создан и сохранен в db:
@receiver(post_save, sender=User)
def create_user_profile(sender, instance=None, created=False, **kwargs):
if created:
Profile.objects.create(user=instance)
Как я могу сохранить все необходимые атрибуты для профиля модели в базе данных?
Я бы просто настроил профиль клиента в методе save
, а не использовал здесь сигнал.
Если вы действительно хотите использовать сигнал, вам нужно написать свой собственный, который посылает весь validated_data
поверх
См: https://docs.djangoproject.com/en/3.2/topics/signals/#defining-and-sending-signals
В качестве примечания,
Метод
get_cleaned_data
выглядит немного странно, поскольку все поля в сериализаторах обязательны, можно просто использоватьself.validated_data
в методеsave
.ваш
validate_<field>
метод должен быть просто методом экземпляра, а не методом класса, согласно DRF doc, вы можете игнорировать ваш линтер здесь.
Смотрите https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation
Это нечто связанное, что я сделал, это не точный ответ, но тесно связанный. Я добавлял USER-GROUP, BRANCH к пользователю во время регистрации. Проверьте ключевое слово SUPER в Views.py.
Я расширил модель пользователя, чтобы получить всю информацию о нем в одном месте.
Это мой model.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
gender = models.CharField(max_length=10,blank = True)
first_name = models.CharField(max_length=30,blank = True)
last_name = models.CharField(max_length=30,blank = True)
nickname = models.CharField(max_length=30, blank = True)
dob = models.DateField(null = True,blank = True)
mobileNumber = models.CharField(max_length=15,blank = True)
maritalStatus = models.CharField(max_length=10,blank = True)
localAddLine1 = models.CharField(max_length=150, blank=True)
branch = models.ForeignKey(branch,on_delete=models.CASCADE, related_name =
'user_brn_data', blank = True, null=True)
user_group = models.ForeignKey(user_group,on_delete=models.CASCADE,
related_name = 'user_group_data', blank = True, null=True)
Это мой serializers.py
from django.contrib.auth import get_user_model
User = get_user_model()
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
# fields = ("__all__")
exclude = ['password']
А это мой View.js
from rest_auth.registration.views import RegisterView
from django.contrib.auth import get_user_model
User = get_user_model()
class CuustomRegisterView(RegisterView):
def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)
data = request.data
branch = data['branchId']
groups = data['userGroupId']
email = data['email']
isSuperUser = data['isSuperUser']
User.objects.filter(email=email).update(branch=branch,
is_superuser=isSuperUser, user_group=groups, branch =branch)
return response
Вы можете использовать ключевое слово SUPER в python для вызова главной функции и расширить ее роль для достижения того, что вы ищете.