多个站点和用户

时间:2012-08-29 09:01:39

标签: django

我们正在针对同一个数据库运行多个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'),)

此部分删除用户名的唯一性,添加网站字段,使这对(用户名,网站)唯一。

然后出现在请求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

到目前为止似乎工作。但是......这些网站使用了几乎相同的对象,而且很可能我们使用管理界面更改了这些对象的用户字段,这对所有网站都是通用的...因此,如果我想要归属一个对象(具有因为用户管理器将在site = site1上进行过滤,因此在site1上以管理员身份登录时,对于site2的用户来说是auh.User的外键,这将无效。

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

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文件中,只是在加载模块时运行...

1 个答案:

答案 0 :(得分:2)

而不是我建议使用个人资料:

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)

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

decorators.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错误。