Aula 54 – Loja Online – Django – criando o accounts

Aula 54 – Loja Online – Django – Criando o accounts

Criando o accounts

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&oacute;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!

 

 

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>