Адреса электронной почты dj-rest-auth и django allauth

Когда я пытаюсь удалить уже зарегистрированного пользователя из базы данных, я получаю следующее: update or delete on table "users_user" violates foreign key constraint "account_emailaddress_user_id_2c513194_fk_users_user_id" on table "account_emailaddress" также, когда я регистрирую пользователя, только email, имя пользователя и пароль регистрируются в базе данных.

Сериализаторы:

class RegisterSerializer(serializers.Serializer):
    password = serializers.CharField(
        write_only=True,
        required=True,
        validators=[validate_password],
    )
    password2 = serializers.CharField(
        write_only=True,
        required=True,
    )

    class Meta:
        model = User
        fields = [
            "first_name",
            "last_name",
            "location",
            "username",
            "email",
            "password",
            "password2",
        ]

        extra_kwargs = {
            "first_name": {"required": True},
            "last_name": {"required": True},
            "location": {"required": False},
        }

        def validate_username(self, username):
            username = get_adapter().clean_username(username)
            return username
        
        def validate_email(self, email):
            email = get_adapter().clean_email(email)
            return email
        
        def validate_password1(self, password):
            password = get_adapter().clean_password(password)
            return password

        def validate(self, data):
            if data["password"] != data["password2"]:
                raise serializers.ValidationError(
                    {"password": "Password fields didn't match."}
                )
            return data
        
        def get_cleaned_data(self):
            return User(
                username=self.validated_data.get("username", ""),
                email=self.validated_data.get("email", ""),
                password=self.validated_data.get("password", ""),
                first_name=self.validated_data.get("first_name", ""),
                last_name=self.validated_data.get("last_name", ""),
                location=self.validated_data.get("location", ""),
            )
        
        def save(self, request):
            adapter = get_adapter()
            user = adapter.new_user(request)
            self.cleaned_data = self.get_cleaned_data()
            adapter.save_user(request, user, self, commit=False)
            if "password1" in self.cleaned_data:
                try:
                    adapter.clean_password(self.cleaned_data["password1"], user=user)
                except DjangoValidationError as e:
                    raise serializers.ValidationError(
                        {"password": list(e.messages)}
                    )
            # user.is_active = False
            user.save()
            return user

Вид:

class RegisterView(CreateAPIView):
    serializer_class = api_settings.REGISTER_SERIALIZER
    permission_classes = api_settings.REGISTER_PERMISSION_CLASSES
    token_model = TokenModel
    throttle_scoop = "dj_rest_auth"

    @method_decorator(sensitive_post_parameters('password1', 'password2'))
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    
    def get_response_data(self, user):
        if allauth_settings.EMAIL_VERIFICATION == allauth_settings.EmailVerificationMethod.MANDATORY:
            return {"detail": _("Verification e-mail sent.")}
        
        if api_settings.USE_JWT:
            data = {
                'user': user,
                'access': self.access_token,
                'refresh': self.refresh_token,
            }
            return api_settings.JWT_SERIALIZER(data, context=self.get_serializer_context()).data
        elif api_settings.SESSION_LOGIN:
            return {"detail": _("User created. Please login.")}
        else:
            return api_settings.TOKEN_SERIALIZER(data, context=self.get_serializer_context()).data
        
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        data = self.get_response_data(user)

        if data:
            response = Response(
                data,
                status=status.HTTP_201_CREATED,
                headers=headers,
            )
        else:
            response = Response(
                status=status.HTTP_204_NO_CONTENT,
                headers=headers,
            )
        return response
    
    def perform_create(self, serializer):
        user = serializer.save(self.request)
        if allauth_settings.EMAIL_VERIFICATION != allauth_settings.EmailVerificationMethod.MANDATORY:
            if api_settings.USE_JWT:
                self.access_token, self.refresh_token = jwt_encode(user)
            elif not api_settings.SESSION_LOGIN:
                api_settings.TOKEN_CREATOR(self.token_model, user, serializer)

        complete_signup(
            self.request._request,
            user,
            allauth_settings.EMAIL_VERIFICATION,
            None,
        )
        return user

Ошибка, с которой вы столкнулись при попытке удалить пользователя из базы данных, связана с нарушением ограничений внешнего ключа. В частности, таблица account_emailaddress имеет внешний ключ, который ссылается на таблицу users_user. Чтобы решить эту проблему, необходимо обработать зависимые записи в таблице account_emailaddress до или во время удаления пользователя. Обычно это включает удаление или обновление связанных записей, чтобы убедиться, что ограничение внешнего ключа не нарушено. Что касается проблемы с регистрацией, когда сохраняются только email, имя пользователя и пароль, похоже, что метод save в вашем сериализаторе неправильно сохраняет дополнительные поля (first_name, last_name, location). Вы должны убедиться, что эти поля устанавливаются в пользовательском объекте перед его сохранением. Корректировка метода save в сериализаторе для правильной установки этих полей должна решить проблему.

Пользователь создает проблему

Вместо того чтобы возвращать экземпляр User из метода get_cleaned_data, верните словарь с данными формы (аналогично оригинальной реализации, но расширенный вашими пользовательскими полями).

    def get_cleaned_data(self):
        return {
            'username': self.validated_data.get('username', ''),
            'password1': self.validated_data.get('password1', ''),
            'email': self.validated_data.get('email', ''),
            # ...custom data
        }

Далее, я думаю, вы хотите переопределить метод save_user адаптера учетной записи, чтобы включить в него ваши пользовательские поля.

    def save_user(self, request, user, form, commit=True):
        """
        Saves a new `User` instance using information provided in the
        signup form.
        """
        from .utils import user_email, user_field, user_username

        data = form.cleaned_data
        first_name = data.get("first_name")
        last_name = data.get("last_name")
        email = data.get("email")
        username = data.get("username")
        custom_field = data.get("custom_field") # <- Read value from cleaned_data
        user_email(user, email)
        user_username(user, username)
        if custom_field:
            user_field(user, "custom_field", custom_field) # <- Set value on the User instance
        if first_name:
            user_field(user, "first_name", first_name)
        if last_name:
            user_field(user, "last_name", last_name)
        if "password1" in data:
            user.set_password(data["password1"])
        else:
            user.set_unusable_password()
        self.populate_username(request, user)
        if commit:
            # Ability not to commit makes it easier to derive from
            # this adapter by adding
            user.save()
        return user

Создайте переопределяемый класс и передайте его в настройки:

ACCOUNT_ADAPTER (по умолчанию: "allauth.account.adapter.DefaultAccountAdapter").
Определяет класс используемого адаптера, позволяя изменять определенное поведение по умолчанию.

Документы: https://docs.allauth.org/en/latest/account/adapter.html

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