4

我们有一个 Django 项目,每当她打电话给我们时,都会为一个人创建一个用户帐户。该人以后可能会或可能不会使用她的帐户登录我们的网站。

问题:如何判断用户是否曾经登录过我们的网站?

澄清:我想为数百名现有用户回答上述问题,而不仅仅是从此时开始创建的新用户。

想法1:检查User.last_login。不幸的是,无论用户是否登录,Django 都会在创建用户时进行last_login初始化。datetime.datetime.now()

想法2:检查是否User.last_login匹配User.date_joined。不幸的是,Django 将这两个字段都初始化datetime.now()它们可能相隔几微秒:

In [1]: u = User.objects.create(username="bla")

In [2]: u.date_joined - u.last_login
Out[2]: datetime.timedelta(0, 0, 23)

我正在使用的当前 hack:假设用户至少登录过一次iff user.last_login - user.date_joined >= datetime.timedelta(seconds=1)

有没有更好的方法来判断用户是否曾经登录过?

4

4 回答 4

4

如果是更新版本的 Django (> 1.8),你应该使用 User.last_login。这是文档所述:

上次登录

用户上次登录的日期时间。

在 Django 1.8 中更改:如果用户从未登录,此字段将为空。以前默认设置为当前日期/时间。

于 2015-12-23T14:47:07.853 回答
2

date_joined当您说和都设置为创建时的当前日期时,我将假设您是对last_login的,并且由于某种原因,两个分配之间有足够的时间来创建一个明显的增量。

如果是这种情况,那么您可以接受@LAK 的建议并创建一个pre_save(并检查实例的 ID 是否为 0)或post_save(并检查created参数)并手动将该last_login字段设置Nonedate_joined. 从那里你所有的未来数据都被保存在你似乎鄙视的一秒钟模糊中。

至于您现有的数据,我认为您无法对现有数据做出最佳猜测。我认为做出你所做的假设并没有太大风险。如果您想将其清理为与所有新数据相同,您只需更新数据库以设置last_login值。如果您使用的是South,这很容易进行数据迁移。否则,您可以在部署新的代码更改后创建一个要运行的脚本。

老实说,我不认为他们偏离了一点点是个问题。只要您假设用户很可能无法在创建帐户的时间范围内登录,似乎没有理由添加一堆额外的工作来强制它完全匹配。

于 2012-08-20T18:55:12.543 回答
0

我会用一个F对象来last_login比较date_joined。如果它们相等,则用户从未登录(或至少在初始注册后从未登录,这大约是您可以确定的最佳状态)

from django.db.models import F

User.objects.filter(last_login=F('date_joined'))

更新

好吧,它在我的环境中成功运行,但我想这两个可能会关闭几微秒或更长时间。如果是这种情况,那么我认为您唯一的办法是实际手动检查每个User. 如果您需要更高的准确性,您可以对以下内容进行更改,但一般来说,我认为在最初创建计数之后从未登录的用户可以被视为“从未登录”,无论是出于何种意图和目的方式,他们已经放弃了帐户。

if user.date_joined.date() == user.last_login.date():
    # do something

如果您需要更高的准确性:

date_joined = datetime.combine(user.date_joined.date(), time(user.date_joined.hour, user.date_joined.minute))
last_login = datetime.combine(user.last_login.date(), time(user.last_login.hour, user.last_login.minute))
if date_joined == last_login:
    # do something

这实质上创建了新的日期时间对象,消除了秒和微秒的差异。当然,这里 1 分钟的准确度水平就足够了。

于 2012-08-20T20:25:06.497 回答
0

QuerySet这是一个解决方案,可以按已登录或未登录该站点的用户过滤 a 。

filter_user_has_used_site()andfilter_user_hasnt_used_site()函数适用于QuerySet包含auth.User.

filter_resource_has_used_site()filter_resource_hasnt_used_site()适用于模型具有ForeignKey名为userto的字段的任何查询集auth.User

它只适用于 mysql,但可以很容易地支持其他数据库引擎。

from datetime import timedelta
from django.db import connection

MYSQL = "ABS(TIMESTAMPDIFF(SECOND,auth_user.last_login,auth_user.date_joined))"


def filter_resource_has_used_site(qs):
    """
    Takes a QuerySet of resources and returns a QuerySet only containing
    resources that has logged in to site at least once.
    """
    vendor = connection.vendor
    if vendor == 'mysql':
        # Force the orm to join to auth_user.
        qs = qs.filter(user__username__isnull=False)
        where = "".join([MYSQL, '>1'])
        return qs.extra(where=[where])
    else:
        raise NotImplementedError('Vendor type {} not supported.'.format(
            vendor))


def filter_resource_hasnt_used_site(qs):
    """
    Takes a QuerySet of resources and returns a QuerySet only containing
    resources that never logged in to site.
    """
    vendor = connection.vendor
    if vendor == 'mysql':
        # Force the orm to join to auth_user.
        qs = qs.filter(user__username__isnull=False)
        where = "".join([MYSQL, '<2'])
        return qs.extra(where=[where])
    else:
        raise NotImplementedError('Vendor type {} not supported.'.format(
            vendor))


def filter_user_has_used_site(qs):
    """
    Takes a QuerySet of users and returns a QuerySet only containing
    users that has logged in to site at least once.
    """
    vendor = connection.vendor
    if vendor == 'mysql':
        where = "".join([MYSQL, '>1'])
        return qs.extra(where=[where])
    else:
        raise NotImplementedError('Vendor type {} not supported.'.format(
            vendor))


def filter_user_hasnt_used_site(qs):
    """
    Takes a QuerySet of users and returns a QuerySet only containing
    users that never logged in to site.
    """
    vendor = connection.vendor
    if vendor == 'mysql':
        where = "".join([MYSQL, '<2'])
        return qs.extra(where=[where])
    else:
        raise NotImplementedError('Vendor type {} not supported.'.format(
            vendor))


def user_has_used_site(user):
    """
    Returns if a auth.user has logged into the site.
    """
    return abs(user.last_login - user.date_joined) > timedelta(seconds=1)
于 2014-02-19T10:32:54.497 回答