首页 > 解决方案 > 尝试在未登录的情况下查看产品时出现值错误

问题描述

创建了一个分析模型来跟踪用户数据并获取 IP 地址。但它只适用于登录用户。来宾用户尝试查看对象时会引发错误。

产品-views.py

class ProductDetailSlugView(ObjectViewedMixin, DetailView):

    def get_context_data(self, *args, **kwargs):
        context             = super(ProductDetailSlugView, self).get_context_data(*args, **kwargs)
        cart_obj, new_obj   = Cart.objects.new_or_get(self.request)
        context['cart']     = cart_obj

        return context

帐户-views.py

class LoginView(FormView):

        if user is not None:
            login(request, user)
            user_logged_in.send(user.__class__, instance=user, request=request)

            try:
                del request.session['guest_id']
            except:
                pass

分析 - mixin.py

from .signals import object_viewed_signal

class ObjectViewedMixin(object):
    def get_context_data(self, *args, **kwargs):
        context = super(ObjectViewedMixin, self).get_context_data(*args, **kwargs)
        request = self.request
        #instance = context['object']
        instance = context.get('object')
        if instance:
            object_viewed_signal.send(instance.__class__, instance=instance, request=request)

        return context

分析-signals.py

from django.dispatch import Signal

object_viewed_signal = Signal(providing_args=['instance', 'request']) 

分析 - utils.py

def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]                      
    else:
        ip = request.META.get('REMOTE_ADDR', None)
    return ip

分析-models.py

def object_viewed_reciver(sender, instance, request, *args, **kwargs):
    _type = ContentType.objects.get_for_model(sender)                                                       # instance.__class__
    print(sender)
    print(instance)
    print(request)
    print(request.user)
    ip_address = None
    try:
        ip_address = get_client_ip(request)
    except:
        pass

    new_view_obj = ObjectViewed.objects.create(
        user = request.user,
        content_type = _type,
        object_id = instance.id,
        ip_address = ip_address                                                                            # TODO: parsing the ip address to get the location
    )

object_viewed_signal.connect(object_viewed_reciver)


class UserSession(models.Model):
    user            = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    ip_address      = models.CharField(max_length=220, blank=True, null=True)
    session_key     = models.CharField(max_length=120, 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
        ended = self.ended
        try:
            Session.objects.get(pk=session_key).delete()
            self.active = False
            self.ended = True
            self.save()
        except:
            pass
        return self.ended

def user_logged_in_receiver(sender, instance, request, *args, **kwargs):
    print(instance)
    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)

我得到以下用户:

lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 211, in __set__
    self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7f4975fa09e8>>": "ObjectViewed.user" must be a "User" instance.

    products/views.py in get_context_data

    context = super(ProductDetailSlugView, self).get_context_data(*args, **kwargs)

    analytics/mixin.py  in get_context_data

    object_viewed_signal.send(instance.__class__, instance=instance, request=request) 

标签: pythondjango

解决方案


如错误所示,问题发生在object_viewed_reciver信号中,您尝试在其中ObjectViewed为当前用户创建一个实例;但模型需要一个实际用户的实例。

您需要决定在这种情况下该怎么做。一种可能性是使用户字段可以为空:

class ObjectViewed(model.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
    ...

这样在您的信号中您可以执行以下操作:

user = request.user if request.user.is_authenticated else None
new_view_obj = ObjectViewed.objects.create(
    user=user,
    content_type=_type,
    object_id=instance.id,
    ip_address=ip_address                                                                                
)

推荐阅读