4

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

到目前为止似乎工作。但是......站点使用几乎相同的对象,很可能我们使用管理界面更改这些对象的用户字段,这对所有站点都是通用的......因此,如果我想为一个对象(它有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 文件中,只是在加载模块时运行...

4

1 回答 1

2

而不是这个,我建议使用配置文件:

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

于 2012-08-29T09:46:55.227 回答