2011-01-03 5 views
0

Ist es möglich, Djangos Benutzerauthentifizierungsfunktionen mit mehr als einem Profil zu verwenden?Mehr als ein Profil in Django?

Zur Zeit habe ich eine settings.py-Datei, die diese in sich hat:

AUTH_PROFILE_MODULE = 'auth.UserProfileA' 

und eine models.py-Datei, die diese in sich hat:

from django.db import models 
from django.contrib.auth.models import User 

class UserProfileA(models.Model): 
    company = models.CharField(max_length=30) 
    user = models.ForeignKey(User, unique=True) 

auf diese Weise, wenn ein Benutzer Loggen Sie sich ein, ich kann das Profil leicht erhalten, weil der Benutzer eine Methode get_profile() hat. Ich möchte jedoch UserProfileB hinzufügen. Wenn man sich ein wenig umschaut, scheint es der Ausgangspunkt zu sein, eine Superklasse zu erstellen, die als AUTH_PROFILE_MODULE verwendet werden kann, und sowohl UserProfileA als auch UserProfileB von dieser Superklasse erben. Das Problem ist, ich glaube nicht, dass die Methode get_profile() das korrekte Profil zurückgibt. Es würde eine Instanz der Oberklasse zurückgeben. Ich komme aus einem Java-Hintergrund (Polymorphismus), also bin ich mir nicht sicher, was genau ich tun sollte.

Danke!

Edit:

Nun fand ich einen Weg, um es über etwas ein „Erbe Hack“ genannt zu tun, die ich an dieser Stelle gefunden http://djangosnippets.org/snippets/1031/

Es funktioniert wirklich gut, aber von einem Java-Hintergrund kommen, wo das geschieht automatisch, ich bin ein wenig verunsichert durch die Tatsache, dass jemand das programmieren musste und es einen "Hack" nannte, um es in Python zu machen. Gibt es einen Grund, warum Python dies nicht aktiviert?

Antwort

0

ist die Antwort auf meine Frage, wie mehrere Profile an die Arbeit:

from django.contrib.contenttypes.models import ContentType 
class Contact(models.Model): 

    content_type = models.ForeignKey(ContentType,editable=False,null=True) 

    def save(self): 
     if(not self.content_type): 
      self.content_type = ContentType.objects.get_for_model(self.__class__) 
     self.save_base() 

    def as_leaf_class(self): 
     content_type = self.content_type 
     model = content_type.model_class() 
     if(model == Contact): 
      return self 
     return model.objects.get(id=self.id) 

Ich verstehe nicht wirklich, warum es funktioniert oder warum die Entwickler von django/Python gemacht Vererbung arbeiten auf diese Weise

+0

Ich habe das gleiche Problem. Ich frage mich nur, wofür hast du dein 'AUTH_PROFILE_MODULE' platziert? – Modelesq

4

Das Problem, das Sie haben werden, ist, dass, was auch immer Sie für Ihr Profil wollen, Sie es in einer Datenbank irgendwie beibehalten müssen. Grundsätzlich sind alle Back-Ends für Django relational und somit ist jedes Feld in einem persistenten Objekt in jeder Zeile der Tabelle vorhanden. Es gibt ein paar Möglichkeiten, um zu bekommen, was Sie wollen.

Django bietet einige Unterstützung für inheritance. Sie können die aufgelisteten Techniken verwenden und angemessene Ergebnisse auf eine polymorphe Weise erhalten.

Der direkteste Ansatz ist die Verwendung der Vererbung mehrerer Tabellen. Grob:

class UserProfile(models.Model): 
    # set settings.AUTH_PROFILE_MODULE to this class! 
    pass 

class UserProfileA(UserProfile): 
    pass 

class UserProfileB(UserProfile): 
    pass 

es zu benutzen:

try: 
    profile = user.get_profile().userprofilea 
    # user profile is UserProfileA 
except UserProfileA.DoesNotExist: 
    # user profile wasn't UserProfileB 
    pass 
try: 
    profile = user.get_profile().userprofileb 
    # user profile is UserProfileB 
except UserProfileB.DoesNotExist: 
    # user profile wasn't either a or b... 

Edit: Re, Ihren Kommentar. Das relationale Modell impliziert eine Reihe von Dingen, die seem to disagree mit objektorientierten Philosophie. Damit eine Beziehung nützlich ist, muss jedes Element in der Relation dieselben Dimensionen aufweisen, sodass relationale Abfragen für die gesamte Relation gültig sind. Da dies a priori bekannt ist, kann die Zeile keine Unterklasse sein, bevor sie auf eine Instanz einer in der Relation gespeicherten Klasse trifft. django's orm überwindet diese Impedanzfehlanpassung, indem die Unterklasseninformation in einer anderen Beziehung gespeichert wird (eine spezifisch für die Unterklasse). Es gibt andere Lösungen, aber sie alle gehorchen dieser grundlegenden Natur des relationalen Modells.

Wenn es Ihnen hilft, damit fertig zu werden, würde ich empfehlen, zu prüfen, wie Persistenz auf einem RDBMs für Anwendungen in Abwesenheit eines ORM funktioniert. Insbesondere beziehen sich relationale Datenbanken eher auf Sammlungen und Zusammenfassungen vieler Zeilen als auf das Verhalten von Daten, die einmal aus der Datenbank abgerufen wurden.Das spezifische Beispiel der Verwendung der Profilfunktion von django.contrib.auth ist ein ziemlich uninteressantes, insbesondere wenn die einzige Möglichkeit, dass Modell jemals verwendet wird, das Abrufen der Profildaten ist, die einer bestimmten django.contrib.auth.models.User Instanz zugeordnet sind. Wenn keine anderen Abfragen vorhanden sind, benötigen Sie keine Unterklasse django.models.Model. Sie können eine reguläre Python-Klasse picken und in einem Blob-Feld eines ansonsten merkmalslosen Modells speichern.

Auf der anderen Seite, wenn Sie mehr interessante Dinge mit Profilen tun möchten, wie die Suche nach Benutzern, die in einer bestimmten Stadt leben, dann ist es wichtig für alle Profile einen Index für ihre Stadt Eigenschaft zu haben. Das hat nichts mit OOP und allem, was mit relationalen Beziehungen zu tun hat, zu tun.

+0

, dass eine Menge Programmierung Prinzipien zu verletzen scheint. Ich würde lieber die Methode von djangosnippets.com verwenden, zu der ich den Link in den Änderungen zu meiner ursprünglichen Frage dann dieses gepostet habe. Ich schätze die Hilfe jedoch. Nachdem Sie den Link gelesen haben, den Sie zur Vererbung gepostet haben, scheint es, dass django nicht in der Lage ist, automatisch zu wissen, was die Kindklasse ist. – JPC

1

Die Idios-App des Pinax-Teams zielt darauf ab, das Multiple-Profile-Problem zu lösen. Sie können das Modell optimieren, um die Vererbung der Basisprofilklasse entweder abstrakt oder nicht-abstrakt zu machen. https://github.com/eldarion/idios. Hier

0

Wenn Sie für jeden Benutzer anwendungsspezifische Optionen haben, empfehle ich Ihnen, sie in ein separates Modell zu übernehmen.

Ein vereinfachtes Beispiel:

class UserSettings(models.Model): 
    user = models.ForeignKey(User, primary_key = True) 

    # Settings go here 
    defaultLocale = models.CharField(max_length = 80, default = "en_US") 
    ... 

Dies würde wie so verwendet werden:

def getUserSettings(request): 
    try: 
     return UserSettings.objects.get(pk = request.user) 
    except UserSettings.DoesNotExist: 
     # Use defaults instead, that's why you should define reasonable defaults 
     # in the UserSettings model 
     return UserSettings()