Aula 82 - Loja Online - Formulário Personalizado do Modelo User
Admin
Classe UserAdmin
No código do
django_ecommerce/e_commerce/accounts/admin.py, a classe
UserAdmin é uma extensão da classe
BaseUserAdmin fornecida pelo Django.
Ela personaliza a exibição e as opções de administração do modelo de usuário personalizado.
Define os formulários
UserAdminCreationForm e
UserAdminChangeForm para adicionar e alterar instâncias de usuário, respectivamente.
Define também os campos a serem exibidos no modelo usuário, como:
email e se o usuário é um
administrador.
Configura os
campos de
pesquisa e
filtros para
facilitar a
busca e filtragem dos usuários.
Define os
grupos de campos para edição de usuário e criação de usuário.
Registra o modelo de usuário personalizado, aplicando a classe
UserAdmin a ele.
Classe GuestEmailAdmin
A classe
GuestEmailAdmin é uma extensão da classe
ModelAdmin fornecida pelo Django.
Ela personaliza a exibição e as opções de administração do modelo
GuestEmail.
Configura o
campo de
pesquisa por email para
facilitar a
busca de registros de
GuestEmail.
Registra o modelo
GuestEmail e aplica a classe
GuestEmailAdmin a ele.
django_ecommerce/e_commerce/accounts/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminCreationForm, UserAdminChangeForm
from .models import GuestEmail
User = get_user_model()
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ['email', 'admin']
list_filter = ['admin', 'staff', 'active']
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ()}),
('Permissions', {'fields': ('admin', 'staff', 'active',)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password', 'password_2')}
),
)
search_fields = ['email']
ordering = ['email']
filter_horizontal = ()
admin.site.register(User, UserAdmin)
# Remove Group Model from admin. We're not using it.
admin.site.unregister(Group)
class GuestEmailAdmin(admin.ModelAdmin):
search_fields = ['email']
class Meta:
model = GuestEmail
admin.site.register(GuestEmail, GuestEmailAdmin)
Explicando algumas partes do código em mais detalhes.
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ()}),
('Permissions', {'fields': ('admin', 'staff', 'active',)}),
)
Nesse trecho, a variável
fieldsets é uma tupla que define os grupos de campos a serem exibidos na página de administração do modelo de usuário personalizado.
- O primeiro grupo de campos tem o rótulo "None" (nenhum) e contém os campos 'email' e 'password'.
- O segundo grupo de campos tem o rótulo "Personal info" (informações pessoais) e não contém nenhum campo. Esse grupo está vazio.
- O terceiro grupo de campos tem o rótulo "Permissions" (permissões) e contém os campos 'admin', 'staff' e 'active'.
Cada grupo de campos é uma tupla que consiste em um rótulo (opcionalmente, None) e um dicionário com a chave 'fields' que especifica os campos a serem exibidos nesse grupo.
Essa estrutura de grupos de campos permite organizar e agrupar os campos de informações pessoais, permissões e outros em seções distintas na página de administração, tornando-a mais clara e organizada.
Agora essa parte:
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
search_fields = ['email']
ordering = ['email']
filter_horizontal = ()
add_fieldsets
É uma tupla que define a forma como os campos são exibidos ao adicionar um novo usuário através da página de administração.
Nesse caso, há apenas um grupo de campos, sem rótulo (None), e contém os campos 'email', 'password1' e 'password2'.
Além disso, a classe CSS '
wide' é aplicada ao grupo de campos para que ele seja exibido em uma largura maior.
search_fields
É uma lista que especifica os campos do modelo de usuário pelos quais é possível realizar uma busca na página de administração.
Nesse caso, apenas o campo '
email' é definido como um campo de busca.
ordering
É uma lista que define a ordem em que os registros do modelo de usuário são exibidos na página de administração.
Nesse caso, a ordem é definida pelo campo '
email', ou seja, os registros são ordenados alfabeticamente pelo endereço de email.
filter_horizontal
É uma tupla vazia que indica que não há campos para exibir em formato horizontal no painel de administração.
Essa configuração é usada para campos de relacionamento muitos-para-muitos, como grupos de permissões, mas neste caso não há nenhum campo desse tipo.
Ainda relativo ao código acima, a parte:
class GuestEmailAdmin(admin.ModelAdmin):
search_fields = ['email']
class Meta:
model = GuestEmail
admin.site.register(GuestEmail, GuestEmailAdmin)
search_fields é uma lista que especifica os campos do modelo
GuestEmail pelos quais é possível realizar uma busca na página de administração.
Neste caso, apenas o campo '
email' é definido como um campo de busca.
Isso significa que na página de administração, haverá uma caixa de pesquisa onde você pode digitar um endereço de e-mail e pesquisar por registros que correspondam a esse valor.
Meta é uma classe interna do
GuestEmailAdmin que define metadados adicionais para o modelo
GuestEmail.
Nesse caso, a propriedade model é definida como
GuestEmail, indicando qual modelo está associado a essa classe de administração.
Essas configurações permitem que você adicione um campo de busca específico e defina o modelo ao qual essa classe de administração está associada.
Dessa forma, você pode personalizar a forma como o modelo
GuestEmail é exibido e gerenciado na página de administração do Django.
Seguindo para o
e_commerce/accounts/forms.py.
Forms
Classe UserAdminCreationForm
No código do
django_ecommerce/e_commerce/accounts/forms.py, a classe
UserAdminCreationForm é um formulário para a criação de novos usuários.
Ela
herda de
forms.ModelForm e é associada ao modelo de usuário personalizado.
Define os campos necessários para criar um novo usuário, incluindo uma senha repetida para confirmação.
Implementa uma verificação para garantir que as senhas sejam iguais antes de salvar o usuário.
E sobrescreve o método save para salvar a senha fornecida no formato de hash.
Classe UserAdminChangeForm
É um formulário para a atualização de usuários existentes.
Herda de
forms.ModelForm e é associada ao modelo de usuário personalizado.
Substitui o campo de senha pelo campo somente leitura que exibe o hash da senha atual.
E garante que a senha inicial seja retornada independentemente do que o usuário forneça.
django_ecommerce/e_commerce/accounts/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import ReadOnlyPasswordHashField
User = get_user_model()
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password = forms.CharField(widget=forms.PasswordInput)
password_2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ['email']
def clean(self):
'''
Verify both passwords match.
'''
cleaned_data = super().clean()
password = cleaned_data.get("password")
password_2 = cleaned_data.get("password_2")
if password is not None and password != password_2:
self.add_error("password_2", "Your passwords must match")
return cleaned_data
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ['email', 'password', 'active', 'admin']
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class GuestForm(forms.Form):
email = forms.EmailField()
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
class RegisterForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
def clean_username(self):
username = self.cleaned_data.get('username')
qs = User.objects.filter(username=username)
if qs.exists():
raise forms.ValidationError("Esse usuário já existe, escolha outro nome.")
return username
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("Esse email já existe, tente outro!")
return email
def clean(self):
data = self.cleaned_data
password = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError("As senhas informadas devem ser iguais!")
return data
Explicando algumas partes do código em mais detalhes.
UserAdminCreationForm
A
password1 e
password2 são campos de senha utilizados para inserir a senha do usuário e confirmar a senha, respectivamente.
Eles são definidos como campos
forms.CharField com rótulos específicos e widgets de
forms.PasswordInput para ocultar os caracteres digitados.
Meta é a classe interna usada para
definir a meta-informação do
formulário.
No caso desse formulário, especifica que o modelo
User é o modelo base para o formulário e o campo email como o único campo a ser exibido no formulário.
O
clean() é um método de validação personalizado que verifica se as duas senhas fornecidas (
password1 e
password2) correspondem.
Se as senhas não corresponderem, vai lançar um erro com a mensagem: "
Your passwords must match".
E o
save() é o método usado para salvar o usuário no banco de dados.
Ele chama o método
save() da classe base
forms.ModelForm para criar uma instância do modelo
User, define a senha fornecida no formato hash e salva o usuário no banco de dados.
No contexto da classe
UserAdminCreationForm, o motivo de usar
commit=False é permitir a manipulação da senha antes de salvar o usuário no banco de dados.
O código seguinte à chamada do método
save() é responsável por definir a senha fornecida pelo usuário no formato
hash e, em seguida, salvar o usuário no banco de dados somente se o parâmetro
commit for
True.
Dessa forma, você tem a oportunidade de processar a senha antes de salvar o usuário, garantindo que ela esteja armazenada de forma segura.
O parâmetro
commit=True indica que o usuário deve ser salvo imediatamente, por isso tá assim:
user = super(UserAdminCreationForm, self).save(commit=False)
O método
clean_password() é usado na classe
UserAdminChangeForm para retornar o valor inicial do campo de senha.
O campo password da classe
UserAdminChangeForm é definido como
ReadOnlyPasswordHashField(), que exibe uma representação de hash da senha atual do usuário em vez do campo de senha original.
Portanto, o campo não é editável e não precisa ser validado.
Ao substituir o método
clean_password(), o objetivo é retornar o valor inicial do campo password, ou seja, a representação de hash da senha atual para garantir que o campo não seja alterado acidentalmente quando o formulário for atualizado.
Esses métodos
clean() e
clean_password() são exemplos de como o Django permite personalizar a validação dos campos de um formulário de acordo com as necessidades específicas do aplicativo.
UserAdminChangeForm
O
password é um campo somente leitura (
ReadOnly) que exibe o valor hash da senha do usuário atual.
Ele usa a classe
ReadOnlyPasswordHashField, que é um widget do Django para exibir senhas em formato hash sem permitir que sejam editadas.
A classe Meta é usada para definir a meta-informação do formulário.
Nesse caso, os campos
email,
password,
active e
admin são especificados para serem exibidos no formulário.
O método
clean_password() não é realmente utilizado neste contexto.
Ele retorna o valor inicial do campo de senha (
password) sem fazer nenhuma validação adicional.
Essas duas classes fornecem os formulários necessários para a criação e atualização de usuários na aplicação Django.
Elas definem os campos necessários e validações personalizadas, além de lidarem com o salvamento dos dados do usuário no banco de dados.
Na próxima aula vamos adicionar campos obrigatórios ao nosso
User personalizado.
É isso, até a próxima. ;)
Código final da aula:
Canais do Youtube
Dêem um joinha 👍 na página do Código Fluente no
Facebook.
Sigam o Código Fluente no Instagram e no TikTok.
Código Fluente no Pinterest.
Meus links de afiliados:
Nos vemos na próxima então, \o/ 😉 Bons Estudos!