7

Ich möchte eine Django-Anwendung bereitstellen, die mehrere Websites mit einer einzigen Datenbank, aber unterschiedlichen Benutzersätzen bedient. Denke wie eine Blog-Anwendung, sie wird von mehreren Domains mit unterschiedlichen Themen verwendet, verwendet aber die gleiche Datenbank, indem sie ein Site-Feld zu Modellen hinzufügt.Django 1.7 Multisite Benutzermodell

Ich verwende Django's SitesFramework für diesen Job. Aber das Problem ist, ich konnte Benutzermodelle für verschiedene Sites nicht trennen. Ich möchte dasselbe Benutzermodell mit einem Site-Feld und einem E-Mail-Feld verwenden, das pro Site eindeutig ist.

Ich versuchte AbstractUser Modell so zu erweitern:

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') 

Aber gibt diesen Fehler: 'Member.email' must be unique because it is named as the 'USERNAME_FIELD'.

Was ist die beste Praxis für dieses Problem?

Antwort

4

ich diesen Ansatz hoffen, hilft Ihnen:

1) Compose Benutzernamen vor speichern:

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) überschreiben Dann ModelBackend in Ihrem benutzerdefinierten Authentifizierungs-Backend:

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) Denken Sie daran, das benutzerdefinierte Backend auf die Einstellungen zu setzen:

AUTH_USER_MODEL='s1.Member' 
SITE_ID = 1 
AUTHENTICATION_BACKENDS = ('MyApp.MyModule.MyModelBackend',) 

4) einschließen Website wenn authenticate:

>>> from s1.models import Member as M 
>>> m1 = M() 
>>> m1.site_id = 1 
>>> m1.email = '[email protected]' 
>>> m1.save() 
>>> m1.set_password('hi') 
>>> m1.save() 
>>> 
>>> from django.contrib.auth import authenticate, login 
>>> u=authenticate(username='[email protected]', password='hi', site=1) 
>>> u 
<Member: [email protected]_at_1> 
>>> 
+0

Mit ein paar Fixes funktionierte das für mich. Hier ist mein letzter Code: https://gist.github.com/muratcorlu/1ad61a43d4836d5b1227 Danke! –

3

Wenn Sie die E-Mail als USERNAME_FIELD speichern möchten, die per Definition im Benutzermodell immer eindeutig sein muss, können Sie sie nicht für jede Site wiederholen.

Es gibt mehr als einen Ansatz ich daran denken kann, wahrscheinlich funktionieren würde, aber ich denke, ich würde wie folgt vorgehen:

  • Zunächst einmal würde ich nicht das AbstractUser-Modell erweitern und machen a OneToOne Abhängigkeit von der Site. Weil ein Benutzer tatsächlich zu mehr als einer Site gehören kann . Also, hier ist die beste Option imo ist ein Member-Modell mit einem ForeignKey zu Benutzer und ein Site-Feld zu erstellen und diese unique_together. Es gibt also nur ein Mitglied pro Site, und ein Benutzer bleibt einzigartig. Was auch im wirklichen Leben der Fall ist.

  • Wenn Sie nun einen neuen Benutzer für eine Site registrieren, überprüfen Sie zuerst, ob der Benutzer (E-Mail-Adresse) bereits existiert und weisen Sie diesem Benutzer dann ein neues Mitglied zu. Wenn nicht, erstellen Sie auch einen neuen Benutzer.

Erste Bearbeiten auf die Frage, „was ist, wenn ein Benutzer die auf eine andere Website mit anderen Benutzernamen, Passwort oder E-Mail registrieren möchten?“

Laut meinen Kommentaren ist es in Ordnung, ein Benutzerkonto für die Websites zu teilen (und der Benutzer ist sich dessen natürlich bewusst). Im Register-Prozess, falls der Benutzer für eine bestimmte E-Mail bereits existiert, dann könnte er darüber informiert werden, dass, da ein Konto für diese Adresse bereits für die Site-a existiert, dieses Benutzerkonto der Mitgliedschaft von site-b zugewiesen würde. Dann könnte eine E-Mail mit einem Bestätigungslink gesendet werden, und bei Bestätigung würde das neue Mitglied erstellt und dem gültigen Benutzer zugewiesen werden.

Ein anderer Ansatz

Wenn ich falsch war vorausgesetzt, es ist in Ordnung, und sogar erwünscht Benutzer zwischen Standorten zu teilen, dann denke ich, ein ganz neuer Ansatz hier gebraucht wird:

die AbstractUser verlängern, wie Sie waren tun, aber anstatt die E-Mail als USERNAME_FIELD zu verwenden, verwenden Sie ein neues Feld, das aus <email>_<site_id> besteht (was immer eindeutig wäre, da diese 2 Felder unique_together sind) ... das Feld könnte unique_site_id oder so heißen. Und dieses Feld könnte nach dem Senden der Anmelde- und Anmeldeformulare ausgefüllt werden.

+0

Was passiert, wenn ein Besucher anmeldet mit derselben E-Mail und Benutzernamen, aber ein anderes Passwort? Oder die gleiche E-Mail-Adresse, aber anderer Benutzername? Oder der gleiche Benutzername, aber andere E-Mail-Adresse? –

+0

Nun, wenn die E-Mail korrekt ist, ist es derselbe Benutzer, so dass der Benutzer kein neues Konto erstellen muss. ... Wenn die persönlichen Daten des Benutzers nicht identisch sind, könnte der Benutzer gefragt werden, ob er seine Daten aktualisieren möchte? ... oder sollte der Benutzer "denken", dass er für jede Site ein neues/separates Konto erstellt? ... Ich dachte, es könnte mehr wie die stackoverflow/-exchange sites ... ein Login/Profil für mehrere verwandte Seiten sein. – andzep

+0

... Vielleicht habe ich den Punkt der Freigabe einer Datenbank zwischen den Websites missverstanden. Ich dachte, dass die Seiten irgendwie zusammenhängen und einige Daten zwischen ihnen teilen, einschließlich der Benutzer. – andzep

Verwandte Themen