Адреса электронной почты 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