7

単一のデータベースで複数の Web サイトを提供する Django アプリケーションを提供したいと考えていますが、ユーザー セットは異なります。ブログ アプリケーションのように考えてください。テーマの異なる複数のドメインで使用されますが、モデルにサイト フィールドを追加することで同じデータベースを使用します。

その仕事にはDjango の SitesFrameworkを使用します。しかし問題は、サイトごとにユーザー モデルを分離できなかったことです。サイトごとに一意のサイト フィールドと電子メール フィールドで同じユーザー モデルを使用したいと考えています。

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' must be unique because it is named as the 'USERNAME_FIELD'.

その問題のベストプラクティスは何ですか?

4

2 に答える 2

6

このアプローチがあなたに役立つことを願っています:

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) 次に、カスタム認証バックエンドでModelBackendを上書きします。

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>
>>> 
于 2014-11-22T20:18:29.283 に答える
3

メールを USERNAME_FIELD として保持したい場合、これは User-model の定義により常に一意でなければなりませんが、サイトごとに繰り返すことはできません。

おそらくうまくいくだろうと私が考えることができる複数のアプローチがありますが、私は次のことを行うと思います:

  • まず第一に、私は AbstractUser-model を拡張せず、サイトへの OneToOne 依存関係を作成しません。ユーザーは実際には複数のサイトに所属することが許可されているためです。したがって、ここでの最良のオプションは、ForeignKey to User と Site フィールドを使用して Member-model を作成し、それらを unique_together にすることです。したがって、サイトごとにメンバーは 1 人だけであり、ユーザーは一意のままです。これは、実生活でもケースをよりよく表しているものです。

  • 現在、サイトに新しいユーザーを登録するときは、最初にユーザー (電子メール アドレス) が既に存在するかどうかを確認し、存在する場合は、そのユーザーに新しいメンバーを割り当てるだけです。そうでない場合は、新しいユーザーも作成します。

最初に、「ユーザーが別のユーザー名、パスワード、または電子メールで別のサイトに登録したい場合はどうすればよいですか?」という質問を編集します。

私のコメントによると、サイトのユーザーアカウントを共有しても問題ない場合 (もちろん、ユーザーはこれを認識しています) 登録プロセスで、ユーザーが特定の電子メールに対して既に存在する場合、彼は通知を受けることができますそのアドレスのアカウントは既にサイト a に存在するため、このユーザー アカウントはサイト b のメンバーシップに割り当てられます。次に、確認リンクを含む電子メールが送信され、確認されると、新しいメンバーが作成され、有効なユーザーに割り当てられます。

別のアプローチ

私が間違っていたとしたら、サイト間でユーザーを共有することは問題なく、さらにはそれを望んでいても、ここではまったく新しいアプローチが必要になると思います。

行っていたように AbstractUser を拡張しますが、電子メールを USERNAME_FIELD として使用する代わりに、から構成される新しいフィールドを使用します<email>_<site_id>(これらの 2 つのフィールドは unique_together であるため、常に一意になります)... フィールドは呼び出すことができますunique_site_id。このフィールドは、サインイン フォームとログイン フォームを送信した後に入力できます。

于 2014-11-17T20:27:39.843 に答える