Aula 89 - Lidando com o Sinal do Objeto Visualizado
Agora vamos lidar com o sinal emitido pelo objeto visualizado.
Temos o
mixin, temos o
signal, que fizemos na
aula passada, e portanto, uma forma de trabalhar com esses dados dos produtos visualizados.
Então bora lá!
Abra o
models.py do
analytics e faça as alterações indicadas abaixo em
azul.
django_ecommerce/e_commerce/analytics/models.py
from django.conf import settings
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from .signals import object_viewed_signal
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):
print(sender)
print(instance)
print(request)
print(request.user)
object_viewed_signal.connect(object_viewed_receiver)
Agora entre na página de produtos, clique na view de algum produto e no console do servidor, vejo os
prints da
object_viewed_receiver().
Explicação das alterações feitas acima
from .signals import object_viewed_signal: Importa um sinal personalizado chamado object_viewed_signal de um arquivo signals.py no mesmo diretório. Esse sinal é usado para notificar partes do aplicativo quando um objeto é visualizado.
def object_viewed_receiver(sender, instance, request, *args, **kwargs): Define uma função que atua como receptor para o sinal object_viewed_signal. Essa função será chamada automaticamente quando o sinal for emitido. Ela recebe informações sobre o evento que disparou o sinal, incluindo o modelo que enviou o sinal (sender), a instância do modelo (instance), e o objeto de requisição HTTP (request).
object_viewed_signal.connect(object_viewed_receiver): Conecta o receptor object_viewed_receiver ao sinal object_viewed_signal. Isso significa que, sempre que o sinal object_viewed_signal for emitido em qualquer parte do aplicativo, a função object_viewed_receiver será executada.
Esse código permite que você monitore quando um objeto específico é visualizado no seu aplicativo Django, executando a função
object_viewed_receiver em resposta a esse evento.
Arquivo signals.py criado na aula passada
No arquivo
signals.py, foi definido um
sinal personalizado Django utilizando a classe
Signal do módulo.
django_ecommerce/e_commerce/analytics/signals.py
from django.dispatch import Signal
object_viewed_signal = Signal(providing_args=['instance', 'request'])
IMPORTANTE. A partir da versão 4.0 do Django, o signal não recebe mais o providing_args, portanto a forma correta do signals.py é essa abaixo.
Vejamos o que cada parte faz:
- Importação da Classe
Signal:
from django.dispatch import Signal: Aqui, você está importando a classe Signal do módulo django.dispatch. No Django, Signal é uma forma de permitir que determinados remetentes notifiquem um conjunto de receptores quando ocorrem ações no sistema.
- Criação de um Sinal Personalizado (
object_viewed_signal):
object_viewed_signal = Signal(providing_args=['instance', 'request']): Nesta linha, você está criando um sinal personalizado chamado object_viewed_signal.
providing_args=['instance', 'request']: Esta parte é uma maneira de documentar quais argumentos são esperados pelos receptores deste sinal. Aqui, os argumentos são instance (a instância do objeto que foi visualizado) e request (o objeto de requisição HTTP).
IMPORTANTE. A partir da versão 4.0 do Django, o signal não recebe mais o providing_args, portanto a forma correta do signals.py é essa abaixo.
django_ecommerce/e_commerce/analytics/signals.py
from django.dispatch import Signal
object_viewed_signal = Signal()
Melhorando o utils.py
A razão para usar
request.META.get("REMOTE_ADDR", None) é garantir que, se o endereço
IP não estiver disponível no
request.META, como em situações onde o usuário está atrás de um proxy, a função retornará
None em vez de causar um erro.
Isso torna o código mais seguro e previne falhas caso a chave
"REMOTE_ADDR" não exista no dicionário.
django_ecommerce/e_commerce/analytics/utils.py
def get_client_ip(request):
# Obtém o valor do cabeçalho 'HTTP_X_FORWARDED_FOR' do objeto 'request.META'.
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
# Verifica se o cabeçalho 'HTTP_X_FORWARDED_FOR' está presente.
if x_forwarded_for:
# Se estiver presente, o cabeçalho pode conter uma lista de endereços IP separados por vírgulas.
# Portanto, dividimos a string em uma lista usando ',' como delimitador e pegamos o primeiro elemento da lista,
# que é o endereço IP do user.
ip = x_forwarded_for.split(",")[0]
else:
# Se o cabeçalho 'HTTP_X_FORWARDED_FOR' não estiver presente, usamos o endereço IP do user
# que está disponível em 'request.META["REMOTE_ADDR"]'.
ip = request.META.get("REMOTE_ADDR", None)
# Retornamos o endereço IP final.
return ip
Continuando as alterações do models.py do analytics
django_ecommerce/e_commerce/analytics/models.py
from django.conf import settings
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
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):
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)
Agora entre na
página de
produtos e
visualize alguns deles, depois entre na
página de
admin,
acesse a parte de
analytics/objectviewed.
E veja que agora temos uma forma de salvar e armazenar items visualizados.
Explicação das alterações
- Importação de
get_client_ip:
from .utils import get_client_ip: Esta linha importa a função get_client_ip do móduloutils que está no mesmo diretório que o arquivo atual, indicado pelo .. A função get_client_ip é usada para obter o endereço IP do cliente que está fazendo a requisição.
- Função
object_viewed_receiver:
- Esta função é um receptor (receiver) de sinal que é chamado quando um objeto é visualizado. Em Django, os sinais permitem que determinadas ações sejam executadas em resposta a eventos específicos.
- Parâmetros da Função:
sender: O modelo que enviou o sinal.
instance: A instância do modelo que foi visualizada.
request: O objeto de requisição HTTP.
*args, **kwargs: Argumentos e palavras-chave adicionais.
- Corpo da Função:
c_type = ContentType.objects.get_for_model(sender): Obtém o ContentType para o modelo que enviou o sinal. ContentType é um modelo do Django que armazena informações sobre os modelos usados em um aplicativo.
new_view_obj = ObjectViewed.objects.create(...): Cria um novo registro no modelo ObjectViewed, salvando quem viu o objeto, qual foi o objeto, o ID do objeto e o endereço IP do usuário que o viu.
- Criação do Registro
ObjectViewed:
user = request.user: O usuário que fez a requisição.
content_type = c_type: O tipo de conteúdo do objeto visualizado.
object_id = instance.id: O ID da instância visualizada.
ip_address = get_client_ip(request): O endereço IP do usuário, obtido pela função get_client_ip.
- Conexão com o Sinal:
object_viewed_signal.connect(object_viewed_receiver): Conecta o receptor object_viewed_receiver ao sinal object_viewed_signal. Isso significa que, sempre que o sinal object_viewed_signal for disparado, a função object_viewed_receiver será chamada.
Por essa aula é só, na próxima a gente vai fazer o handle do sinal emitido pelos objetos visualizados.
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!