如何处理每个用户的多个配置文件?

时间:2010-05-08 05:28:07

标签: django profiles

我正在做一些感觉效率不高的事情。从下面的代码中,您可能会看到我正在尝试允许将多个不同类型的配置文件附加到我的自定义用户对象(Person)。其中一个配置文件将被视为默认配置文件,并且应具有Person类的访问者。在配置文件中存储is_default字段似乎不是跟踪默认值的最佳方式,是吗?

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


class Person(User):

    public_name = models.CharField(max_length=24, default="Mr. T")

    objects = UserManager()

    def save(self):
        self.set_password(self.password)
        super(Person, self).save()


    def _getDefaultProfile(self):

        def_teacher = self.teacher_set.filter(default=True)
        if def_teacher: return def_teacher[0]

        def_student = self.student_set.filter(default=True)
        if def_student: return def_student[0]

        def_parent  = self.parent_set.filter(default=True)
        if def_parent:  return def_parent[0]

        return False
    profile = property(_getDefaultProfile)


    def _getProfiles(self):
        # Inefficient use of QuerySet here. Tolerated because the QuerySets should be very small.
        profiles = []
        if self.teacher_set.count(): profiles.append(list(self.teacher_set.all()))
        if self.student_set.count(): profiles.append(list(self.student_set.all()))
        if self.parent_set.count():  profiles.append(list(self.parent_set.all()))

        return profiles
    profiles = property(_getProfiles)




class BaseProfile(models.Model):

    person = models.ForeignKey(Person)
    is_default = models.BooleanField(default=False)

    class Meta:
        abstract = True


class Teacher(BaseProfile):
    user_type = models.CharField(max_length=7, default="teacher")


class Student(BaseProfile):
    user_type = models.CharField(max_length=7, default="student")


class Parent(BaseProfile):
    user_type = models.CharField(max_length=7, default="parent")

1 个答案:

答案 0 :(得分:2)

首先,您可以通过不声明BaseProfile摘要来使事情变得更加轻松:

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

class Person(User):
    public_name = models.CharField(max_length=24, default="Mr. T")
    objects = UserManager()

    def save(self):
        self.set_password(self.password)
        super(Person, self).save()

    def _getDefaultProfile(self):
        try:
            return self.baseprofile_set.get(default=True)
        except ObjectDoesNotExist:
            return False
    profile = property(_getDefaultProfile)

    def _getProfiles(self):
        return self.baseprofile_set.all()
    profiles = property(_getProfiles)

class BaseProfile(models.Model):

    person = models.ForeignKey(Person)
    is_default = models.BooleanField(default=False)    

class Teacher(BaseProfile):
    user_type = models.CharField(max_length=7, default="teacher")    

class Student(BaseProfile):
    user_type = models.CharField(max_length=7, default="student")    

class Parent(BaseProfile):
    user_type = models.CharField(max_length=7, default="parent")

这样更好吗?你的属性无论如何都不知道它们返回的是什么类型,所以抽象基类只会让你有一个令人难以置信的令人讨厌的开销。

如果您现在想知道如何从特定的配置文件中获取数据,因为我做了任何返回的BaseProfile?你可以这样做:

try:
    #note the lowercase teacher referal
    print myuser.profile.teacher.someteacherfield 
except Teacher.DoesNotExist:
    print "this is not a teacher object!"

此外,我希望您不会仅仅为此目的使用user_type字段,因为django内置的更好,如您所见。我也希望你在派生的配置文件类中确实有其他一些独特的字段,否则你应该抛弃它们,然后将一个usertype字段放到BaseProfile中(看看choices就可以了。)

现在至于is_default,imho这个方法和任何方法一样好。您总是可以尝试向dbms本身添加自定义约束,说可能有0或1条记录包含相同的FK和is_default = True(没有django方法来执行此操作)。我还要说的是,添加方法make_default并在该方法中确保is_default对于该人是唯一的(例如,首先在具有相同FK的所有配置文件上将is_default设置为False)。这将为您节省很多可能的悲伤。您还可以在BaseProfile的save()方法中添加此检查。

另一种方法是向Person Model添加一个指向默认Profile的外键。虽然这将确保默认在django级别上是唯一的,但它也可以提供数据的非规范化和损坏,即使在更烦人的级别上,所以我不是它的忠实粉丝。但同样,如果您通过预定义的方法完成所有添加/删除/更新配置文件(现在会更复杂!),您应该是安全的。

最后,也许你有充分的理由从User继承,但扩展用户功能的默认方式不是这个,它描述为here