2010-05-08 134 views
1

我正在做一些效率不高的事情。从我下面的代码中,你可能会看到我试图允许将多个不同类型的配置文件附加到我的自定义用户对象(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") 

回答

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,恕我直言,这种方法是一样好。你总是可以尝试添加自定义约束到你自己的dbms,说应该有0或1个记录包含相同的FK和is_default = True(没有django的方式来做到这一点)。我还要说的是,添加一个make_default方法,并在该方法中确保is_default对该人是唯一的(例如,首先在具有相同FK的所有配置文件上将is_default设置为False)。这会为你节省很多可能的伤痛。您也可以在BaseProfile的save()方法中添加此检查。

另一种可以做到这一点的方法是将外键添加到指向默认配置文件的人员模型。虽然这将确保默认在django级别上是唯一的,但它也可以提供数据的非规范化和损坏,即使在更令人讨厌的级别上,所以我并不是很喜欢它。但是,如果您通过预定义的方法添加/删除/更新配置文件(现在会更复杂!),您应该是安全的。

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

+0

我已经避免从BaseProfile中移除抽象,希望在模板中到达我的“类型”配置文件之前不必穿过另一个层。然而,我错过的那个谜题的缺失部分是在模型上创建访问器,从模板中遮盖了该图层。 现在我看到,走这条路线开辟了一系列更好的方式来做到这一点,这正是我所期待的。我会尝试这种方法,谢谢Killian! – Scott 2010-05-08 16:43:39

相关问题