Python-en-equipo / MarketPlace

Aplicación web Tipo Marketplace, registro de usuarios, post y compras de usuarios y vendedores desarrollada con Django y Tailwind
11 stars 1 forks source link

Autenticación por email #35

Open Arturomtz8 opened 2 years ago

Arturomtz8 commented 2 years ago

Okey, lograr que tus usuarios se puedan autenticar con email es posible de distintas maneras, aqui se propone hacerlo con un AbstractUser y un BaseUserManager. Primero creemos un AbstractUser que hereda todos los campos del User por default de Django, seteamos el username como None y el campo de email como unique, asimismo usamos USERNAME_FIELD para indicarle que nos autenticaremos con email

from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
from django.utils.translation import ugettext_lazy as _

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_('email address'), unique=True)

        # para que en vez de username use el campo de email para autenticarse
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

        # el modelo que administra a mi usuario, sígase leyendo
    objects = CustomUserManager()

Necesitamos una clase que herede de BaseUserManager para que cree a los nuevos usuarios de aquí en adelante, puesto que modificamos el User que nos da django, y seteamos el username como None, es necesario el BaseUserManager. En realidad mucho de este código proviene de https://github.com/django/django/blob/main/django/contrib/auth/models.py[](https://docs.djangoproject.com/es/4.0/topics/auth/customizing/#writing-a-manager-for-a-custom-user-model) pero mi referencia de youtube lo ponía amablemente en su github:

If your user model defines different fields, you’ll need to define a custom manager that extends [BaseUserManager](https://docs.djangoproject.com/es/4.0/topics/auth/customizing/#django.contrib.auth.models.BaseUserManager) providing two additional methods: create_user and create_superuser(https://docs.djangoproject.com/es/4.0/topics/auth/customizing/#writing-a-manager-for-a-custom-user-model)

class CustomUserManager(BaseUserManager):
    """Define a model manager for User model with no username field."""

    def _create_user(self, email, password=None, **extra_fields):
        """Create and save a User with the given email and password."""
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password=None, **extra_fields):
        """Create and save a SuperUser with the given email and password."""
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)

Ahora en nuestro [settings.py](http://settings.py/) añadamos a nuestro nuevo usuario

AUTH_USER_MODEL = 'tuApp.CustomUser'

Para que admin se vea en orden, puesto que nuestro usuario es customizado, podemos usar la siguiente configuración, y añadirla en [admin.py](http://admin.py/) de nuestra app

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model

class CustomUserAdmin(UserAdmin):
    """Define admin model for custom User model with no username field."""
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
                                       'groups', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2'),
        }),
    )
    list_display = ('email', 'first_name', 'last_name', 'is_staff')
    search_fields = ('email', 'first_name', 'last_name')
    ordering = ('email',)

admin.site.register(get_user_model(), CustomUserAdmin)

Listo, ¡haz makemigrations y migrate!

Crea tu forms con los campos que pienses que son necesarios:

class UserForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = ["first_name", "last_name", "email", "password1", "password2"]

Y también tus views

@unauthenticated_user
def register_view(request):
    form = UserForm
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            form.save()
            user = form.cleaned_data.get("email")
            messages.success(request, f"{user} was succesfully created")
            return redirect("users:login")

    return render(request, "users/register.html", {"user_registration": form})

No te olvides de configurar tu [urls.py](http://urls.py/)[](https://www.youtube.com/watch?v=SbU2wdPIcaY) de tu app

from django.urls import path
from . import views

# no borrar porque los templates usan la appname
app_name = "users"

urlpatterns = [
    path("register/", views.register_view, name="register"),
]

Referencias: https://www.youtube.com/watch?v=SbU2wdPIcaY[](https://github.com/akjasim/cb_dj_custom_user_model/) y https://github.com/akjasim/cb_dj_custom_user_model/