Авторизация электронной почты в Django

Я делаю свое первое приложение, которое является приложением-тодолистом. Я пытаюсь заставить пользователей регистрироваться с помощью электронной почты и входить в систему с ее помощью.

Вот ошибка, которую показывает отладка:

ProgrammingError at /register/

no existe la relación «core_user»
LINE 1: SELECT 1 AS "a" FROM "core_user" WHERE "core_user"."email" =...
                             ^

Request Method:     POST
Request URL:    http://127.0.0.1:8000/register/
Django Version:     5.0.2
Exception Type:     ProgrammingError
Exception Value:    

no existe la relación «core_user»
LINE 1: SELECT 1 AS "a" FROM "core_user" WHERE "core_user"."email" =...

Мои файлы имеют следующую конфигурацию

models.py

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    email = models.EmailField(unique=True)
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

class Task(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    description = models.TextField()
    complete = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['complete']

views.py

from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, FormView

from django.urls import reverse_lazy

from django.contrib.auth.views import LoginView
from django.contrib.auth.mixins import LoginRequiredMixin

from django.contrib.auth import login

from .models import Task
from .forms import LoginForm, RegisterForm

class CustomLoginView(LoginView):
    template_name = 'core/login.html'
    form_class = LoginForm
    redirect_authenticated_user = True

    def get_success_url(self):
        return reverse_lazy('task_list')

class RegisterPage(FormView):
    template_name = 'core/register.html'
    form_class = RegisterForm
    redirect_authenticated_user = True
    success_url = reverse_lazy('task_list')

    def form_valid(self, form):
        user = form.save()
        if user is not None:
            login(self.request, user)
        return super(RegisterPage, self).form_valid(form)

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated:
            return redirect('task_list')
        return super(RegisterPage, self).get(*args, **kwargs)

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    template_name = 'core/index.html'
    context_object_name = 'task_list'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['task_list'] = context['task_list'].filter(user=self.request.user)
        context['count'] = context['task_list'].filter(complete=False).count()

        search_input = self.request.GET.get('search-area') or ''
        if search_input:
            context['task_list'] = context['task_list'].filter(title__startswith=search_input)

        context['search_input'] = search_input

        return context

class TaskDetail(LoginRequiredMixin, DetailView):
    model = Task
    template_name = 'core/task_detail.html'
    context_object_name = 'task'

class TaskCreate(LoginRequiredMixin, CreateView):
    model = Task
    template_name = 'core/task_form.html'
    fields = ['title', 'description', 'complete']
    success_url = reverse_lazy('task_list')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(TaskCreate, self).form_valid(form)

class TaskUpdate(LoginRequiredMixin, UpdateView):
    model = Task
    fields = ['title', 'description', 'complete']
    success_url = reverse_lazy('task_list')

class TaskDelete(LoginRequiredMixin, DeleteView):
    model = Task
    context_object_name = 'task'
    success_url = reverse_lazy('task_list')

forms.py

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model
from django import forms


class RegisterForm(UserCreationForm):
    class Meta:
        model = get_user_model()
        fields = ('email', 'password1', 'password2')


class LoginForm(AuthenticationForm):
    username = forms.CharField(label='Email')

    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        # Verificar si el nombre de usuario es un correo electrónico
        if '@' in username:
            kwargs = {'email': username}

        # Asignar los datos limpios validados al formulario
        self.cleaned_data['username'] = username
        self.cleaned_data['password'] = password
        return super().clean()

backends.py

from django.contrib.auth.hashers import check_password
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q

UserModel = get_user_model()

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except UserModel.DoesNotExist:
            return None
        except UserModel.MultipleObjectsReturned:
            # Podrías manejar este caso de manera más específica si es necesario
            user = UserModel.objects.filter(Q(username__iexact=username) | Q(email__iexact=username)).order_by('id').first()

        if user and check_password(password, user.password):
            return user
        else:
            return None

settings.py

Я хочу иметь возможность корректно входить и регистрироваться, не используя имя пользователя, используя электронную почту и пароль.

В вашем случае, поскольку вы переопределили поведение по умолчанию, чтобы использовать электронную почту в качестве имени пользователя, вы должны включить 'email' в список REQUIRED_FIELDS вместо 'username'.

class User(AbstractUser):
    email = models.EmailField(unique=True)
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['email']
Вернуться на верх