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

В качестве примечания,

  1. Метод get_cleaned_data выглядит немного странно, поскольку все поля в сериализаторах обязательны, можно просто использовать self.validated_data в методе save.

  2. ваш 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 для вызова главной функции и расширить ее роль для достижения того, что вы ищете.

Вернуться на верх