Python Django 1.7多站点用户模型

Python Django 1.7多站点用户模型,python,django,django-models,django-authentication,django-sites,Python,Django,Django Models,Django Authentication,Django Sites,我想为Django应用程序提供服务,该应用程序通过单个数据库但不同的用户集为多个网站提供服务。就像一个博客应用程序一样,它将被多个具有不同主题的域使用,但通过向模型添加一个站点字段来使用相同的数据库 我用它做那份工作。但问题是,我不能为不同的站点分离用户模型。我想使用一个网站字段和电子邮件字段,每个网站唯一相同的用户模型 我试图像这样扩展AbstractUser模型: from django.contrib.auth.models import AbstractUser from django.

我想为Django应用程序提供服务,该应用程序通过单个数据库但不同的用户集为多个网站提供服务。就像一个博客应用程序一样,它将被多个具有不同主题的域使用,但通过向模型添加一个站点字段来使用相同的数据库

我用它做那份工作。但问题是,我不能为不同的站点分离用户模型。我想使用一个网站字段和电子邮件字段,每个网站唯一相同的用户模型

我试图像这样扩展
AbstractUser
模型:

from django.contrib.auth.models import AbstractUser
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Member(AbstractUser):
    username = None
    site = models.ForeignKey(Site)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    on_site = CurrentSiteManager()

    class Meta:
        unique_together = ('site', 'email')
但是给出了错误:
“Member.email”必须是唯一的,因为它被命名为“USERNAME\u字段”。


解决这个问题的最佳做法是什么?

如果您想将电子邮件保留为用户名字段,根据用户模型中的定义,用户名字段必须始终是唯一的,那么您将无法在每个站点重复该字段

我可以想到不止一种可能有效的方法,但我想我会做以下几点:

  • 首先,我不会扩展AbstractUser模型并进行 OneTONE对站点的依赖性。因为用户实际上是被允许归属的 到多个站点。所以在这里,imo的最佳选择是创建一个 带有ForeignKey to User和Site字段的成员模型以及make 那些独特的东西在一起。因此,每个站点只有一个成员,并且用户保持唯一性。这在现实生活中也能更好地体现这一点

  • 现在,在为站点注册新用户时,只需首先检查该用户(电子邮件地址)是否已经存在,如果已经存在,只需为该用户分配一个新成员即可。如果没有,也创建一个新用户

首先编辑问题“如果用户希望使用不同的用户名、密码或电子邮件注册到另一个站点怎么办?”

如果根据我的评论,在注册过程中共享站点的用户帐户(当然用户知道这一点)是可以的,如果该用户已经存在于给定的电子邮件中,那么他可以被告知,由于该地址的帐户已经存在于站点-a,此用户帐户将分配给site-b的成员资格。然后,可以发送带有验证链接的电子邮件,确认后,将创建新成员并将其分配给有效用户

另一种方法

如果我的假设是错误的,那么在站点之间共享用户是可以的,甚至是需要的,那么我想这里需要一种全新的方法:


按您所做的方式扩展AbstractUser,但不要使用电子邮件作为用户名字段,而是使用由
组成的新字段(该字段始终是唯一的,因为这两个字段一起是唯一的)。。。该字段可以称为
unique\u site\u id
左右。提交登录和登录表单后,可以填充此字段。

我希望此方法对您有所帮助:

1) 保存前编写用户名:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Member(AbstractUser):
    site = models.ForeignKey(Site)
    on_site = CurrentSiteManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = []

    class Meta:
        unique_together = ('site', 'email')

from django.db.models.signals import pre_save
from django.dispatch import receiver

@receiver(pre_save, sender=Member)
def compose_username(sender, instance, **kwargs):
    instance.username = "{0}__{1}".format( instance.email, instance.site_id ) 
2) 然后在自定义身份验证后端中覆盖:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model

class MyModelBackend(ModelBackend):

    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        site = kwargs.get('site')
        identifier = "{0}__{1}".format( username, site )
        try:
            user = UserModel.objects.get(username=identifier)
            if user.check_password(password):
                return user
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)
3) 请记住在设置上设置自定义后端:

AUTH_USER_MODEL='s1.Member'
SITE_ID = 1
AUTHENTICATION_BACKENDS = ( 'MyApp.MyModule.MyModelBackend',)
4) 验证时包括站点:

>>> from s1.models import Member as M
>>> m1 = M()
>>> m1.site_id = 1
>>> m1.email = 'peter@hello.com'
>>> m1.save()
>>> m1.set_password('hi')
>>> m1.save()
>>> 
>>> from django.contrib.auth import authenticate, login
>>> u=authenticate(username='peter@hello.com', password='hi', site=1)
>>> u
<Member: peter@hello.com_at_1>
>>> 
>>从s1.models导入成员为M
>>>m1=M()
>>>m1.site_id=1
>>>m1.电子邮件地址:peter@hello.com'
>>>m1.save()
>>>m1.设置密码(“hi”)
>>>m1.save()
>>> 
>>>从django.contrib.auth导入身份验证,登录
>>>u=验证(用户名=)peter@hello.com,密码='hi',站点=1)
>>>u
>>> 

如果访问者使用相同的电子邮件和用户名注册,但使用不同的密码怎么办?或者相同的电子邮件地址但不同的用户名?或者相同的用户名但不同的电子邮件地址?好吧,如果电子邮件是正确的,它是同一个用户,因此用户不必创建新帐户。。。如果用户的个人信息不同,可能会询问用户是否希望更新其数据。。。或者用户是否应该“认为”他正在为每个站点创建一个新的/单独的帐户。。。我想它可能更像stackoverflow/-exchange站点。。。多个相关站点的一个登录/配置文件。。。。也许我误解了网站之间共享数据库的意义。我认为这些网站之间有某种关联,它们之间会共享一些数据,包括用户。我的项目不像stackoverflow。这是一个新闻网站平台,使用许多不同的和不相关的新闻网站。所有网站都使用相同的数据库,但从访问者的角度来看,用户对这些网站之间的关系一无所知。你称之为“另一种方法”的方法似乎是一个很好的解决方法。我会试试的。经过一些修复,这对我很有效。这是我的最新代码:谢谢!