2012-03-10 24 views
19

Inicialmente, empecé mi uso de perfiles de esta manera:Django - Múltiples perfiles de usuario

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

class UserProfile(models.Model): 
    user = models.OneToOneField(User) 
    verified = models.BooleanField() 
    mobile = models.CharField(max_length=32) 

    def __unicode__(self): 
     return self.user.email 

que funciona muy bien junto con AUTH_PROFILE_MODULE = 'accounts.UserProfile' set en settings.py.

Sin embargo, tengo dos tipos diferentes de usuarios en mi sitio web, Individuales y Corporativos, cada uno con sus propios atributos únicos. Por ejemplo, me gustaría que mis usuarios individuales tuvieran un solo usuario, por lo tanto, tenían user = models.OneToOneField(User), y para Corporativo me gustaría que tuvieran varios usuarios relacionados con el mismo perfil, por lo que tendría user = models.ForeignKey(User) en su lugar.

así que pensé en segregar el modelo en dos modelos diferentes, y IndivProfileCorpProfile, tanto la herencia de UserProfile mientras mueve los atributos específicos del modelo en las sub-modelos pertinentes. Me parece una buena idea y probablemente funcione, sin embargo, no podría especificar AUTH_PROFILE_MODULE de esta manera ya que tengo dos perfiles de usuario que serían diferentes para diferentes usuarios.

También pensé en hacerlo a la inversa, teniendo UserProfile poder heredar de múltiples clases (modelos), algo como esto:

class UserProfile(IndivProfile, CorpProfile): 
    # some field 

    def __unicode__(self): 
     return self.user.email 

De esta manera me gustaría establecer AUTH_PROFILE_MODULE = 'accounts.UserProfile' y resolver su problema. Pero eso no parece funcionar, ya que la herencia en python funciona de izquierda a derecha y todas las variables en IndivProfile serán dominantes.

Claro que siempre puedo tener un solo modelo con IndivProfile y CorpProfile variables todas mezcladas juntas y luego usaría las necesarias cuando sea necesario. Pero eso simplemente no me parece limpio, preferiría que se segregara y usar el modelo apropiado en el lugar apropiado.

Cualquier sugerencia de limpiar forma de hacer esto?

+0

¿Qué pasa con [herencia] (https://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance)? – danihp

+1

Podría hacer que 'UserProfile' sea abstracto y permitir que' IndivProfile' y 'CorpProfile' hereden de' UserProfile'. Esto aún no va a resolver el problema con 'AUTH_PROFILE_MODULE'. ¿A cuál va a apuntar? – abstractpaper

+0

¿Qué le parece agregar campos corporativos + individuales + tipo de cuenta a un modelo? Creo que podría estar bien si solo tienes dos tipos, pero puede ser malo si tienes más de 2 o esos perfiles son muy diferentes. –

Respuesta

6

Lo he hecho de esta manera.

PROFILE_TYPES = (
    (u'INDV', 'Individual'), 
    (u'CORP', 'Corporate'), 
) 

# used just to define the relation between User and Profile 
class UserProfile(models.Model): 
    user = models.ForeignKey(User) 
    profile = models.ForeignKey('Profile') 
    type = models.CharField(choices=PROFILE_TYPES, max_length=16) 

# common fields reside here 
class Profile(models.Model): 
    verified = models.BooleanField(default=False) 

Terminé usando una tabla intermedia para reflejar la relación entre dos modelos abstractos, User que ya se define en Django, y mi modelo Profile. En caso de tener atributos que no son comunes, crearé un nuevo modelo y lo relacionaré con Profile.

+0

¿Cómo almacenaste los campos poco comunes? ¿Puedes mostrar el código para eso? – user3411864

-1

Podría valer la pena intentar usar un campo directo. La idea detrás de esto es usar el modelo UserProfile como a través de un modelo para los modelos de PerfilPublico o IndivProfile. De esa manera se crea tan pronto como un perfil Corp o Indiv está vinculada a un usuario:

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

class UserProfile(models.Model): 
    user = models.ForeignKey(User) 
    profile = models.ForeignKey(Profile, related_name='special_profile') 

class Profile(models.Model): 
    common_property=something 

class CorpProfile(Profile): 
    user=models.ForeignKey(User, through=UserProfile) 
    corp_property1=someproperty1 
    corp_property2=someproperty2 

class IndivProfile(Profile): 
    user=models.ForeignKey(User, through=UserProfile, unique=true) 
    indiv_property1=something 
    indiv_property2=something 

creo que así debe ser posible establecer AUTH_PROFILE_MODULE = 'accounts.UserProfile', y cada vez que se crea, ya sea un CorpProfile o una IndivProfile que está vinculado a un usuario real, se crea un modelo único UserProfile. A continuación, puede acceder a eso con consultas db o lo que desee.

No he probado esto, entonces no hay garantías. Puede ser un poco hacky, pero por otro lado la idea me parece bastante atractiva. :)

+0

He intentado ejecutar esto pero mostró un error 'invalid keyword argument 'through''. Estoy trabajando en este momento y no puedo obtener la redacción exacta. – abstractpaper

+0

Vaya, a través de obras solo para relaciones ManyToMany. Parece otra solución no tan limpia ahora. Pero creo que Aamir ya propuso una solución bastante simple. – marue

+0

@marue, ¿esta respuesta debería eliminarse por completo? Es incorrecto y parece confuso. –

20

Puede hacerlo de la siguiente manera. Tener un perfil que contenga campos comunes que son necesarios en ambos perfiles. Y ya lo ha hecho creando la clase UserProfile.

class UserProfile(models.Model): 
    user = models.ForeignKey(User) 
    #some common fields here, which are shared among both corporate and individual profiles 

class CorporateUser(models.Model): 
    profile = models.ForeignKey(UserProfile) 
    #corporate fields here 

    class Meta: 
     db_table = 'corporate_user' 

class IndividualUser(models.Model): 
    profile = models.ForeignKey(UserProfile) 
    #Individual user fields here 

    class Meta: 
     db_table = 'individual_user' 

No hay ciencia espacial involucrada aquí. Solo tiene una palabra clave que distinguirá entre el perfil corporativo o el perfil individual. P.ej. Considere que el usuario se está registrando. Luego, tenga un campo en el formulario que diferenciará si el usuario se está registrando para corporativo o no. Y use esa palabra clave (parámetro de solicitud) para guardar al usuario en el modelo respectivo.

Luego, cuando quiera comprobar que el perfil del usuario es corporativo o individual, puede verificarlo escribiendo una pequeña función.

def is_corporate_profile(profile): 
    try: 
     profile.corporate_user 
     return True 
    except: 
     return False 

#If there is no corporate profile is associated with main profile then it will raise exception and it means its individual profile 
#you can use this function as a template function also to use in template 
{%if profile|is_corporate_profile %} 

esperanza que le llevará en algún lugar. Gracias

+0

No es preferible un [OneToOne] (https://docs.djangoproject.com/en/dev/topics/db/models/#one-to-one-relationships) en lugar de una ForeignKey? – danihp

+0

Especificar clave externa también es algo relacionado con la relación oneToOne. –

+0

sin OneToOne debe escribir: 'try: profile.corporate_user_set.all() [0]' – danihp

Cuestiones relacionadas