Aula 90 – Tratamento e Encerramento de Sessões de Usuário

Aula 90 – Tratamento e Encerramento de Sessões de Usuário

Loja Online - Django

Loja Online – Django

Voltar para página principal do blog

Todas as aulas desse curso

Aula 89                                   Aula 91

Redes Sociais:

facebook

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

Canais do Youtube

Toti

Lofi Music Zone Beats

Backing Track / Play-Along

Código Fluente

Putz!

Vocal Techniques and Exercises

PIX para doações

PIX Nubank

PIX Nubank


 

Aula 90 – Tratamento e Encerramento de Sessões de Usuário

O que faremos agora é colocar tudo o que aprendemos com o Object Viewed em uma sessão de usuário.

Vamos criar o modelo de sessão do usuário e um sinal(signal), importar algumas coisas, etc.

Antes de iniciar as modificações, crie uma branch para trabalhar as mudanças da aula e abra o models do analytics.

No código abaixo temos as Importações

  • from django.db.models.signals import pre_save, post_save: Essas importações permitem que você conecte funções (conhecidas como “signal handlers” ou “receivers“) a sinais específicos do Django, que são emitidos em determinados pontos do ciclo de vida de um modelo. Esses sinais são úteis para executar código antes ou depois de um modelo ser salvo no banco de dados.
  • from django.contrib.sessions.models import Session: Esta importação é utilizada para interagir com a tabela de sessões do Django, permitindo o acesso e manipulação de sessões de usuário. Em contextos típicos, essa classe é usada para gerenciar dados de sessão, como identificar sessões únicas de usuários através de seus session_key.
  • from accounts.signals import user_logged_in: Esta linha importa o sinal user_logged_in do accounts. Esse sinal é emitido quando um usuário faz login com sucesso, permitindo que outras partes do aplicativo reajam a esse evento, como registrar informações de sessão do usuário.

Modelo UserSession e user_logged_in_receiver

O modelo UserSession é definido para rastrear sessões de usuários no seu aplicativo. Vamos detalhar os campos deste modelo:

  • user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE): Este campo estabelece uma relação de chave estrangeira com o modelo de usuário do Django. Isso permite associar cada sessão a um usuário específico. Os parâmetros blank=True e null=True indicam que o campo pode ser deixado em branco ou conter um valor NULL no banco de dados, respectivamente, o que significa que sessões anônimas podem ser rastreadas.
  • ip_address = models.CharField(max_length=220, blank=True, null=True): Armazena o endereço IP do usuário associado à sessão. Isso pode ser útil para análises de segurança ou para rastrear a origem das sessões dos usuários.
  • session_key = models.CharField(max_length=100, blank=True, null=True): Este campo armazena a chave de sessão única, que identifica a sessão no banco de dados de sessões do Django.
  • timestamp = models.DateTimeField(auto_now_add=True): Registra o momento em que a sessão foi criada, usando a data e hora atuais ao criar um registro de UserSession.
  • active = modelsBooleanField(default=True): Um campo booleano que indica se a sessão está ativa. Isso pode ser usado para rastrear sessões que ainda são válidas.
  • ended = modelsBooleanField(default=False): Similar ao campo active, mas indica se a sessão foi encerrada.

Função user_logged_in_receiver

Esta função é um receiver para o sinal user_logged_in.

Ela é chamada automaticamente quando o sinal é emitido.

Aqui está o que acontece dentro desta função:

  • Captura detalhes sobre o usuário (user = instance), o endereço IP (ip_address = get_client_ip(request)) e a chave de sessão (session_key = request.session.session_key).
  • Cria um novo registro de UserSession com essas informações, efetivamente registrando a sessão do usuário no sistema.

Finalmente, o sinal user_logged_in é conectado ao receiver user_logged_in_receiver, significando que cada vez que um usuário fizer login com sucesso, as informações da sessão serão registradas conforme definido na função receiver.

django_ecommerce/e_commerce/analytics/models.py 

from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from accounts.signals import user_logged_in
from .signals import object_viewed_signal
from .utils import get_client_ip

User = settings.AUTH_USER_MODEL

class ObjectViewed(models.Model):
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) # specific user, instance.id
    ip_address = models.CharField(max_length=220, blank=True, null=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) # Product, Order, Cart, Address...
    object_id = models.PositiveIntegerField() # User id, Product id, Order id
    content_object = GenericForeignKey('content_type', 'object_id')
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.content_object} viewed on {self.timestamp}"

    class Meta:
        ordering = ['-timestamp'] # most recent saved show up first
        verbose_name = 'Object viewed'
        verbose_name_plural = 'Objects viewed'

def object_viewed_receiver(sender, instance, request, *args, **kwargs):
    c_type = ContentType.objects.get_for_model(sender) # instance.__class__
    new_view_obj = ObjectViewed.objects.create(
        user = request.user,
        content_type = c_type,
        object_id = instance.id,
        ip_address = get_client_ip(request)
    )

object_viewed_signal.connect(object_viewed_receiver)

class UserSession(models.Model):
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) # specific user, instance.id
    ip_address = models.CharField(max_length=220, blank=True, null=True)
    session_key = models.CharField(max_length=100, blank=True, null=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=True)
    ended = models.BooleanField(default=False)

def user_logged_in_receiver(sender, instance, request, *args, **kwargs):
    user = instance
    ip_address = get_client_ip(request)
    session_key = request.session.session_key
    UserSession.objects.create(
        user = user,
        ip_address = ip_address,
        session_key = session_key
    )

user_logged_in.connect(user_logged_in_receiver)

Faça as Migration:

python manage.py makemigrations

python manage.py migrate

A próxima coisa a fazer é criar um signal para login do usuário.

Então vamos criar o signals.py na pasta accounts.

django_ecommerce/e_commerce/accounts/signals.py


from django.dispatch import Signal

user_logged_in = Signal()

Importe ele no view.py do accounts.

A linha from .signal import user_logged_in importa o sinal user_logged_in definido no signals do accounts.

Neste caso, o sinal user_logged_in é destinado a ser emitido sempre que um usuário faz login com sucesso, permitindo que outras partes do aplicativo reajam a esse evento.

A expressão user_logged_in.send(sender=user.__class__, request=request, user=user) é onde o sinal user_logged_in é efetivamente emitido, ou “enviado”.

Vamos quebrar essa linha para entender melhor:

  1. sender: O remetente do sinal, que é a classe do objeto user (user.__class__). Isso informa aos receptores do sinal qual classe está enviando o sinal.
  2. instance: O objeto user que foi autenticado e fez login.
  3. request: O objeto de solicitação (self.request), que contém informações sobre a solicitação HTTP atual, como parâmetros GET, POST e outros metadados.

Em resumo, essa linha está emitindo um sinal indicando que um usuário fez login com sucesso. Ele envia informações sobre o usuário que fez login e a solicitação HTTP associada ao login.

Os receptores desse sinal podem então executar ações com base nessas informações, como registrar o evento de login, atualizar dados do usuário, iniciar uma sessão, entre outras possibilidades.

Essencialmente, essa linha de código permite que você execute lógica adicional em outras partes do seu aplicativo em resposta a um usuário fazendo login, sem ter que acoplar firmemente essa lógica à sua view de login.

Por exemplo, você pode ter um receiver que registra a hora do login, um que verifica se o perfil do usuário está completo, ou qualquer outra ação que você queira realizar automaticamente quando um usuário faz login.

django_ecommerce/e_commerce/accounts/views.py 


from django.contrib.auth import authenticate, login, logout, get_user_model
from django.views.generic import CreateView, FormView, View 
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, GuestForm
from .models import GuestEmail
from .signals import user_logged_in


def guest_register_view(request):
    form = GuestForm(request.POST or None)
    context = {
        "form": form
    }
    next_ = request.GET.get('next')
    next_post = request.POST.get('next')
    redirect_path = next_ or next_post or None
    if form.is_valid():
        email       = form.cleaned_data.get("email")
        new_guest_email = GuestEmail.objects.create(email=email)
        request.session['guest_email_id'] = new_guest_email.id
        if url_has_allowed_host_and_scheme(redirect_path, request.get_host()):
            return redirect(redirect_path)
        else:
            return redirect("/register/")
    return redirect("/register/")

class LoginView(FormView):
    form_class = LoginForm
    success_url = '/'  # Redireciona para a raiz do projeto
    template_name = 'accounts/login.html'
    
    def form_valid(self, form):
        email = form.cleaned_data.get("email")
        password = form.cleaned_data.get("password")
        user = authenticate(request=self.request, username=email, password=password) 
        if user is not None:
            login(self.request, user)
            user_logged_in.send(sender=user.__class__, instance=user, request=self.request)
            try:
                del self.request.session['guest_email_id']
            except:
                pass
        return super(LoginView, self).form_valid(form)

# def login_page(request):
#     form = LoginForm(request.POST or None)
#     context = {
#                     "form": form
#               }
#     next_ = request.GET.get('next')
#     next_post = request.POST.get('next')
#     redirect_path = next_ or next_post or None
#     if form.is_valid():
#         username = form.cleaned_data.get("username")
#         password = form.cleaned_data.get("password")
#         user = authenticate(request, username=username, password=password) 
#         if user is not None:
#             login(request, user)
#             try:
#                 del request.session['guest_email_id']
#             except:
#                 pass
#             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)

class LogoutView(View):
    template_name = 'accounts/logout.html'
    
    def get(self, request, *args, **kwargs):
        context = {
            "content": "Você efetuou o logout com sucesso! :)"
        }
        logout(request)
        return render(request, self.template_name, context)
    
# def logout_page(request):
#     context = {
#                 "content": "Você efetuou o logout com sucesso! :)"
#               }
#     logout(request)
#     return render(request, "accounts/logout.html", context)

class RegisterView(CreateView):
    form_class = RegisterForm
    template_name = 'accounts/register.html'
    success_url = '/login/'

# User = get_user_model()
# def register_page(request):
#     form = RegisterForm(request.POST or None)
#     context = {
#                 "form": form
#               }
#     if form.is_valid():
#         form.save()
#     return render(request, "accounts/register.html", context)

Precisamos de um método para encerrar a sessão depois de salvar no banco.

django_ecommerce/e_commerce/analytics/admin.py


from django.contrib import admin
from .models import ObjectViewed
from .models import UserSession
admin.site.register(ObjectViewed)
admin.site.register(UserSession)

A linha admin.site.register(UserSession) no arquivo admin.py do seu aplicativo Django está registrando o modelo UserSession no site de administração do Django.

Isso significa que o Django irá gerar automaticamente uma interface no painel de administração para que você possa visualizar, adicionar, editar e deletar instâncias do modelo UserSession.

Certifique-se que o projeto esteja rodando e faça o login no painel admin do django e na parte de Analytics clique em UserSession e em UserSessionObject.

localhost:8000/admin

Veja que você tem uma session key no UserSessionObject.

Vamos explorar o session no shell do django.

Abra outro terminal para poder deixar o servidor rodando e digite:

python manage.py shell

Copie o número da session key do UserSessionObject e atribua a session_key.

>>>session_key = 'qus0xwjinskfitjdn8dhrnhcwhu9f2ds'

Importe o Session

>>>from django.contrib.sessions.models import Session

>>>Session.objects.get(pk=session_key )

>>>Session.objects.get(pk=session_key ).delete()

Agora dê um refresh na página e veja que você foi deslogado.

Essa é a forma como django gerencia as sessões, como ele cria e deleta as sessões.

O Django usa uma sessão consistente entre o frontend e o backend.

Isso significa que, se o mesmo usuário estiver logando no admin e na loja com as mesmas credenciais e a sessão ainda estiver ativa, ele permanecerá logado em ambos os lugares.

A sincronização de sessão entre o admin e o frontend acontece naturalmente com o Django, porque o Django usa um sistema de sessão centralizado.

Quando um usuário faz login em qualquer parte do site, seja no admin ou no frontend, o Django cria uma sessão para esse usuário, que é válida em todo o site, a menos que você tenha configurado algo para separar explicitamente as sessões entre o admin e o frontend.

Voltando ao código

O código em azul abaixo, é a lógica para encerrar sessões de usuário no Django, juntamente com a definição de receivers para os sinais post_save que são conectados aos modelos UserSession e User.

Vamos detalhar cada parte:

FORCE_SESSION_TO_ONE e FORCE_INACTIVE_USER_ENDSESSION

Essas duas linhas de código estão obtendo valores de configuração do arquivo settings.py do projeto Django, com opções de fallback caso essas configurações não estejam explicitamente definidas.

FORCE_SESSION_TO_ONE = getattr(settings, ‘FORCE_SESSION_TO_ONE’, False): Esta linha busca a configuração FORCE_SESSION_TO_ONE dentro do objeto settings do Django. O método getattr é usado para tentar obter o valor dessa configuração, caso não esteja definido em settings.py, o valor padrão False é utilizado. Se FORCE_SESSION_TO_ONE for True, indica que o sistema deve forçar apenas uma sessão ativa por usuário a qualquer momento, encerrando automaticamente sessões anteriores quando uma nova sessão é iniciada.

FORCE_INACTIVE_USER_ENDSESSION = getattr(settings, ‘FORCE_INACTIVE_USER_ENDSESSION’, False): De maneira semelhante, esta linha busca a configuração FORCE_INACTIVE_USER_ENDSESSION. Se for True, o sistema encerra automaticamente todas as sessões ativas de um usuário quando sua conta é marcada como inativa (is_active = False).

Essas configurações permitem controlar o comportamento das sessões de usuário no seu projeto Django de maneira flexível.

Você pode habilitá-las adicionando as seguintes linhas ao seu arquivo settings.py:

FORCE_SESSION_TO_ONE = True # Força apenas uma sessão por usuário

FORCE_INACTIVE_USER_ENDSESSION = True # Encerra sessões quando o usuário é marcado como inativo

No settings.py vamos colocar como False ambas as opções, o código já tá controlando isso.

Método end_session()

O método end_session é um método de instância, o que significa que ele é chamado em um objeto específico de UserSession. Vamos passar por cada linha:

  • session_key = self.session_key: Isso pega a chave da sessão (um identificador único para cada sessão) do objeto UserSession atual.
  • try:: Este bloco é usado para “tentar” executar um código que pode potencialmente falhar, ou seja, pode lançar uma exceção.
    • Session.objects.get(pk=session_key).delete(): Aqui, tentamos encontrar uma sessão do Django (não uma UserSession, mas a sessão real usada pelo Django para manter o estado de login) que tenha a chave primária (pk) igual à session_key do nosso UserSession. Se encontrada, a sessão é deletada, o que efetivamente desloga o usuário do ponto de vista do Django.
  • except Session.DoesNotExist:: Se a sessão com a session_key dada não existir, o Django lançará uma Session.DoesNotExist exceção. Neste caso, usamos pass para simplesmente ignorar esse erro e continuar. Isso significa que se a sessão do Django já foi excluída, não faremos nada.
  • except Exception as e:: Se ocorrer qualquer outro tipo de exceção ao tentar excluir a sessão, capturamos essa exceção e a imprimimos no console. Isso é para fins de depuração e deve ser manuseado com cuidado em um ambiente de produção, pois a impressão de erros pode não ser a melhor maneira de lidar com exceções inesperadas.
  • self.active = False: Independente de a sessão do Django existir ou não, definimos o campo active do nosso objeto UserSession como False, indicando que esta UserSession não deve mais ser considerada ativa.
  • self.ended = True: Também definimos o campo ended como True, indicando que esta sessão de usuário foi encerrada.
  • self.save(): Finalmente, salvamos o objeto UserSession com as atualizações que fizemos nos campos active e ended.

Método save()

O método save é o método padrão do Django que é chamado quando você salva um objeto no banco de dados.

  • if not self.active and not self.ended:: Antes de salvar o objeto, verificamos se o campo active é False e o campo ended é False. Se ambos forem False, chamamos o método end_session que acabamos de descrever. Isso pode ser usado para garantir que, se por algum motivo estivermos salvando uma sessão que deveria ser encerrada, encerramos corretamente.
  • super().save(*args, **kwargs): Depois de lidar com o estado da sessão, chamamos o método save da superclasse (no caso, o save padrão do Django para modelos) para continuar o processo normal de salvar o objeto no banco de dados. Os *args e **kwargs são argumentos e argumentos nomeados que podem ser passados para o método save padrão do Django e são aqui repassados.

django_ecommerce/e_commerce/analytics/models.py 


from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from accounts.signals import user_logged_in
from .signals import object_viewed_signal
from .utils import get_client_ip

User = settings.AUTH_USER_MODEL
FORCE_SESSION_TO_ONE = getattr(settings, 'FORCE_SESSION_TO_ONE', False)
FORCE_INACTIVE_USER_ENDSESSION= getattr(settings, 'FORCE_INACTIVE_USER_ENDSESSION', False)

class ObjectViewed(models.Model):
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) # specific user, instance.id
    ip_address = models.CharField(max_length=220, blank=True, null=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) # Product, Order, Cart, Address...
    object_id = models.PositiveIntegerField() # User id, Product id, Order id
    content_object = GenericForeignKey('content_type', 'object_id')
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.content_object} viewed on {self.timestamp}"

    class Meta:
        ordering = ['-timestamp'] # most recent saved show up first
        verbose_name = 'Object viewed'
        verbose_name_plural = 'Objects viewed'

def object_viewed_receiver(sender, instance, request, *args, **kwargs):
    c_type = ContentType.objects.get_for_model(sender) # instance.__class__
    new_view_obj = ObjectViewed.objects.create(
        user = request.user,
        content_type = c_type,
        object_id = instance.id,
        ip_address = get_client_ip(request)
    )

object_viewed_signal.connect(object_viewed_receiver)

class UserSession(models.Model):
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) # specific user, instance.id
    ip_address = models.CharField(max_length=220, blank=True, null=True)
    session_key = models.CharField(max_length=100, blank=True, null=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=True)
    ended = models.BooleanField(default=False)

    def end_session(self):
        session_key = self.session_key
        try:
            Session.objects.get(pk=session_key).delete()
        except Session.DoesNotExist:
            pass
        except Exception as e:
            print(f"Unexpected error ending session: {e}")
        self.active = False
        self.ended = True
        self.save()

    def save(self, *args, **kwargs):
        # Se 'active' for False e 'ended' ainda não for True, encerra a sessão
        if not self.active and not self.ended:
            self.end_session()
        super().save(*args, **kwargs)

def post_save_session_receiver(sender, instance, created, *args, **kwargs):
    if created:
        qs = UserSession.objects.filter(user=instance.user, ended=False, active=False).exclude(id=instance.id)
        for i in qs:
            i.end_session()
    if not instance.active and not instance.ended:
        instance.end_session()

if FORCE_SESSION_TO_ONE:
    post_save.connect(post_save_session_receiver, sender=UserSession)


def post_save_user_changed_receiver(sender, instance, created, *args, **kwargs):
    if not created:
        if instance.is_active == False:
            qs = UserSession.objects.filter(user=instance.user, ended=False, active=False)
            for i in qs:
                i.end_session()


if FORCE_INACTIVE_USER_ENDSESSION:
    post_save.connect(post_save_user_changed_receiver, sender=User)

def user_logged_in_receiver(sender, instance, request, *args, **kwargs):
    user = instance
    ip_address = get_client_ip(request)
    session_key = request.session.session_key
    UserSession.objects.create(
            user=user,
            ip_address=ip_address,
            session_key=session_key
        )


user_logged_in.connect(user_logged_in_receiver)

django_ecommerce/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
    'addresses',
    'analytics',
    'billing',
    'accounts',
    'carts',
    'orders',
    'products',
    'search',
    'tags',
]

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

AUTH_USER_MODEL = 'accounts.User' # changes the built-in user model to ours
FORCE_SESSION_TO_ONE = False
FORCE_INACTIVE_USER_ENDSESSION= False

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")

Deixar essas configurações como False no settings.py é uma abordagem deliberada que oferece várias vantagens.

Ao definir FORCE_SESSION_TO_ONE e FORCE_INACTIVE_USER_ENDSESSION como False por padrão, o desenvolvedor ou administrador do sistema tem a flexibilidade para ativar essas funcionalidades apenas se e quando necessário. Isso permite uma personalização mais granular do comportamento do aplicativo sem modificar o código fonte, apenas alterando a configuração no settings.py.

Deixar FORCE_SESSION_TO_ONE e FORCE_INACTIVE_USER_ENDSESSION como False no settings.py é uma prática que permite uma maior flexibilidade e minimiza surpresas para os desenvolvedores e administradores do sistema.

Essa abordagem reflete uma consideração cuidadosa dos princípios de design de software, onde mudanças significativas no comportamento do aplicativo devem ser opcionais, em vez de impostas por padrão.

Vamos testar

Queremos permitir multiplas sessões de usuário, se a gente quiser apenas uma sessão por usuário realmente mais a frente, será através do código que iremos controlar isso, e não configurando no settings.py.

Abra o ecommerce: localhost:8000/ e faça o login no ecommerce.

Abra o painel admin: localhost:8000/admin e faça o login também.

Abra uma janela anônima e tente fazer o login com o mesmo usuário.
Veja que ele agora não vai desconectar o login em uma das duas janelas, ele vai permitir mais de uma sessão aberta por usuário.

Agora desmarque o active da última sessão criada, e dê um refresh onde você logou por último, veja que agora você foi deslogado.

Por essa aula é só, na próxima a gente vai fazer o handle do sinal emitido pelos objetos visualizados.

Voltar para página principal do blog

Todas as aulas desse curso

Aula 89                                   Aula 91

Código final da aula:

https://github.com/toticavalcanti

Canais do Youtube

Toti

Backing Track / Play-Along

Código Fluente

Putz!

Vocal Techniques and Exercises

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:

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>