I am making my first app, which is a todolist app. I am trying to get users to register with email and login with it.
This is the error that the debug shows me:
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" =...
My files have the following configuration
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
"""
Django settings for todolist_project project.
Generated by 'django-admin startproject' using Django 5.0.2.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
from decouple import config
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-0blmoc@*qb)vl*b++oj$akhq!3@s^dhbq3u89nt3ap(%0%thd9'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
AUTHENTICATION_BACKENDS = [
'core.backends.EmailBackend', # Personalización para permitir inicio de sesión con email
]
# Personalización de la autenticación para permitir inicio de sesión con email
AUTH_USER_MODEL = 'core.User'
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core.apps.CoreConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'todolist_project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'todolist_project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': config('DB_PORT'),
}
}
# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
AUTHENTICATION_BACKENDS = [
'core.backends.EmailBackend', # Personalización para permitir inicio de sesión con email
]
# Personalización de la autenticación para permitir inicio de sesión con email
AUTH_USER_MODEL = 'core.User'
# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
LOGIN_URL = 'login'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
I want to be able to login and register correctly, without using the username, using email and password.
In your case, since you've overridden the default behavior to use the email as the username, you should include 'email' in the REQUIRED_FIELDS list instead of 'username'.