Aula 54 – Loja Online – Django – criando o accounts
Aula 54 – Loja Online – Django – Criando o accounts
Voltar para página principal do blog
Todas as aulas desse curso
Aula 53 Aula 55
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Esse é o link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Melhore seu NETWORKING
https://digitalinnovation.one/
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no https://github.com/toticavalcanti.
Código final da aula:
https://github.com/toticavalcanti
Quer aprender python3 de graça e com certificado? Acesse então:
https://workover.com.br/python-codigo-fluente
Toti:
https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA
Backing track / Play-along:
https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA
Código Fluente
https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w
Putz!
https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw
Aula 54 – Loja Online – Django – Criando o accounts
Esse app, ou seja, esse componente do nosso projeto do ecommerce, será responsável pela parte de autenticação e coisas relacionadas.
Para criar o accounts, vamos executar o comando:
python manage.py startapp accounts
Pronto, app accounts criado.
Vamos começar transferindo as funções de login(), register() e de logout() que estão no /e_commerce/e_commerce/views.py para o views do app que a gente acabou de criar, do accounts, ou seja, /e_commerce/accounts/views.py.
No código abaixo, o que tá em vermelho é o que vai ser transferido para o /e_commerce/accounts/views.py.
/e_commerce/e_commerce/views.py
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import ContactForm, LoginForm, RegisterForm
def home_page(request):
context = {
"title": "Home Page",
"content": "Bem vindo a Home Page",
}
if request.user.is_authenticated:
context["premium_content"] = "Você é um usuário Premium"
return render(request, "home_page.html", context)
def about_page(request):
context = {
"title": "Página Sobre",
"content": "Bem vindo a página sobre"
}
return render(request, "about/view.html", context)
def contact_page(request):
contact_form = ContactForm(request.POST or None)
context = {
"title": "Página de Contato",
"content": "Bem vindo a página de contato",
"form": contact_form
}
if contact_form.is_valid():
print(contact_form.cleaned_data)
return render(request, "contact/view.html", context)
def login_page(request):
form = LoginForm(request.POST or None)
context = {
"form": form
}
print("User logged in")
print(request.user.is_authenticated)
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
print(user)
print(request.user.is_authenticated)
if user is not None:
print(request.user.is_authenticated)
login(request, user)
print("Login válido")
print(request.user.is_authenticated)
# Redireciona para uma página de sucesso.
return redirect("/")
else:
#Retorna uma mensagem de erro de 'invalid login'.
print("Login inválido")
return render(request, "auth/login.html", context)
def logout_page(request):
context = {
"content": "Você efetuou o logout com sucesso! :)"
}
logout(request)
return render(request, "auth/logout.html", context)
User = get_user_model()
def register_page(request):
form = RegisterForm(request.POST or None)
context = {
"form": form
}
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
new_user = User.objects.create_user(username, email, password)
print(new_user)
return render(request, "auth/register.html", context)
Tudo que tá em vermelho acima a gente vai transferir agora para o /e_commerce/accounts/views.py e fazer pequenas modificações nele.
É o que tá em azul no código abaixo, então esse arquivo vai ficar assim:
/e_commerce/accounts/views.py
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.utils.http import url_has_allowed_host_and_scheme
from .forms import LoginForm, RegisterForm
def login_page(request):
form = LoginForm(request.POST or None)
context = {
"form": form
}
print("User logged in")
print(request.user.is_authenticated)
next_ = request.GET.get('next')
next_post = request.POST.get('next')redirect_path = next_ or next_post or None
redirect_path = next_ or next_post or None
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
print(user)
print(request.user.is_authenticated)
if user is not None:
print(request.user.is_authenticated)
login(request, user)
if url_has_allowed_host_and_scheme( redirect_path, request.get_host() ):
return redirect( redirect_path )
else:
# Redireciona para uma página de sucesso.
return redirect("/")
else:
#Retorna uma mensagem de erro de 'invalid login'.
print("Login inválido")
return render(request, "accounts/login.html", context)
def logout_page(request):
context = {
"content": "Você efetuou o logout com sucesso! :)"
}
logout(request)
return render(request, "accounts/logout.html", context)
User = get_user_model()
def register_page(request):
form = RegisterForm(request.POST or None)
context = {
"form": form
}
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
new_user = User.objects.create_user(username, email, password)
print(new_user)
return render(request, "accounts/register.html", context)
Parâmetro next
O parâmetro next aparece em uma URL quando um usuário está tentando acessar uma página, mas é redirecionado para outra página antes de poder acessar essa página.
Antes que um usuário possa fazer algo no site, como criar uma postagem por exemplo, ele deve estar logado.
Dessa forma, se um usuário que não está logado clicar em um link ‘Criar uma postagem‘, ele será primeiro direcionado para a página de login.
Uma vez logado, ele é redirecionado para a página ‘Criar um Post’.
url_has_allowed_host_and_scheme()
A url_has_allowed_host_and_scheme() tem os seguintes parâmetros:
url_has_allowed_host_and_scheme(url, allowed_hosts, require_https = False))
Retorna True se a url for um redirecionamento seguro, ou seja, não aponta para um host diferente e usa um esquema seguro.
Sempre retorna False se for uma url vazia.
Se require_https for True, apenas ‘https‘ será considerado um esquema válido, caso contrário ‘http‘ e ‘https’ serão válidos.
O padrão é False.
O ?next={{request.path}} no final das URLs adiciona um parâmetro de URL a seguir, contendo o endereço (URL) da página atual, ao final do URL vinculado.
Após o usuário ter efetuado login/logout com sucesso, as views usarão este valor “next” para redirecionar o usuário de volta à página em que ele clicou pela primeira vez, antes de fazer o login/logout.
Ou seja, vamos dizer que o usuário não está logado.
Aí ele clica em algum produto, pra visualizar os detalhes daquele produto.
Aí ele resolve fazer o login.
Depois de efetuado o login, você pode definir o next para redirecionar para a página do produto que ele tava visualizando, só que agora ele tá logado.
Para isso funcionar vamos fazer o seguinte, no e_commerce/templates/base/navbar.html insira ?next={{request.path}} no final da url de login.
e_commerce/templates/base/navbar.html
{% url 'home' as home_url %}
{% url 'contact' as contact_url %}
{% url 'products:list' as products_list_url %}
{% url 'login' as login_url %}
{% url 'logout' as logout_url %}
{% url 'register' as register_url %}
{% url 'cart:home' as cart_url %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-3">
<div class='container'>
<a class="navbar-brand" href="{{ home_url }}">
<img src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" width="30" height="30" class="d-inline-block align-top" alt="">
{% if nome_da_marca %}
{{ nome_da_marca }}
{% else %} Código Fluente eCommerce
{% endif %}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item {% if request.path == home_url %} active {% endif %}">
<a class="nav-link" href="{{ home_url }}">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item {% if request.path == contact_url %} active {% endif %}">
<a class="nav-link" href="{{ contact_url }}">Contato</a>
</li>
<li class="nav-item {% if request.path == products_list_url %} active {% endif %}">
<a class="nav-link" href="{{ products_list_url }}">Produtos</a>
</li>
{% if request.user.is_authenticated %}
<li class="nav-item {% if request.path == login_url %} active {% endif %}">
<a class="nav-link" href="{{ logout_url }}">Logout</a>
</li>
{% else %}
<li class="nav-item {% if request.path == login_url %} active {% endif %}">
<a class="nav-link" href="{{ login_url }}?next={{request.path}}">Login</a>
</li>
<li class="nav-item {% if request.path == register %} active {% endif %}">
<a class="nav-link" href="{{ register_url }}">Registrar-se</a>
</li>
{% endif %}
<li class="nav-item {% if request.path == cart_url %} active {% endif %}">
<a class="nav-link" href="{{ cart_url }}">
{{ request.session.cart_items }}<i class="fa fa-shopping-cart"></i>
</a>
</li>
</ul>
{% include 'search/snippets/search-form.html' %}
</div><!-- fim da div navbarNav-->
</div><!--fim container-->
</nav>
Forms de login e register
Vamos pegar os forms de login e register do e_commerce/e_commerce/forms.py e transferir para o e_commerce/accounts/forms.py.
e_commerce/e_commerce/forms.py
from django import forms
from django.contrib.auth import get_user_model
User = get_user_model()
class ContactForm(forms.Form):
full_name = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Seu nome completo"
}
)
)
email = forms.EmailField(
widget=forms.EmailInput(
attrs={
"class": "form-control",
"placeholder": "Digite seu email"
}
)
)
content = forms.CharField(
widget=forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Digite sua mensagem"
}
)
)
def clean_email(self):
email = self.cleaned_data.get("email")
if not "gmail.com" in email:
raise forms.ValidationError("O Email deve ser do gmail.com")
return email
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
Agora vamos transferir tudo que tá em vermelho no código acima para o forms do accounts e também fazer os imports do get_user_model e do forms.
e_commerce/accounts/forms.py
from django import forms
from django.contrib.auth import get_user_model
User = get_user_model()
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
No url.py do ecommerce corrija os imports para importar o login_page, logout_page, register_page do accounts.views.
e_commerce/e_commerce/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
from carts.views import cart_home
from accounts.views import login_page, register_page, logout_page
from .views import (home_page,
about_page,
contact_page
)
urlpatterns = [
path('', home_page, name='home'),
path('about/', about_page, name='about'),
path('contact/', contact_page, name='contact'),
path('cart/', include("carts.urls", namespace="cart")),
path('login/', login_page, name='login'),
path('logout/', logout_page, name='logout'),
path('register/', register_page, name='register'),
path('bootstrap/', TemplateView.as_view(template_name='bootstrap/example.html')),
path('search/', include("search.urls", namespace="search")),
path('products/', include("products.urls", namespace="products")),
path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
No e_commerce/e_commerce/settings.py defina a url que o usuário será direcionado quando fizer o logout, no código abaixo, coloquei pra ser redirecionado para a página de login.
E também registre o app accounts em INSTALLED_APPS.
e_commerce/e_commerce/settings.py
"""
Django settings for e_commerce project.
Generated by 'django-admin startproject' using Django 2.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'xjmv-0^l__duq4-xp54m94bsf02lx4&1xka_ykd_(7(5#9^1o^'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#our apps
'accounts',
'carts',
'orders',
'products',
'search',
'tags',
]
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',
]
LOGOUT_REDIRECT_URL = '/login/'
ROOT_URLCONF = 'e_commerce.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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 = 'e_commerce.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.1/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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static_local")
]
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "static_root")
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "media_root")
Vamos criar a pasta de templates html do accounts src/accounts/templates/accounts/, e transferir os templates e_commerce/templates/auth/login.html e e_commerce/templates/auth/register.html para dentro.
Agora podemos deletar a pasta e_commerce/templates/auth/ porque não vamos mais precisar dela.
Primeiro teste
Faça um primeiro teste, se tiver logado, faça o logout, vá na página de listagem de produtos, escolha um produto qualquer, clique para visualizar os detalhes dele, em seguida faça o login.
127.0.0.1:8000
Se tudo funcionou corretamente, você deverá ser redirecionado para a página do produto que você tava visualizando antes de efetuar o login.
Segundo teste
Agora um segundo teste, faça o logout se tiver logado, adicione um produto qualquer ao carrinho e acesse a url baixo.
127.0.0.1:8000/login/?next=/cart/checkout/
Ele cai na página de login e quando você fizer o login ele vai pro checkout.
Terceiro teste
Faça o mesmo teste, tentando acessar agora uma outra rul, por exemplo, o endereço do http://www.duckduckgo.com:
127.0.0.1:8000/login/?next=http://www.duckduckgo.com
Veja que ele vai redirecionar o usuário para a home do site do ecommerce e não para a página do duckduckgo.
Pra finalizar
No e_commerce/e_commerce/urls.py vamos importar o LogoutView.
e_commerce/e_commerce/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth.views import LogoutView
from django.urls import path, include
from django.views.generic import TemplateView
from carts.views import cart_home
from .views import (home_page,
about_page,
contact_page,
login_page,
logout_page,
register_page
)
urlpatterns = [
path('', home_page, name='home'),
path('about/', about_page, name='about'),
path('contact/', contact_page, name='contact'),
path('cart/', include("carts.urls", namespace="cart")),
path('login/', login_page, name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
path('register/', register_page, name='register'),
path('bootstrap/', TemplateView.as_view(template_name='bootstrap/example.html')),
path('search/', include("search.urls", namespace="search")),
path('products/', include("products.urls", namespace="products")),
path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Fico por aqui, na próxima vamos construir o billing profile model.
Voltar para página principal do blog
Todas as aulas desse curso
Aula 53 Aula 55
Código final da aula:
https://github.com/toticavalcanti
Outros canais
Toti:
https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA
Backing track / Play-along:
https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA
Código Fluente
https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w
Putz!
https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw
Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook
Esse é o link do código fluente no Pinterest
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Nos vemos na próxima então, \o/ 😉 Bons Estudos!