【问题标题】:Multiple sites and users多个站点和用户
【发布时间】:2012-08-29 17:46:55
【问题描述】:

我们针对同一个数据库运行多个 django 站点(我们称它们为 site1、site2、site3),并且我们希望允许在它们之间使用重复的用户名。 Site 和 auth 框架似乎没有实现这一点,默认情况下,username 是 auth.User 中的唯一字段。

所以到目前为止我做了什么(猴子补丁,搞砸了用户对象......):

User._meta.get_field('username')._unique = False
User.add_to_class('site', models.ForeignKey(Site, default=Site.objects.get_current().id, blank=True, null=True))
User._meta.unique_together = (('username', 'site'),)

这块去掉了username的唯一性,增加了一个site字段,使情侣(username,site)唯一。

如果某些用户在不同站点上具有相同的用户名,那么在请求 User.objects.get(username=xx)(例如身份验证后端)时可能会出现问题。 所以,我决定修补 User.objects 管理器:

def get_query_set(filter=True):
    q = QuerySet(User.objects.model, using=User.objects._db)
    if filter:
        return q.filter(site = Site.objects.get_current())
    return q
User.objects.get_query_set = get_query_set

到目前为止似乎有效。但是......这些站点使用几乎相同的对象,并且很可能我们使用管理界面更改这些对象的用户字段,这对所有站点都是通用的......因此,如果我想为一个对象(它有auh.User 的外键)到 site2 的用户,同时在 site1 上以管理员身份登录,这是行不通的,因为用户管理器将在 site=site1 上过滤。

我挖掘了一下,发现这似乎有效:

class UserDefaultManager(UserManager):
    def get_query_set(self, filter=None):
        return QuerySet(User.objects.model)
User._default_manager = UserDefaultManager()

据我了解,_default_manager 由相关对象管理器使用。 然后,User.objects.get(username=xx) 过滤网站,而 an_object.user 不会。

嗯,问题是:是的,这很混乱,我很确定会有缺陷,但它们是什么?

下一个问题是:如果它有效,那么放置这段代码的最佳位置在哪里?它目前在 models.py 文件中,只是在加载模块时运行...

【问题讨论】:

  • 存储用户名有效的站点并在身份验证期间检查此列表不是更简单吗?通过这种方式,您可以为从另一个站点开始的用户提供重用其登录信息的能力,就像 Stack Exchange 所做的那样。
  • 其他方法会更简单,也不会那么混乱,但如果你真的想使用这个,那么你应该创建一个manager.py文件
  • 这个问题有什么想法吗? stackoverflow.com/questions/4662348/…
  • 好吧,由于站点都是相关的,使用具有多对多站点对象的配置文件,以便能够将用户从一个站点重用到另一个站点似乎是一个有趣的想法。当用户使用相同的用户名注册或尝试登录他尚未注册的站点时,我将在登录信号上添加一些挂钩。我只是觉得 django 提供了用户和站点框架有点令人失望,但不会将它们混合起来以隔离每个站点的用户:-\

标签: django


【解决方案1】:

我建议使用配置文件来代替这个:

models.py:

from django.contrib.auth.models import User


class UserProfile(models.Model):
    """ Modèle ajoutant des propriété au modèle User """
    user = models.OneToOneField(User, editable=False)
    site1 = models.BooleanField()
    site2 = models.BooleanField()
    site3 = models.BooleanField()


def create_user_profile(sender, instance, created, **kwargs):
    """ Crée la jonction entre le modèle User, et le modèle UserProfile """
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

并在每个站点上创建一个装饰器:

装饰器.py:

try:
    from functools import wraps
except ImportError:
    from django.utils.functional import wraps
from django.http import HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from distrib.views.error import error403


def site1_required(function):
    @wraps(function)
    @login_required
    def decorateur(request, *k, **a):
        if request.user.get_profile().site1 or request.user.is_superuser:
            return function(request, *k, **a)
        else:
            result = error403(request)
            return HttpResponseForbidden(result)
    return decorateur
    return function

然后在每个视图上添加装饰器,如果不允许用户在此站点上连接,他将收到 http403 错误。

【讨论】:

  • 正如我上面评论的那样,我想我会回滚到类似的东西,意思是,我不会弄乱 auth.user 模型,在我的用户配置文件中添加一个 manytomanyfield(Site),并且在登录/注册信号上添加一些连接,以在用户重新使用用户名时捕获/重定向用户。谢谢大家:)
猜你喜欢
  • 2011-11-24
  • 1970-01-01
  • 2018-05-28
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2012-06-30
  • 1970-01-01
相关资源
最近更新 更多